Zsh Keybindings
Keymap Modes
Emacs vs Vi mode
# Emacs mode (default)
bindkey -e
# Vi mode
bindkey -v
export KEYTIMEOUT=1 # reduce mode switch delay (10ms)
# Check current keymap
bindkey -l # list all keymaps
bindkey -M emacs # show emacs bindings
bindkey -M vicmd # show vi command mode bindings
bindkey -M viins # show vi insert mode bindings
Essential Emacs-Mode Bindings
Default bindings (Ctrl-based)
# Navigation
Ctrl-a # beginning of line
Ctrl-e # end of line
Ctrl-f # forward one char
Ctrl-b # back one char
Alt-f # forward one word
Alt-b # back one word
# Editing
Ctrl-d # delete char under cursor (or EOF if empty)
Ctrl-h # backspace
Ctrl-w # delete word backward
Alt-d # delete word forward
Ctrl-u # delete from cursor to beginning of line
Ctrl-k # delete from cursor to end of line
Ctrl-y # paste (yank) last deleted text
Ctrl-t # transpose chars
Alt-t # transpose words
# History
Ctrl-r # reverse search history
Ctrl-s # forward search history
Ctrl-p # previous command (same as Up)
Ctrl-n # next command (same as Down)
Alt-. # insert last argument of previous command
# (repeat to cycle through older commands)
# Misc
Ctrl-l # clear screen
Ctrl-c # cancel current line
Ctrl-z # suspend current process
Ctrl-x Ctrl-e # edit current line in $EDITOR
Custom Bindings
bindkey patterns
# Bind to key sequence
bindkey '^[l' clear-screen # Alt-l to clear
bindkey '^X^E' edit-command-line # Ctrl-x Ctrl-e to edit in vim
# Bind to widget
autoload -Uz edit-command-line
zle -N edit-command-line
bindkey '^xe' edit-command-line
# Find key codes
# Run: cat -v then press the key
# Or: showkey -a
# Common sequences:
# ^[[A Up arrow
# ^[[B Down arrow
# ^[[H Home
# ^[[F End
# ^[[3~ Delete
# ^[[1;5C Ctrl-Right
# ^[[1;5D Ctrl-Left
Custom Widgets
ZLE (Zsh Line Editor) widgets
# Insert sudo at beginning of line
insert-sudo() {
BUFFER="sudo $BUFFER"
CURSOR=$((CURSOR + 5))
}
zle -N insert-sudo
bindkey '^[s' insert-sudo # Alt-s to prepend sudo
# Accept and run
accept-and-hold() {
zle accept-line # run command
# line stays in buffer for editing
}
# Jump to project directory
goto-project() {
local dir
dir=$(find ~/atelier -maxdepth 3 -type d -name ".git" 2>/dev/null | \
sed 's|/.git||' | \
fzf --prompt="Project: ")
if [[ -n "$dir" ]]; then
BUFFER="cd $dir"
zle accept-line
fi
}
zle -N goto-project
bindkey '^xp' goto-project # Ctrl-x p
Vi Mode Enhancements
Making vi mode practical
# Cursor shape changes by mode
function zle-keymap-select {
if [[ $KEYMAP == vicmd ]]; then
echo -ne '\e[2 q' # block cursor (normal mode)
else
echo -ne '\e[6 q' # beam cursor (insert mode)
fi
}
zle -N zle-keymap-select
# Initialize beam cursor for insert mode
zle-line-init() { echo -ne '\e[6 q' }
zle -N zle-line-init
# Keep useful emacs bindings in vi insert mode
bindkey -M viins '^a' beginning-of-line
bindkey -M viins '^e' end-of-line
bindkey -M viins '^r' history-incremental-search-backward
bindkey -M viins '^w' backward-kill-word