我的中有以下代码~/.zshrc
:
autoload -Uz edit-command-line
zle -N edit-command-line
bindkey '^X^E' edit-command-line
它将edit-command-line
zle 小部件绑定到 keysequence C-x C-e
。该小部件在man zshcontrib
(节 ZLE FUNCTIONS
,小节Widgets
)中描述:
edit-command-line 使用可视化编辑器编辑命令行,如 ksh 中。
bindkey -M vicmd v edit-command-line
目的是能够在默认编辑器中通过按 来编辑当前 shell 命令行,C-x C-e
类似于 readline 函数edit-and-execute-command
的功能(man bash
、section READLINE
、subsection Commands for Manipulating the History
)。
edit-and-execute-command (C-xC-e) 在当前命令行上调用编辑器,并将结果作为 shell 命令执行。 Bash 尝试按顺序调用 $VISUAL、$EDITOR 和 emacs 作为编辑器。
我的默认编辑器是 Vim 8.1
(1-538
包括补丁)。我有 Vim 映射,使用C-h
、C-j
、C-k
、 、键C-l
将焦点移动到相邻窗口。它们可以归结为:
nnoremap <c-h> :<c-u>wincmd h<cr>
nnoremap <c-j> :<c-u>wincmd j<cr>
nnoremap <c-k> :<c-u>wincmd k<cr>
nnoremap <c-l> :<c-u>wincmd l<cr>
它们都在常规 Vim 实例中按预期工作(通过执行 启动$ vim
)。但是C-j
当 Vim 由 启动时并没有按预期工作edit-command-line
。
当我C-x C-e
在 shell 命令行上按 while 时,zsh 会启动 Vim。如果我通过执行分割窗口:split
,然后按C-k
移动到顶部窗口,我会得到两个窗口,并且焦点移动到顶部窗口。但是,如果我按C-j
返回到底部窗口,则什么也不会发生。
我不知道这是否是问题的原因,但如果我尝试C-j
在 Vim 缓冲区中插入文字(通过按C-v C-j
),^M
则会显示(回车符的插入符号)。在常规 Vim 实例中(通过执行 启动$ vim
),插入文字C-j
会产生脱字符号为^@
(NUL) 的字符。
我可以用这个最小的方法重现这个问题~/.zshrc
:
export EDITOR=vim
autoload -Uz edit-command-line
zle -N edit-command-line
bindkey '^X^E' edit-command-line
这个最小的~/.vimrc
:
nnoremap <c-j> :echom 'C-j has been pressed'<cr>
C-x C-e
在 zsh 命令行上按下启动 Vim,然后按下C-j
应该打印并记录消息:
C-j has been pressed
但什么也没发生。
我无法在 bash 中重现该问题,也无法使用 Neovim ( v0.3.2-752-g4d7c7f9
) 重现该问题。此外,C-j
在按下 后从 bash 启动 Vim 时,在 Vim 中插入文字C-x C-e
会导致 NUL ( ^@
)。按 后从 bash 或 zsh 启动 Neovim 时也会出现同样的情况C-x C-e
。
┌────────┬──────┬─────┐
│ │ bash │ zsh │
├────────┼──────┼─────┤
│ Vim │ ^@ │ ^M │
├────────┼──────┼─────┤
│ Neovim │ ^@ │ ^@ │
└────────┴──────┴─────┘
我认为可能某些 Vim 终端选项配置不正确,所以我捕获了以下输出:
:set termcap
从 Vim 开始$ vim
,从 Vim 开始C-x C-e
。但两种情况下的输出是相同的:
--- Terminal codes ---
t_AL=^[[%p1%dL t_DL=^[[%p1%dM t_mr=^[[7m t_se=^[[27m t_us=^[[4m
t_al=^[[L t_dl=^[[M t_ms=y t_Sf= t_ut=
t_bc= t_EC= t_nd=^[[C t_SH= t_vb=^[g
t_BE= t_EI=^[[2 q t_op=^[[39;49m t_SI=^[[6 q t_vi=^[[?25l
t_BD= t_fs=^G t_RF= t_Si= t_VS=
t_cd=^[[J t_GP= t_RB= t_so=^[[7m t_vs=^[[34l
t_ce=^[[K t_IE= t_RC= t_SR=^[[4 q t_WP=
t_cl=^[[H^[[J t_IS= t_RI=^[[%p1%dC t_sr=^[M t_WS=
t_Ce= t_ke=^[[?1l^[> t_Ri= t_ST= t_xn=y
t_Co=256 t_ks=^[[?1h^[= t_RS= t_Te= t_xs=
t_CS= t_le=^H t_RT= t_Ts= t_ZH=^[[3m
t_CV= t_mb=^[[5m t_RV= t_ts=^[]0; t_ZR=^[[23m
t_da= t_md=^[[1m t_Sb= t_u7= t_8f=
t_db= t_me=^[[0m t_SC= t_ue=^[[24m t_8b=
t_AB=^[[%?%p1%{8}%<%t4%p1%d%e%p1%{16}%<%t10%p1%{8}%-%d%e48;5;%p1%d%;m
t_AF=^[[%?%p1%{8}%<%t3%p1%d%e%p1%{16}%<%t9%p1%{8}%-%d%e38;5;%p1%d%;m
t_cm=^[[%i%p1%d;%p2%dH
t_Cs=^[]12;%p1%s^G
t_cs=^[[%i%p1%d;%p2%dr
t_te=^[[2 q^[[?1004l^[[?1049l
t_ti=^[[2 q^[[?1004h^[[?1049h
t_ve=^[[34h^[[?25h
--- Terminal keys ---
t_#2 <S-Home> ^[[1;2H t_k6 <F6> ^[[17~ t_kh <Home> ^[[1~ <ð> ^[p
t_#4 <S-Left> ^[[1;2D t_k7 <F7> ^[[18~ t_kl <Left> ^[OD <ô> ^[t
t_%i <S-Right> ^[[1;2C t_k8 <F8> ^[[19~ t_kr <Right> ^[OC <õ> ^[u
t_*7 <S-End> ^[[1;2F t_k9 <F9> ^[[20~ t_ku <Up> ^[OA <ù> ^[y
t_@7 <End> ^[[4~ t_k; <F10> ^[[21~ <á> ^[a <ú> ^[z
t_F1 <F11> ^[[23~ t_kB <S-Tab> ^[[Z <â> ^[b <Mouse> ^[[M
t_F2 <F12> ^[[24~ t_kD <Del> ^[[3~ <ä> ^[d <S-F18> ^[[O
t_k1 <F1> ^[OP t_kI <Insert> ^[[2~ <å> ^[e <S-F19> ^[[I
t_k2 <F2> ^[OQ t_kN <PageDown> ^[[6~ <æ> ^[f <xUp> ^[[1;*A
t_k3 <F3> ^[OR t_kP <PageUp> ^[[5~ <ç> ^[g <xDown> ^[[1;*B
t_k4 <F4> ^[OS t_kb <BS> ^? <í> ^[m <xLeft> ^[[1;*D
t_k5 <F5> ^[[15~ t_kd <Down> ^[OB <î> ^[n <xRight> ^[[1;*C
bash 和 zsh 中的输出$ stty -a
也相同:
speed 38400 baud; rows 33; columns 119; line = 0;
intr = ^C; quit = ^\; erase = ^?; kill = ^U; eof = ^D; eol = <undef>;
eol2 = <undef>; swtch = <undef>; start = ^Q; stop = ^S; susp = ^Z; rprnt = ^R;
werase = ^W; lnext = ^V; discard = ^O; min = 1; time = 0;
-parenb -parodd -cmspar cs8 -hupcl -cstopb cread -clocal -crtscts
-ignbrk -brkint -ignpar -parmrk -inpck -istrip -inlcr -igncr icrnl -ixon -ixoff
-iuclc -ixany -imaxbel iutf8
opost -olcuc -ocrnl onlcr -onocr -onlret -ofill -ofdel nl0 cr0 tab0 bs0 vt0 ff0
isig icanon iexten echo echoe echok -echonl -noflsh -xcase -tostop -echoprt
echoctl echoke -flusho -extproc
我在用着zsh 5.6.2-dev-1 (x86_64-pc-linux-gnu)
。
是否应该设置 Vim 或 zsh 选项以防止 Vim在由 zle 小部件启动时转换C-j
为?C-m
edit-command-line
答案1
如果您将您设置$EDITOR
为执行此操作的脚本或函数stty -a
,您会注意到当时vim
调用的终端设置edit-command-line
是 zle 的设置(其中inlcr
导致终端设备驱动程序将 NL 转换为 CR 处于打开状态) 。
^J
是换行符,所以绑定有点微妙。
在这里,您可以通过将函数定义为来解决这个问题vim
:
vim() STTY=sane command vim "$@"
或者添加编辑STTY=sane
(或STTY=-inlcr
) 到edit-command-line
。