How to configure zsh with vi bindings and nice shortcuts

Having a good working environment is vital for feeling comfortable being productive. This extends to computational tools and the command shell is an integral part of the daily work for many of us. It’s a good idea to configure the shell’s interface to be efficient and pleasant to use. Here we see how zsh, arguably the best shell around, can be configured to suit the needs of people used to vi key bindings (which are arguably arguably superior and more ergonomical than the default emacs-style bindings)1.

Using vi-bindings in the shell

The first step towards nice vi key bindings is almost too easy: The red pill takes the form of

Type it into your prompt (and add it to your .zshrc file) and emacs bindings are going bye-bye. Escape will bring you to normal-mode, while i, a, o etc. will bring you back to insert-mode, just as with your favorite editor. Use j and k in normal-mode to go through your history and move around within the line with h, l, w, b and the like.

This is a good start, let’s see how we can bring it from “this is nice” to “that’s just awesome”.

First, we may want to keep some of the default key bindings in insert-mode since we’ve grown accustomed to them. No missing out, let’s put them back in:

You can take a look at the key bindings defined for emacs-mode by typing bindkey -M emacs -L and reuse the bindings you like. See the zshzle manpage for more pre-defined widgets for which you could define bindings.

Configuring the prompt to show the current editing mode

So the key bindings are quite usable now, but it’s a bit unfortunate that it is impossible to see if the shell is in insert- or normal-mode. There should be a mode indicator right in the shell prompt!

This gives a prompt in the style of

user@host /current/working/path
[I] %

where [I] is the insert-mode indicator and is changed to [N] when normal-mode is activated. Neat, isn’t it?

Single- and multi-key shortcuts

This is all nice and dandy, but it’s not quite like vim yet. How about those sweet bindings where pressing jj in quick succession brings us to normal-mode without having to press Esc? Setting it up is easy as pie.

We can also add two-key bindings to jump to the start and end of the line:

Jumping to the beginning of the line is now as easy as pressing ; and h at the same time. No need to switch to normal-mode and your fingers don’t leave the your keyboard’s home-row. Try it, it’s great!


Customizations like this can make it much more pleasant to use the command line and boost your productivity. If the above is still not enough, here are some more ideas:

  • Define custom keymaps, e.g. to control other programs such as mpc or tmux.
  • Switch to said keymaps via some nice bindings.
  • Show the status of version control systems and build environments in the prompt.

If you don’t feel like doing all the work yourself, I can heartly reommend you take a look at oh-my-zsh. It offers a great collection of ideas to build on and some really cool ready-to-use plugins. Have fun!

  1. Emacs is a great program which I’ve been using for years and continue to use daily, but vi bindings just make good things better. Thanks to evil, that’s not a problem.