In "vi" mode you can edit/navigate on the current shell prompt like a line in the vi editor. You can look at it like a one-line text file. Analogously in "emacs" mode you can edit/navigate the current command line using (some) of Emacs' shortcuts.
Example
For example in vi-mode you can do something like (in bash):
$ set -o vi
$ ls hello world
<ESC>
bbdw # results in
$ ls world
In emacs-mode you can hit e.g. Ctrl+A to jump at the start of a line (vi: Ctrl+[, 0 or ESC,0). You can turn on emacs mode via set -o emacs
(in bash, ksh, zsh etc.).
Readline
A lot of interactive command line programs (including bash) use the readline library. Thus, you can configure which input mode to use (vi or emacs) and other options in one place such that every program using readline has the exact same editing/navigating interface.
For example my readline configuration looks like:
$ cat ~/.inputrc
set editing-mode vi
set blink-matching-paren on
For example zsh/ksh does not use readline as far as I know, but also support vi/emacs modes that are very much like the bash/readline one.
Of course, the vi/emacs mode in a command line shell is just a subset of the complete editor feature set. Not every feature makes sense in a command line shell, and some features are more complicated to support than others.
Canonical Mode
Before vi/emacs modes of interactive command line shells 'were invented' your shell would use just the canonical mode of your terminal which only provides a limited set of editing commands (e.g. Ctrl+W to delete the last word.
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
Best Answer
You can add this to your zsh configuration:
Explanation:
Vi-mode is just a set of preconfigured keymaps (viins, vicmd, viopp, visual) that bind certain keys to certain widgets. Some of these widgets are specifically designed to behave close to the way the vi editor does.
In your case this is the
vi-backward-delete-char
widget that is by default bound to Backspace in the viins mode, which has the specific feature to not delete past the position where insert mode was entered.Often sligthtly different versions of these widgeds exist, that behave more in line with the emacs editor. In this case it would be the
backward-delete-char
widget, which is not limited to the current insert session. Although it is by default bound in emacs-mode, there are no hard restrictions on which widget can be used in which mode. You can usebackward-delete-char
within vi-mode by simply rebinding Backspace to call the widgetbackward-delete-char
instead.The reason for there being two bindings -
^?
and^H
- is that it depends on the terminal, which of those two key sequences is sent on pressing Backspace. By default both are bound to the same widget in vi-mode as well as emacs-mode.