Zsh Vi Mode and Command History
November 7, 2020
I’ve been using zsh for about 15 years but despite this I’ve noticed lately I’m pretty inefficient at editing commands in particular, mostly because I don’t have a clue about emacs keybindings. I am however very familiar with vi bindings but my config was never properly setup for zsh, I couldn’t search history like I could in emacs mode and I’ve been blundering along in this state for too long. (turns out it was just because the bindkey’s were not declared after doing bindkey -v to go to vi mode, oops)
Took a little time this weekend to switch to zsh vi mode and polish up my config so I could efficiently navigate. Most of my config is driven through oh my zsh these days, but I found these additions perfect for working with vi bindings:
#########
# vi mode
#########
bindkey -v
# switch to command mode with jj
bindkey '^j' vi-cmd-mode
# `v` is already mapped to visual mode, so we need to use a different key to
# open Vim
bindkey -M vicmd "^V" edit-command-line
# Make Vi mode transitions faster (KEYTIMEOUT is in hundredths of a second)
export KEYTIMEOUT=1
# incremental search in insert mode
bindkey "^F" history-incremental-search-forward
bindkey "^R" history-incremental-search-backward
# beginning search with arrow keys and j/k
bindkey "^[OA" up-line-or-beginning-search
bindkey "^[OB" down-line-or-beginning-search
bindkey -M vicmd "k" up-line-or-beginning-search
bindkey -M vicmd "j" down-line-or-beginning-search
# beginning search in insert mode, redundant with the up/down arrows above
# but a little easier to press.
bindkey "^P" history-search-backward
bindkey "^N" history-search-forward
# incremental search in vi command mode
bindkey -M vicmd '?' history-incremental-search-backward
bindkey -M vicmd '/' history-incremental-search-forward
# navigate matches in incremental search
bindkey -M viins '^R' history-incremental-pattern-search-backward
bindkey -M viins '^F' history-incremental-pattern-search-forward
Highlights here:
Type the start of a command and press up/down arrows to cycle through history for that command. I’ve always used Ctrl-P and Ctrl-N for this but the arrow keys and in the above they work roughly the same.
Ctrl-R and start typing any part of a past command to incrementally search through history. Ctrl-F to move the opposite direction.
Ctrl-J to go into vi command mode and start editing. This flows better than Esc, but technically I think Ctrl-[ is also there by default and very close to J, none the less it doesn’t feel quite as easy to hit.