Vim’s Big Idea

Learning the lesson of vi

Mike Kozlowski

--

1976 was a good year for text editors. At MIT, Richard Stallman and Guy Steele wrote the first version of Emacs. And over at Berkeley, Bill Joy wrote vi (though it wouldn’t be called that for a few years yet).

It’s reductionist to say that these two editors were each built around one big idea, but what the hell, let’s be reductionist. Because what stands out today, looking at modern editors like Sublime Text and Atom, is how Emacs’ big idea has been thoroughly learned — and how vi’s big idea hasn’t.

Emacs and Extensibility

Emacs’ big idea was that it could be modified and extended cleanly. The functionality of the editor is defined in a library of commands, which are then bound to particular keystrokes. So there might be a save-buffer command bound to C-x C-s, a kill-region command bound to C-w, and so on.

If you don’t like those key mappings you can change them — go ahead and make kill-region be C-k if you want. And you can do more than just change mappings: If you want additional functionality, you can just write your own functions in the same language as the built-in functions (Lisp, in the case of GNU Emacs). The editor’s UI is almost infinitely malleable, and can be mutated to any purpose you desire.

If this sounds a bit commonplace, it’s because Emacs’ big idea has been widely influential and extensibility is today a standard feature in any serious editor. Sublime Text uses Python instead of Lisp, and Atom uses Coffeescript, but the fundamentals of commands and keymaps are built in to the core. Even Vim has absorbed Emacs’ extensibility: Vim script can define new functions, which can be mapped to command keystrokes.

Vi and Composability

Vi’s big idea hasn’t been nearly as influential.

Vi is fundamentally built on command composability. It favors small, general-purpose commands that can be combined with objects to compose larger commands. By contrast, Emacs and its philosophical descendants (including Sublime Text and Atom) use monolithic, special-purpose commands.

Let’s say that you want to move the cursor forward a word, to the end of the line, to the end of the file, or to the end of the paragraph.

Emacs has commands for these motions: forward-word, move-end-of-line, end-of-buffer, and forward-paragraph, respectively. Atom has commands for three of them: moveCursorToBeginningOfNextWord(), moveCursorToEndOfLine(), and moveCursorToBottom().

Vim’s got commands for these, too: w, $, G, }. Those are weird function names, a heritage of vi’s non-programmable past (where keys and commands were inextricably bound), but fundamentally we’re in the same ballpark.

But now let’s look at delete commands. Let’s say you want to delete a word, delete to the end of the line, delete to the end of the file, or delete to the end of a paragraph.

Emacs only has two of these functions: kill-word and kill-line. Atom has the same two, more or less: deleteToEndOfWord() and deleteLine().

Vim, though, is different. Vim only has one command: d, which is “delete.” What does it delete? You name it, literally. The d command gets combined together with those commands for movement: dw deletes to the next word, d$ to the end of the line, dG to the end of the file, and d} to the end of the paragraph.

This is where Vim’s composability leads to its power. Emacs and Atom don’t have commands for deleting to the end of a file or a paragraph — even when they have commands to move to those places. But in Vim, if you can move to a location, you can delete to that location.

And composability is about more than just power, it’s also about learnability and consistency. The command for copying text in Vim is y. Do you know how to copy to the end of the line/file/paragraph? Of course you do: It’s y$, yG, and y} respectively. The command for increasing the indent is >, so you instantly know >$, >G, and >}. Convert to lowercase is gu, so… sure enough: gu$, guG, gu}.

This works both ways, of course. If you go on to learn that t= means “move until the next occurrence of the = character”, you now know what dt=, yt=, >t=, and gut= do. The composability of Vim commands means that every command you learn can act on any target; and every motion/object you learn makes every command you know more powerful.

This philosophy of minimalist commands that can be composed together is the fundamental originating philosophy of Unix, and Vim exemplifies it like no other editor.

Vim Forever?

But of course, Vim isn’t perfect. Vim script is nobody’s preferred programming language; the out-of-box experience is terrible; you need to install a half-dozen third-party plugins (and a third-party plugin manager at that) to get basic functionality working; its modal nature makes it difficult to approach; and there are some fundamental limitations to its extensibility (particularly visually).

A new, shiny, modern editor could one-up Vim by fixing some (or hopefully all) of these issues. But before an editor can replace Vim, it needs to learn everything that 1976 has to teach — not just the lesson of Emacs, but also the lesson of vi.

--

--