Early on in the history of the editor wars, adherents of Emacs banded together to form a religion. As a result of this ecclesiastical schism, vi came to be known as "the editor of the beast". It comes as no surprise that something denounced by a particular religious sect turns out, in reality, to be very awesome, useful, and generally good for society.
I am talking, of course, about the power of modal editing.
The ubiquitous, second-nature process of reading and writing belies the fact that working with text is a subtle, complex, and multifaceted task. Moreover, in our interactions with text we typically spend the majority of the time reading, searching, and editing. This is doubly true for structured text, such as Wikipedia markup or computer programs. Key-chord-based text editors make this process needlessly slow and inconvenient.
But this post isn't just another vi/Vim paean. This post is about Evil, the Extensible Vi Layer for Emacs written by Frank Fischer and Vegard Øye. It allows to combine the incredible power of Emacs with the ergonomics, terseness, and efficiency of Vim, and if you are an Emacs user, you should check it out. If you are a Vim user, here's your chance to switch to a better editor without having to retrain the muscle memory.
Currently, most Evil users seem to come from the Vim camp. As a result, Evil's defaults skew towards Vim behavior. This makes it somewhat difficult to adopt for us Emacs users: we have to face the double task of learning Vim, as well as figuring out how to make the modal editing paradigm work smoothly with the existing Emacs usage patterns. As someone that has done this journey, I would like to share some tips.
So let's assume you successfully installed Evil. Great! Now, what exactly did you get yourself into? Well, effectively, all Evil does is redefine the key bindings depending on the context, or "state". As a user, you will primarily deal with three states: normal (for navigating/editing), insert (for typing characters), and motion (used for read-only buffers such as help). There is also the Emacs state, which simply gives you familiar Emacs behavior, the same as what you'd get if you turned off Evil.
One option, therefore, is to use Evil's Emacs state as a default, using
C-z to toggle between it and the normal state. However, I don't recommend this approach, as one would be tempted to revert to old Emacs habits, thereby missing 90% of the awesomeness Evil provides. Let's just plunge in:
(setq evil-default-state 'normal)
Now do a Google search for a good Vim tutorial, and experiment lots!
Issues you might encounter as an Emacs user
Insert state clobbers some useful Emacs keybindings
The solution to this is to clear the insert state keymap, leaving you with unadulterated Emacs behavior. You might still want to poke around the keymap (defined in
evil-maps.el) and see if you want to salvage some useful insert state command by rebinding them to keys of your liking. Also, you need to bind
ESC to putting you back in normal mode. So, try using this code. With it, I have no practical need to ever switch to Emacs state.
(setcdr evil-insert-state-map nil) (define-key evil-insert-state-map (read-kbd-macro evil-toggle-key) 'evil-emacs-state)
I want the keybinding X to work in Evil!
You can always override or add bindings to any Evil state. Just use something like this:
(define-key evil-normal-state-map "\C-r" 'isearch-backward) (define-key evil-normal-state-map "\C-e" 'evil-end-of-line) (define-key evil-motion-state-map "\C-e" 'evil-end-of-line)
Evil bindings for key X shadow the default bindings in mode Y
A common culprit here is the
return key, which is ordinarily bound to
evil-ret (a command that, as of this writing, doesn't know about what return is supposed to do in a current mode).
A crude but effective solution is to change Evil bindings on a per-state, per-mode basis, like so:
(evil-declare-key 'motion completion-list-mode-map (kbd "<return>") 'choose-completion) (evil-declare-key 'motion completion-list-mode-map (kbd "RET") 'choose-completion) (evil-declare-key 'motion browse-kill-ring-mode-map (kbd "<return>") 'browse-kill-ring-insert-and-quit) (evil-declare-key 'motion browse-kill-ring-mode-map (kbd "RET") 'browse-kill-ring-insert-and-quit) (evil-declare-key 'motion occur-mode-map (kbd "<return>") 'occur-mode-goto-occurrence) (evil-declare-key 'motion occur-mode-map (kbd "RET") 'occur-mode-goto-occurrence)
Note that I am using both the
<return> forms to make sure the key works both in terminal and under X.
This issue becomes more tricky in "read-only" modes that use letter keys for navigation (e.g. info, dired, ibuffer). It's not obvious to me what the best practices are for such modes. Should the Emacs bindings shadow Evil normal state? Does insert or normal state make more sense as the default? Currently, I don't have clear-cut answers.
I don't want Evil to ever touch keybinding X
This can too be arranged! Define the following function:
(defun evil-undefine () (interactive) (let (evil-mode-map-alist) (call-interactively (key-binding (this-command-keys)))))
Now, to make sure that Evil's normal state never touches
TAB, just wire this fall-through binding like so:
(define-key evil-normal-state-map (kbd "TAB") 'evil-undefine)
Mode X should start in normal state, but mode Y should start in insert state
(evil-set-initial-state mode-x 'normal) (evil-set-initial-state mode-y 'insert)
Doing a copy via M-w loses a character
If you are running Emacs 24, see if you are being affected by this bug.
My selection is off by a character
This can be somewhat subtle, as Emacs and Vim have different defaults regarding the visual/transient mark. In particular, in Emacs, the last selected character is always the one before the point. This makes operating on text from left to right and from right to left asymmetrical: if you wanted to select the string
123, and your cursor is on the 1, you press
C-SPC,C-3,C-f. However, if your cursor is on the 3, you first have to move it past the 3, and only then do
C-SPC,C=3,C-b. In Vim, on the other hand, the last selected character is always under point, so you'd just do
v2l if the cursor is no the 1, or
v2h if the cursor is on the 3. The fact that in Emacs, you always deal with this asymmetry, whether you are aware of it or not, can lead to selections (or, in general, cursor positioning) being off by a character when you use commands that are, conceptually, the same in Emacs and Vim, but differ in their treatment of character under point vs character before point. The good news is that Evil provides the following setting, which might help with correct character selection at beginnings and ends of lines:
(setq evil-want-visual-char-semi-exclusive t)
You might also look into changing Vim's default behavior whereby the cursor moves back one space (although this behavior makes a fair amount of sense). For this, you could look into
(setq evil-move-cursor-back nil) ;;and maybe also: (setq evil-highlight-closing-paren-at-point-states nil)
You could also try playing with
(setq evil-visual-char 'exclusive), but I personally see no good reason to use that setting. In my own configuration, I just turned on
evil-want-visual-char-semi-exclusive and it's been working well for me thus far.
Favorite Vim / Evil usage patterns
I will keep this section brief, since I am relatively new to the Vim way of editing text. Here are a few things that I have found handy or elegant in my 1.5 months with Evil. Some of these are pretty trivial, and some have Emacs equivalents (either built-in or via add-on Elisp). However, everything just feels cleaner without having to press
M all the time.
We all know that isearch is the way to navigate text in Emacs buffers, and
/ is very similar to isearch. Because
/ is ergonomically superior to
C-s, I find myself using the search-to-navigate paradigm much more than with my old Emacs setup.
C-v allows you to select rectangles and do things like insert or paste text before every line in a rectangle. In Emacs, CUA rectangle mode does something similar, but you have to enable it. In Evil, it comes built-in.
Combining search, motion, deletion, and selection commands
Such combinations are very powerful. Here are a few examples to give you a flavor of what I am talking about:
d/foo[RET]: deletes from point to string "foo"
dfa: deletes from point to character "a", inclusive
cta: deletes from point to character "a", exclusive, and puts you in insert mode
viw: selects inside word
vfa;: selects from point until the second occurrence of char "a", inclusive
yi): copy text inside parens
di": delete text inside double quotes
Operating on surrounding delimiters (quotes, parentheses, etc.)
These are enabled by the port of Vim's surround plugin, available here. You can do things like change double quotes to single quotes via
cs"', surround words with HTML tags, and if you have selected some text, surround it with delimiters via e.g.
Defining your own normal mode commands
For instance, I have
gj mapped to
org-goto in org-mode, and
gb mapped to
ido-switch-buffer. I like those way more than the original bindings.
One can take this idea further and create keymaps starting with a dedicated leader key (
, has been suggested as a good leader key choice). See this discussion for more insight into how one might do this via a plugin or Emacs built-in keymap functions.
Where to learn more
Evil is a relatively new project, and resources online are somewhat sparse at the moment. Some of the useful resources out there are:
- Evil on Emacswiki
- Official mailing list
- Michael Markert's Evil config file is an excellent example of how one might want to customize Evil bindings and behavior, and do so in a clean manner. There are lots of goodies there, my favorite being a method to dynamically change the look of the cursor based on the state (insert vs normal). (Note that the code in that file sometimes relies on external utility functions.)
- For a quick run-down of Evil's internals, consult the PDF or Info documentation that comes with the code.
I would have very much liked to include some Vim tutorials here, for the benefit of Emacs users, however, most of the materials that I have stumbled upon seem to be either too basic or too advanced. If you have something that you like, please leave a comment!
Most of the choices we make result in imperfect compromises, which makes it easy to lapse into the "grass is greener" mentality. I am a lindy hopper that envies salsa dancers, and a Linux/Android user that evangelizes all things Apple. Up until recently, I've been an Emacs devotee that coveted modal editing. Today, however, my CapsLock key is mapped to ESC instead of Ctrl, and the world is a slightly more perfect place – all thanks to the powers of Evil.