Shell – How to configure ZSH’s vi mode to persist the state between commands

shellvi-modezlezsh

I am aware how to set ZSH's default line editor to use vi-like keybindings…

bindkeys -v

…and even to default each new prompt to be in command mode instead of insert mod by default…

zle-line-init() { zle -K vicmd; }
zle -N zle-line-init

…and most of the time I prefer this behavior. However, it makes a few things very awkward. For example pasting multi-line commands into a terminal for immediate execution becomes nearly impossible.

How can I configure it so that the mode is persistent? I would like whatever mode it was when I executed one line should be the default mode for the next line.

Best Answer

Maybe like:

vicmd-accept() { prev_mode=vicmd; zle .accept-line }
viins-accept() { prev_mode=viins; zle .accept-line }
zle-line-init() { zle -K ${prev_mode:-viins} }
zle -N viins-accept
zle -N vicmd-accept
zle -N zle-line-init
bindkey -M viins \\r viins-accept
bindkey -M vicmd \\r vicmd-accept

Or even simpler:

accept-line() { prev_mode=$KEYMAP; zle .accept-line }
zle-line-init() { zle -K ${prev_mode:-viins} }
zle -N accept-line
zle -N zle-line-init