The USS Quad Damage

Vim vs Emacs for real!

I talk about the age old battle between vim and emacs, and specifically where vim loses out, and how to help.

There’s one thing about Emacs that’s it’s “killer feature”, it’s the consistency of vision from start to end. The reason people call it an “operating system” is that it has abstractions so powerful that you can just build and build. Nothing else comes close to being as fully featured. We’ve seen things like Eclipse and Idea being good in a “special purpose” sense, but only because they’re effectively supported by corporations.

By contrast, vim is a mess. I say this as a vim guy and a maybe-intermediate vim user. It has one amazing, seductive trick up its sleeve, and that is the power of its grammar and movement. It’s a text meta-editor, and that makes it immensely powerful. I suspect that many vim users are drawn simply by this, and will go from beginner to expert without ever really getting past simply feeling guilty for not being ninja enough for vim.

Unfortunately the power of the grammar sits alongside the immensely clunky and frankly random layout, command sprawl, and variety of input methods. Vim is hard to use because it carries with it a boatload of legacy.

I’m not like that. I’m also not about minimising keystrokes like many vim users. I’m all about Actions Per Second. I’d prefer to press more keys if I can do it more comfortably and more quickly than having to remember more keypresses. To that end, I’ve started to think more deeply about vim’s central grammar, its usefulness, and how it can be improved.

Stage 1: More consistency

Most of the grammar is set up so that if you type a lowercase letter, it will do a thing in the forward direction. If you type an uppercase letter, it will do a thing in the backwards direction. A classic example is / to search forward, ? (shift-/) to search backwards. There are some exceptiont to this rule, and I’d like to remap the keys so it makes more sense.

  • Shift ‘i’, ‘a’, and ‘A’: ‘i’ inserts before the current character and ‘a’ inserts after the current character. It would be more consistent for ‘I’ to go before the current character, and ‘i’ to go after. ‘I’ currently inserts at the beginning of the line. It would be better if ‘A’ prepended at the beginning of the line, and ‘a’ appended at the end of the line.
  • Move ‘b’ to ‘W’: ‘w’ moves to the next word, ‘b’ moves to the previous word. Instead, ‘w’ would move to the next word, and ‘W’ would move to the previous word. Remove the concept of “WORD”, which are used by old ‘W’, ‘E’, and ‘B’. ‘b’ is now unbound.
  • Shift ‘{’, ‘}’, ‘[’, ‘]’, ‘(’, ‘)’ around: Currently, ‘}’ goes to the end of the paragraph, and ‘{’ goes to the beginning of the paragraph. ‘[’ and ‘]’ deal with sections in GROFF files, and there’s some strange mumbo jumbo with, of all things, opening and closing braces. Instead, just remove whatever ‘[’ and ‘]’ do, make ‘[’ and ‘{’ do end and begin sentences, respectively, and ‘]’ and ‘}’ for paragraphs.
  • Switch '' and 'Q': Currently, 'q' records a macro, 'Q' enters 'ex-mode', and '' plays macros back. instead, ‘Q’ should play-back macros, and ‘@’ should enter ‘ex-mode’.
  • Move ‘*’ and ‘#’ to now-unbound ‘b’ and ‘B’: These look forwards and backwards for an identifier.
  • Move ‘^’ to ‘H’, ‘$’ to ‘L’, and ‘0’ to ''': The ‘H’ and ‘L’ keys effectively take you to a random spot in the file, based on your screen real-estate. These should be unbound. Instead, move the much more useful functionality of going to the beginning and end of a line to the cursor keys. The quote character ''' goes to the beginning of the line of a mark, and it seems too special purpose to keep around
  • Ctrl-F/B to ‘J’ and ‘K’, move ‘J’ to ‘Z’: ‘K’ currently looks for help on the currently selected word. Seriously what the even? ‘J’ is for joining lines and can be quite useful. We’ll move this to ‘Z’, which is for quitting vim (and surely everyone would agree that this is not something you need to do that often). Ctrl-F/B go page up and down. This makes the lowercase ‘arrow’ keys move a single character, and uppercase ‘arrow’ keys move to the extremities.
  • Ctrl-R to ‘U’ - ‘U’ is for ‘undo line’, and that’s confusing in a world with a full undo stack. Instead, it should just redo.

All the shift number keys are now unbound except for ‘!’, ‘@’, ‘%’, and ‘&’. “Lost” functionality in the list above could potentially be restored by shoving it up there, but I doubt anyone would miss any of it.

Stage 2: Simplify and cleanup

Here, we remove some special purpose or non-forward thinking commands from the grammar. This is a little more “optional” because there’a a certain amount of “unused functionality isn't hurting anyone”, but I’m aiming for maximum simplicity. Controversially, I’m also proposing removal of ‘g’ and ‘z’ for extra commands. The idea is that you’re pressing an extra character anyway, why not just go all the way with ‘:’?

  • Remove ‘~’: I love toggle-case, but it’s not internationalizable, and it’s simply too special case to abide.
  • Move ‘%’ to ‘s’, move ‘&’ to ‘S’: I can accept ex-mode and filtering to be heavy-weight enough to be on the number line, but matching braces and repeating search/replace is invaluable. I don’t really know anyone who uses ‘s’ substitute character or ‘S’ substitute line.
  • Move ‘`’ to ‘M’: ‘M’ is also a strange cursor movement command based on screen size. Instead we should make it goto mark, since ‘m’ is the mark key.
  • Unbind ‘z’ and ‘g’: The idea being, if you’re already hitting an extra character, may as well go all the way and hit ‘:’.

Stage 3: No ‘Ctrl’ key combos.

We already have commands, shift versions of those commands, and a handful of Ctrl commands. This is a lot to remember. Instead, the idea is that we remove all Ctrl-commands, and make it so the Ctrl-key is like a temporary push into command mode. Hitting Ctrl-x would be the same as typing ESC, x, i. This allows for entering commands and movements whilst in insert mode.

  • Ctrl-V to ‘0’: ‘0’ or start of line has been moved to ''', so is freed up for block visual mode.
  • i_Ctrl-N/P to ‘g’: Ctrl-N/P in insert mode do any-word completion. The idea is to use ‘g’ to initiate the completion, then select using the ‘j’ an ‘k’ keys. This is a little more annoying than currently, but not hugely. This means that you can do any-word completion in either command mode or insert mode, and it functions like a mini buffer / register. This also allows plugins to integrate more tightly with the experience of ‘g’.
  • ‘z’ for an “action” command: This will be a new idea for vim. The idea is to do an action based on the text under the cursor. This could be template substitution, auto-fixing bugs, etc. These would show up like choices in the Ctrl-N list. Like ‘g’, ‘z’ could be used outside insert mode.

Stage 4: And nothing else

The idea is not to pollute the namespace. This would mean using only the given functionality in or implied by the commands as defined. The idea is to work like surround.vim, where we extend the grammar, but follow all its rules, such as using “cs” to mean “change surround”. Of course, the ex-cmd line ‘:’ would still be open slather. The file formats could redefine the meanings of words, sentences, and paragraphs, as well as good autoformatting. Plugins could “hook into” ‘g’ autocomplete or ‘z’ actions. And that’s it.

So there we have it, a simple, consistent grammar for vim in the 21st century. No cruft, clean extension points, and no (real) loss of power from a powerful movement and command system.