The Great Controversy
A standard dictum amongst experienced Vim users is not to use the arrow keys to move around your document. This dictum is often repeated again and again, in tones that range from the taken-for-granted to hysterical-zeal. The most common reason given for this is that using the arrow keys takes your hands away from the home row of your keyboard, and thus is wasteful both in terms of time and energy, whereas the standard Vim movement keys —|
l —| keep your hands on the home row, and therefore is far more efficient. Here is what I have discovered: this anti-arrow key argument is wrong!
The Great Experiment
When I first started using Vim, I of course found the
l keys to be horribly unintuitive.
But what was worse was that I could not use these keys to move in insert mode.It was this latter issue that kept me resolutely married to my arrow keys.The centi-seconds of time it took for me to move my fingers to hit an arrow key seemed far more efficient than exiting into normal mode, using the
l to move to where I wanted, and then
i again to get back into insert mode. And so, for the longest time, not only did I continue to use the arrow keys, but I had absolutely no desire to cease doing so, just to gain what would probably accumulate to be about an hour’s worth of saved time over the course of a year.
Recently, however, on a whim, just to see what the fuss was about and if I was correct in viewing the arrow-keys-Noooooooooo!-zealots as the computing equivalent of monodimensional cladist fundamentalists, I decided to indulge in what I initially viewed as a temporary experiment in masochism.
Yes, that’s right.
I disabled my arrow keys:
inoremap <Up> <NOP> inoremap <Down> <NOP> inoremap <Left> <NOP> inoremap <Right> <NOP> noremap <Up> <NOP> noremap <Down> <NOP> noremap <Left> <NOP> noremap <Right> <NOP>
It did not take long (less than an hour) for me to get used to the spatial directions mapped to the
l keys, and so within a day I was comfortable using these keys to move around in normal mode. But the inability to move around in insert mode was incredibly annoying. It got so frustrating that I considered switching back to using arrow keys permanently, but decided to stick with the pain of trying to work in this tedious and painful environment for a little longer before giving up.
The Great Results
After a couple of days, I came to the realization that I had started working with Vim in a different way. It happened gradually, and mostly unconsciously, so that I did not notice it as first. But I did begin to notice that I was no longer tripping up or stumbling quite as much when needing to move around my document. In fact, quite the opposite, I felt like I was zipping around to places much faster and much more efficiently than I ever did before when I was using the arrow keys.
This feeling was not due to the gains from those accumulated centi-seconds shaved off my editing time by not having to move off the home row so frequently.</ on p>
It was, instead, due to the consequence of being forced to exit insert mode when I was not actually typing text.
Being forced to return to normal mode right after I edited the text at a single point in the document (sometimes just a couple of characters, sometimes a word or two, sometimes short blocks or fragments), also resulted in me being forced to use the rich suite of powerful normal mode movement commands to get to exactly where I needed to be before resuming editing. This was like suddenly beginning to use the fifth and other gears while driving on an open highway, whereas before I had been grinding along for mile after laborious mile on first.
The most remarkable and unanticipated aspect of my new way of working with Vim was not so much my usage of the
l keys, and other relatively “dumb” movement keys (
$, etc.). It was my much greater usage of “smart” movement keys and commands. Due to the shift in the dominant ecology (i.e., normal mode vs. insert mode dominant), my repertoire of idioms for movement within and across the buffer evolved, and simple up/down/left/right movements were replaced by far more efficient and powerful commands. For example, I would use
; etc. to jump to the exact character on a line that I wanted to get to, instead of pecking away at the left/right keys to get there. I would use
150G to jump directly to line 150 instead of using the up/down arrow keys. I would use
?def to jump directly to a function line instead of tapping away a directional key like a zombie trying to signal in pseudo-Morse. I would use marks (e.g.,
mm) to register an “anchor” into the document that I could jump back to directly (by using, for example,
'm), before moving off to temporarily work on some other part of the document.
It is true, of course, that none of these movements are in any way more efficient when, for example, to moving a couple of characters to the left or right or up or down of the current position while in insert mode. In fact, this “local neighborhood” (i.e., one or two characters/lines on either side of my current position) is exactly where the arrow keys do come into their own by allowing you to get to these places without leaving insert mode. It is only when we start dealing with positions more than a couple of offsets away from the current position that the normal mode movement keys and commands start to yield benefits.
But the fact is, while I had arrow keys enabled I simply found it difficult to consciously make it a point to limit my use of them only within the “local neighborhood” . When in insert mode, and I needed to get anywhere that I could see in the viewable buffer, without thinking about it I would start tapping away at the arrow keys, even if the destination was several to dozens of lines/characters away. So while I had learned and started using all those “smart” movement commands that I am using now within the first couple of months of using Vim, I was just not using them enough or in all the places that I should been using them.
Disabling the arrow keys, while making “local neighborhood” movement significantly more cumbersome than before, taught and continues to teach me to view the document as a landscape, across which I can visit any point that I want directly and precisely through Vim’s normal mode movement commands. I still have not completely internalized this perspective, and often find myself reaching for the arrow keys unconsciously while editing in insert mode. So, for the time being, until this regime has been exorcized from my muscle memory, I think I am going to keep my arrow keys disabled as motion keys.
Re-Educating the Arrow Keys to Work With You: Text Shifters Instead of Cursor Movers
However, that does mean that I have 4 decent keys on my keyboard not doing anything at all. That, to me, seems just as wasteful as any of the extra energy and time required to use them. And thus I decided to put those arrow keys to work as “text movers” rather than their default role as “cursor movers”.
Editing text is like doing surgery: when you start hacking away at a bit of code, you usually open up various gashes and slashes in the surrounding area. At least with modern medical practices, it is both customary and polite to sew up these gashes and slashes, and naturally we do the same when editing code: indentation has to restored (here is a tip: see what
== can do for you in Vim), empty lines need to be closed up, etc. etc. We probably do this dozens of times during a particular edit session, and typically it involves a lot of moving around, deleting and inserting lines all over the place. Even with the power of Vim’s normal mode commands, it still takes a lot of keystrokes, tedium and hassle to achieve this.
And so I have remapped my arrow keys to do the following:
Uparrow key deletes a blank line above the current line (a non-empty line will not be deleted), while the
Downarrow key inserts a blank line above the current line. The result is hitting
Downmoves the current line up or down, in both normal as well as insert mode.
Ctrl-Down, instead, deletes or inserts a blank line below the current line. The result is that the text below the current line moves up or down, respectively.
Leftde-dents the current line, while
Rightindents it. The result is that text shifts left and right, respectively.
The following code, included in your
~/.vimrc or otherwise sourced into your session, implements this (the actual functions that do the work are copied from here):
function! DelEmptyLineAbove() if line(".") == 1 return endif let l:line = getline(line(".") - 1) if l:line =~ '^s*$' let l:colsave = col(".") .-1d silent normal! <C-y> call cursor(line("."), l:colsave) endif endfunction function! AddEmptyLineAbove() let l:scrolloffsave = &scrolloff " Avoid jerky scrolling with ^E at top of window set scrolloff=0 call append(line(".") - 1, "") if winline() != winheight(0) silent normal! <C-e> endif let &scrolloff = l:scrolloffsave endfunction function! DelEmptyLineBelow() if line(".") == line("$") return endif let l:line = getline(line(".") + 1) if l:line =~ '^s*$' let l:colsave = col(".") .+1d '' call cursor(line("."), l:colsave) endif endfunction function! AddEmptyLineBelow() call append(line("."), "") endfunction " Arrow key remapping: Up/Dn = move line up/dn; Left/Right = indent/unindent function! SetArrowKeysAsTextShifters() " normal mode nmap <silent> <Left> << nmap <silent> <Right> >> nnoremap <silent> <Up> <Esc>:call DelEmptyLineAbove()<CR> nnoremap <silent> <Down> <Esc>:call AddEmptyLineAbove()<CR> nnoremap <silent> <C-Up> <Esc>:call DelEmptyLineBelow()<CR> nnoremap <silent> <C-Down> <Esc>:call AddEmptyLineBelow()<CR> " visual mode vmap <silent> <Left> < vmap <silent> <Right> > vnoremap <silent> <Up> <Esc>:call DelEmptyLineAbove()<CR>gv vnoremap <silent> <Down> <Esc>:call AddEmptyLineAbove()<CR>gv vnoremap <silent> <C-Up> <Esc>:call DelEmptyLineBelow()<CR>gv vnoremap <silent> <C-Down> <Esc>:call AddEmptyLineBelow()<CR>gv " insert mode imap <silent> <Left> <C-D> imap <silent> <Right> <C-T> inoremap <silent> <Up> <Esc>:call DelEmptyLineAbove()<CR>a inoremap <silent> <Down> <Esc>:call AddEmptyLineAbove()<CR>a inoremap <silent> <C-Up> <Esc>:call DelEmptyLineBelow()<CR>a inoremap <silent> <C-Down> <Esc>:call AddEmptyLineBelow()<CR>a " disable modified versions we are not using nnoremap <S-Up> <NOP> nnoremap <S-Down> <NOP> nnoremap <S-Left> <NOP> nnoremap <S-Right> <NOP> vnoremap <S-Up> <NOP> vnoremap <S-Down> <NOP> vnoremap <S-Left> <NOP> vnoremap <S-Right> <NOP> inoremap <S-Up> <NOP> inoremap <S-Down> <NOP> inoremap <S-Left> <NOP> inoremap <S-Right> <NOP> endfunction call SetArrowKeysAsTextShifters()
Using the arrow keys for cursor movement cripples you in terms of time and efficiency, due to the far superior alternatives found in normal mode. Using the arrow keys for shifting text, on the other hand, empowers you by wrapping up an often-used series of repetitive and stereotypical actions into a single keystroke.
Modified slightly to say “Don’t Use the Arrow Keys for Movement”, this dictum basically holds. But I think it utterly fails to capture the real issue at hand, and the customary justification offered for it (the whole “taking your hands off the home row is wasteful”) fails to make for a convincing argument.
Instead, I think that Vim tutorials, guides, advocates and propaganda everywhere should emphasize:
This is because normal mode offers so much more power and flexibility to get to any part of your document precisely and quickly. The “Don’t Use the Arrow Keys for Movement” should be offered as a corollary to this, rather than a primary statement in its own right, because using arrow keys for movements leads you —| for psychological reasons —| to remain trapped in insert mode when you should be cruising and jetting about in normal mode.