Zsh Vi Mode and Command History

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.