How to prevent Vim from translating C-j into C-m when started by the zle widget `edit-command-line`?

The name of the pictureThe name of the pictureThe name of the pictureClash Royale CLAN TAG#URR8PPP

up vote
2
down vote

favorite

I have the following code in my ~/.zshrc:

autoload -Uz edit-command-line
zle -N edit-command-line
bindkey '^X^E' edit-command-line

It binds the edit-command-line zle widget to the keysequence C-x C-e.
The widget is described in man zshcontrib (section ZLE FUNCTIONS, subsection Widgets):

edit-command-line
Edit the command line using your visual editor, as in ksh.

          bindkey -M vicmd v edit-command-line

The purpose is to be able to edit the current shell command line, in the default editor, by pressing C-x C-e, similar to what the readline function edit-and-execute-command does (man bash, section READLINE, subsection Commands for Manipulating the History).

edit-and-execute-command (C-xC-e)
Invoke an editor on the current command line, and execute the result as shell commands. Bash attempts
to invoke $VISUAL, $EDITOR, and emacs as the editor, in that order.

My default editor is Vim 8.1 (patches 1-538 included).
I have Vim mappings, using the keys C-h, C-j, C-k, C-l, to move the focus to neighbour windows.
They can be boiled down to:

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>

They all work as expected in a regular Vim instance (started by executing $ vim).
But C-j doesn’t work as expected when Vim was started by edit-command-line.

When I press C-x C-e while on the shell command line, zsh starts Vim. If I split the window by executing :split, then press C-k to move to the top window, I get two windows, and the focus is moved to the top one. But then, if I press C-j to get back to the bottom window, nothing happens.

I don’t know whether it’s the cause of the issue, but if I try to insert a literal C-j in a Vim buffer (by pressing C-v C-j), ^M is displayed (the caret notation for a carriage return). In a regular Vim instance (started by executing $ vim), inserting a literal C-j results in a character whose caret notation is ^@ (a NUL).

I can reproduce the issue with this minimal ~/.zshrc:

export EDITOR=vim
autoload -Uz edit-command-line
zle -N edit-command-line
bindkey '^X^E' edit-command-line

And this minimal ~/.vimrc:

nnoremap <c-j> :echom 'C-j has been pressed'<cr>

Pressing C-x C-e on the zsh command line starts Vim, then pressing C-j should print and log the message:

C-j has been pressed

But nothing happens.

I can’t reproduce the issue in bash, nor with Neovim (v0.3.2-752-g4d7c7f9).
Besides, inserting a literal C-j in Vim, when the latter was started from bash after pressing C-x C-e, results in a NUL (^@). Same thing when Neovim is started from bash or zsh after pressing C-x C-e.

┌────────┬──────┬─────┐
│        │ bash │ zsh │
├────────┼──────┼─────┤
│ Vim    │ ^@   │ ^M  │
├────────┼──────┼─────┤
│ Neovim │ ^@   │ ^@  │
└────────┴──────┴─────┘

I thought that maybe some Vim terminal option was not properly configured, so I captured the output of:

:set termcap

from Vim started by $ vim, and from Vim started by C-x C-e.
But the output is identical in both cases:

--- 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

The output of $ stty -a is also identical in bash and zsh:

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

I’m using zsh 5.6.2-dev-1 (x86_64-pc-linux-gnu).

Is there a Vim or zsh option which should be set to prevent Vim from translating C-j into C-m when started by the zle widget edit-command-line?

share|improve this question

  • 1

    Zsh modifies stty settings while zle is active. Running stty from a prompt shows the settings when running commands, not the settings during command line edition. This looks like a bug where it doesn’t properly restore stty settings when it runs a command from within command line edition.
    – Gilles
    Nov 28 at 21:19

  • @Gilles, zsh does redirect stdin from /dev/null inside user-defined widgets, but edit-command-line does a exec < /dev/tty, but does not restore the non-zle settings, so the bug if more with that edit-command-line widget.
    – Stéphane Chazelas
    Dec 2 at 14:51

up vote
2
down vote

favorite

I have the following code in my ~/.zshrc:

autoload -Uz edit-command-line
zle -N edit-command-line
bindkey '^X^E' edit-command-line

It binds the edit-command-line zle widget to the keysequence C-x C-e.
The widget is described in man zshcontrib (section ZLE FUNCTIONS, subsection Widgets):

edit-command-line
Edit the command line using your visual editor, as in ksh.

          bindkey -M vicmd v edit-command-line

The purpose is to be able to edit the current shell command line, in the default editor, by pressing C-x C-e, similar to what the readline function edit-and-execute-command does (man bash, section READLINE, subsection Commands for Manipulating the History).

edit-and-execute-command (C-xC-e)
Invoke an editor on the current command line, and execute the result as shell commands. Bash attempts
to invoke $VISUAL, $EDITOR, and emacs as the editor, in that order.

My default editor is Vim 8.1 (patches 1-538 included).
I have Vim mappings, using the keys C-h, C-j, C-k, C-l, to move the focus to neighbour windows.
They can be boiled down to:

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>

They all work as expected in a regular Vim instance (started by executing $ vim).
But C-j doesn’t work as expected when Vim was started by edit-command-line.

When I press C-x C-e while on the shell command line, zsh starts Vim. If I split the window by executing :split, then press C-k to move to the top window, I get two windows, and the focus is moved to the top one. But then, if I press C-j to get back to the bottom window, nothing happens.

I don’t know whether it’s the cause of the issue, but if I try to insert a literal C-j in a Vim buffer (by pressing C-v C-j), ^M is displayed (the caret notation for a carriage return). In a regular Vim instance (started by executing $ vim), inserting a literal C-j results in a character whose caret notation is ^@ (a NUL).

I can reproduce the issue with this minimal ~/.zshrc:

export EDITOR=vim
autoload -Uz edit-command-line
zle -N edit-command-line
bindkey '^X^E' edit-command-line

And this minimal ~/.vimrc:

nnoremap <c-j> :echom 'C-j has been pressed'<cr>

Pressing C-x C-e on the zsh command line starts Vim, then pressing C-j should print and log the message:

C-j has been pressed

But nothing happens.

I can’t reproduce the issue in bash, nor with Neovim (v0.3.2-752-g4d7c7f9).
Besides, inserting a literal C-j in Vim, when the latter was started from bash after pressing C-x C-e, results in a NUL (^@). Same thing when Neovim is started from bash or zsh after pressing C-x C-e.

┌────────┬──────┬─────┐
│        │ bash │ zsh │
├────────┼──────┼─────┤
│ Vim    │ ^@   │ ^M  │
├────────┼──────┼─────┤
│ Neovim │ ^@   │ ^@  │
└────────┴──────┴─────┘

I thought that maybe some Vim terminal option was not properly configured, so I captured the output of:

:set termcap

from Vim started by $ vim, and from Vim started by C-x C-e.
But the output is identical in both cases:

--- 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

The output of $ stty -a is also identical in bash and zsh:

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

I’m using zsh 5.6.2-dev-1 (x86_64-pc-linux-gnu).

Is there a Vim or zsh option which should be set to prevent Vim from translating C-j into C-m when started by the zle widget edit-command-line?

share|improve this question

  • 1

    Zsh modifies stty settings while zle is active. Running stty from a prompt shows the settings when running commands, not the settings during command line edition. This looks like a bug where it doesn’t properly restore stty settings when it runs a command from within command line edition.
    – Gilles
    Nov 28 at 21:19

  • @Gilles, zsh does redirect stdin from /dev/null inside user-defined widgets, but edit-command-line does a exec < /dev/tty, but does not restore the non-zle settings, so the bug if more with that edit-command-line widget.
    – Stéphane Chazelas
    Dec 2 at 14:51

up vote
2
down vote

favorite

up vote
2
down vote

favorite

I have the following code in my ~/.zshrc:

autoload -Uz edit-command-line
zle -N edit-command-line
bindkey '^X^E' edit-command-line

It binds the edit-command-line zle widget to the keysequence C-x C-e.
The widget is described in man zshcontrib (section ZLE FUNCTIONS, subsection Widgets):

edit-command-line
Edit the command line using your visual editor, as in ksh.

          bindkey -M vicmd v edit-command-line

The purpose is to be able to edit the current shell command line, in the default editor, by pressing C-x C-e, similar to what the readline function edit-and-execute-command does (man bash, section READLINE, subsection Commands for Manipulating the History).

edit-and-execute-command (C-xC-e)
Invoke an editor on the current command line, and execute the result as shell commands. Bash attempts
to invoke $VISUAL, $EDITOR, and emacs as the editor, in that order.

My default editor is Vim 8.1 (patches 1-538 included).
I have Vim mappings, using the keys C-h, C-j, C-k, C-l, to move the focus to neighbour windows.
They can be boiled down to:

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>

They all work as expected in a regular Vim instance (started by executing $ vim).
But C-j doesn’t work as expected when Vim was started by edit-command-line.

When I press C-x C-e while on the shell command line, zsh starts Vim. If I split the window by executing :split, then press C-k to move to the top window, I get two windows, and the focus is moved to the top one. But then, if I press C-j to get back to the bottom window, nothing happens.

I don’t know whether it’s the cause of the issue, but if I try to insert a literal C-j in a Vim buffer (by pressing C-v C-j), ^M is displayed (the caret notation for a carriage return). In a regular Vim instance (started by executing $ vim), inserting a literal C-j results in a character whose caret notation is ^@ (a NUL).

I can reproduce the issue with this minimal ~/.zshrc:

export EDITOR=vim
autoload -Uz edit-command-line
zle -N edit-command-line
bindkey '^X^E' edit-command-line

And this minimal ~/.vimrc:

nnoremap <c-j> :echom 'C-j has been pressed'<cr>

Pressing C-x C-e on the zsh command line starts Vim, then pressing C-j should print and log the message:

C-j has been pressed

But nothing happens.

I can’t reproduce the issue in bash, nor with Neovim (v0.3.2-752-g4d7c7f9).
Besides, inserting a literal C-j in Vim, when the latter was started from bash after pressing C-x C-e, results in a NUL (^@). Same thing when Neovim is started from bash or zsh after pressing C-x C-e.

┌────────┬──────┬─────┐
│        │ bash │ zsh │
├────────┼──────┼─────┤
│ Vim    │ ^@   │ ^M  │
├────────┼──────┼─────┤
│ Neovim │ ^@   │ ^@  │
└────────┴──────┴─────┘

I thought that maybe some Vim terminal option was not properly configured, so I captured the output of:

:set termcap

from Vim started by $ vim, and from Vim started by C-x C-e.
But the output is identical in both cases:

--- 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

The output of $ stty -a is also identical in bash and zsh:

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

I’m using zsh 5.6.2-dev-1 (x86_64-pc-linux-gnu).

Is there a Vim or zsh option which should be set to prevent Vim from translating C-j into C-m when started by the zle widget edit-command-line?

share|improve this question

I have the following code in my ~/.zshrc:

autoload -Uz edit-command-line
zle -N edit-command-line
bindkey '^X^E' edit-command-line

It binds the edit-command-line zle widget to the keysequence C-x C-e.
The widget is described in man zshcontrib (section ZLE FUNCTIONS, subsection Widgets):

edit-command-line
Edit the command line using your visual editor, as in ksh.

          bindkey -M vicmd v edit-command-line

The purpose is to be able to edit the current shell command line, in the default editor, by pressing C-x C-e, similar to what the readline function edit-and-execute-command does (man bash, section READLINE, subsection Commands for Manipulating the History).

edit-and-execute-command (C-xC-e)
Invoke an editor on the current command line, and execute the result as shell commands. Bash attempts
to invoke $VISUAL, $EDITOR, and emacs as the editor, in that order.

My default editor is Vim 8.1 (patches 1-538 included).
I have Vim mappings, using the keys C-h, C-j, C-k, C-l, to move the focus to neighbour windows.
They can be boiled down to:

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>

They all work as expected in a regular Vim instance (started by executing $ vim).
But C-j doesn’t work as expected when Vim was started by edit-command-line.

When I press C-x C-e while on the shell command line, zsh starts Vim. If I split the window by executing :split, then press C-k to move to the top window, I get two windows, and the focus is moved to the top one. But then, if I press C-j to get back to the bottom window, nothing happens.

I don’t know whether it’s the cause of the issue, but if I try to insert a literal C-j in a Vim buffer (by pressing C-v C-j), ^M is displayed (the caret notation for a carriage return). In a regular Vim instance (started by executing $ vim), inserting a literal C-j results in a character whose caret notation is ^@ (a NUL).

I can reproduce the issue with this minimal ~/.zshrc:

export EDITOR=vim
autoload -Uz edit-command-line
zle -N edit-command-line
bindkey '^X^E' edit-command-line

And this minimal ~/.vimrc:

nnoremap <c-j> :echom 'C-j has been pressed'<cr>

Pressing C-x C-e on the zsh command line starts Vim, then pressing C-j should print and log the message:

C-j has been pressed

But nothing happens.

I can’t reproduce the issue in bash, nor with Neovim (v0.3.2-752-g4d7c7f9).
Besides, inserting a literal C-j in Vim, when the latter was started from bash after pressing C-x C-e, results in a NUL (^@). Same thing when Neovim is started from bash or zsh after pressing C-x C-e.

┌────────┬──────┬─────┐
│        │ bash │ zsh │
├────────┼──────┼─────┤
│ Vim    │ ^@   │ ^M  │
├────────┼──────┼─────┤
│ Neovim │ ^@   │ ^@  │
└────────┴──────┴─────┘

I thought that maybe some Vim terminal option was not properly configured, so I captured the output of:

:set termcap

from Vim started by $ vim, and from Vim started by C-x C-e.
But the output is identical in both cases:

--- 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

The output of $ stty -a is also identical in bash and zsh:

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

I’m using zsh 5.6.2-dev-1 (x86_64-pc-linux-gnu).

Is there a Vim or zsh option which should be set to prevent Vim from translating C-j into C-m when started by the zle widget edit-command-line?

zsh vim

share|improve this question

share|improve this question

share|improve this question

share|improve this question

asked Nov 28 at 21:06

user938271

22919

22919

  • 1

    Zsh modifies stty settings while zle is active. Running stty from a prompt shows the settings when running commands, not the settings during command line edition. This looks like a bug where it doesn’t properly restore stty settings when it runs a command from within command line edition.
    – Gilles
    Nov 28 at 21:19

  • @Gilles, zsh does redirect stdin from /dev/null inside user-defined widgets, but edit-command-line does a exec < /dev/tty, but does not restore the non-zle settings, so the bug if more with that edit-command-line widget.
    – Stéphane Chazelas
    Dec 2 at 14:51

  • 1

    Zsh modifies stty settings while zle is active. Running stty from a prompt shows the settings when running commands, not the settings during command line edition. This looks like a bug where it doesn’t properly restore stty settings when it runs a command from within command line edition.
    – Gilles
    Nov 28 at 21:19

  • @Gilles, zsh does redirect stdin from /dev/null inside user-defined widgets, but edit-command-line does a exec < /dev/tty, but does not restore the non-zle settings, so the bug if more with that edit-command-line widget.
    – Stéphane Chazelas
    Dec 2 at 14:51

1

1

Zsh modifies stty settings while zle is active. Running stty from a prompt shows the settings when running commands, not the settings during command line edition. This looks like a bug where it doesn’t properly restore stty settings when it runs a command from within command line edition.
– Gilles
Nov 28 at 21:19

Zsh modifies stty settings while zle is active. Running stty from a prompt shows the settings when running commands, not the settings during command line edition. This looks like a bug where it doesn’t properly restore stty settings when it runs a command from within command line edition.
– Gilles
Nov 28 at 21:19

@Gilles, zsh does redirect stdin from /dev/null inside user-defined widgets, but edit-command-line does a exec < /dev/tty, but does not restore the non-zle settings, so the bug if more with that edit-command-line widget.
– Stéphane Chazelas
Dec 2 at 14:51

@Gilles, zsh does redirect stdin from /dev/null inside user-defined widgets, but edit-command-line does a exec < /dev/tty, but does not restore the non-zle settings, so the bug if more with that edit-command-line widget.
– Stéphane Chazelas
Dec 2 at 14:51

1 Answer
1

active

oldest

votes

up vote
2
down vote

accepted

If you set your $EDITOR to a script or function that does stty -a, you’ll notice that the terminal settings at the time vim is called by that edit-command-line are those of zle (where inlcr which causes the terminal device driver to translate NL to CR is on among other things).

^J is the newline character, so binding it is a bit delicate.

Here, you can work around it by defining a vim function as:

vim() STTY=sane command vim "$@"

Or add edit the STTY=sane (or STTY=-inlcr) to edit-command-line.

share|improve this answer

    Your Answer

    StackExchange.ready(function() {
    var channelOptions = {
    tags: “”.split(” “),
    id: “106”
    };
    initTagRenderer(“”.split(” “), “”.split(” “), channelOptions);

    StackExchange.using(“externalEditor”, function() {
    // Have to fire editor after snippets, if snippets enabled
    if (StackExchange.settings.snippets.snippetsEnabled) {
    StackExchange.using(“snippets”, function() {
    createEditor();
    });
    }
    else {
    createEditor();
    }
    });

    function createEditor() {
    StackExchange.prepareEditor({
    heartbeatType: ‘answer’,
    convertImagesToLinks: false,
    noModals: true,
    showLowRepImageUploadWarning: true,
    reputationToPostImages: null,
    bindNavPrevention: true,
    postfix: “”,
    imageUploader: {
    brandingHtml: “Powered by u003ca class=”icon-imgur-white” href=”https://imgur.com/”u003eu003c/au003e”,
    contentPolicyHtml: “User contributions licensed under u003ca href=”https://creativecommons.org/licenses/by-sa/3.0/”u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href=”https://stackoverflow.com/legal/content-policy”u003e(content policy)u003c/au003e”,
    allowUrls: true
    },
    onDemand: true,
    discardSelector: “.discard-answer”
    ,immediatelyShowMarkdownHelp:true
    });

    }
    });

    draft saved
    draft discarded

    StackExchange.ready(
    function () {
    StackExchange.openid.initPostLogin(‘.new-post-login’, ‘https%3a%2f%2funix.stackexchange.com%2fquestions%2f484764%2fhow-to-prevent-vim-from-translating-c-j-into-c-m-when-started-by-the-zle-widget%23new-answer’, ‘question_page’);
    }
    );

    Post as a guest

    Required, but never shown

    1 Answer
    1

    active

    oldest

    votes

    1 Answer
    1

    active

    oldest

    votes

    active

    oldest

    votes

    active

    oldest

    votes

    up vote
    2
    down vote

    accepted

    If you set your $EDITOR to a script or function that does stty -a, you’ll notice that the terminal settings at the time vim is called by that edit-command-line are those of zle (where inlcr which causes the terminal device driver to translate NL to CR is on among other things).

    ^J is the newline character, so binding it is a bit delicate.

    Here, you can work around it by defining a vim function as:

    vim() STTY=sane command vim "$@"
    

    Or add edit the STTY=sane (or STTY=-inlcr) to edit-command-line.

    share|improve this answer

      up vote
      2
      down vote

      accepted

      If you set your $EDITOR to a script or function that does stty -a, you’ll notice that the terminal settings at the time vim is called by that edit-command-line are those of zle (where inlcr which causes the terminal device driver to translate NL to CR is on among other things).

      ^J is the newline character, so binding it is a bit delicate.

      Here, you can work around it by defining a vim function as:

      vim() STTY=sane command vim "$@"
      

      Or add edit the STTY=sane (or STTY=-inlcr) to edit-command-line.

      share|improve this answer

        up vote
        2
        down vote

        accepted

        up vote
        2
        down vote

        accepted

        If you set your $EDITOR to a script or function that does stty -a, you’ll notice that the terminal settings at the time vim is called by that edit-command-line are those of zle (where inlcr which causes the terminal device driver to translate NL to CR is on among other things).

        ^J is the newline character, so binding it is a bit delicate.

        Here, you can work around it by defining a vim function as:

        vim() STTY=sane command vim "$@"
        

        Or add edit the STTY=sane (or STTY=-inlcr) to edit-command-line.

        share|improve this answer

        If you set your $EDITOR to a script or function that does stty -a, you’ll notice that the terminal settings at the time vim is called by that edit-command-line are those of zle (where inlcr which causes the terminal device driver to translate NL to CR is on among other things).

        ^J is the newline character, so binding it is a bit delicate.

        Here, you can work around it by defining a vim function as:

        vim() STTY=sane command vim "$@"
        

        Or add edit the STTY=sane (or STTY=-inlcr) to edit-command-line.

        share|improve this answer

        share|improve this answer

        share|improve this answer

        answered Dec 2 at 11:01

        Stéphane Chazelas

        296k54559904

        296k54559904

            draft saved
            draft discarded

            Thanks for contributing an answer to Unix & Linux Stack Exchange!

            • Please be sure to answer the question. Provide details and share your research!

            But avoid

            • Asking for help, clarification, or responding to other answers.
            • Making statements based on opinion; back them up with references or personal experience.

            To learn more, see our tips on writing great answers.

            Some of your past answers have not been well-received, and you’re in danger of being blocked from answering.

            Please pay close attention to the following guidance:

            • Please be sure to answer the question. Provide details and share your research!

            But avoid

            • Asking for help, clarification, or responding to other answers.
            • Making statements based on opinion; back them up with references or personal experience.

            To learn more, see our tips on writing great answers.

            draft saved

            draft discarded

            StackExchange.ready(
            function () {
            StackExchange.openid.initPostLogin(‘.new-post-login’, ‘https%3a%2f%2funix.stackexchange.com%2fquestions%2f484764%2fhow-to-prevent-vim-from-translating-c-j-into-c-m-when-started-by-the-zle-widget%23new-answer’, ‘question_page’);
            }
            );

            Post as a guest

            Required, but never shown

            Required, but never shown

            Required, but never shown

            Required, but never shown

            Required, but never shown

            Required, but never shown

            Required, but never shown

            Required, but never shown

            Required, but never shown

            Related Post

            Leave a Reply

            Your email address will not be published. Required fields are marked *