In a previous post I described the “language” metaphor of the text editor vi. To recap,
- Verbs are commands such as change
c
, deleted
, yanky
, and putp
- Nouns (text objects): a paragraph
ap
, a stringa"
, etc. - Prepositional phrases (motions):
“to the next word”
w
, “to the next regex”/
- Numerals (counts) as seen in
“indent ten lines”
10>>
and “to the 27th line”27gg
.
This time around, we’ll see how Vim (vi improved) adds a new word order to make you speak more clearly, and meta-verbs to blow your mind!
Speak Before You Think
Near the end of my previous post we got to the numerals, or counts as they’re officially called. Counts are useful, especially when large numbers are involved, but sometimes it pays off to use Vim without thinking too much ahead. Just start speaking:
Delete … a bit more … a bit more … bit more … ok, stop.
While this is the way many people delete text on their computer, Vim makes it
a lot more efficient than the typical awkward bursts of holding down the delete
key until you delete enough (and probably too much). For example, dw....
deletes one word, then the next, and so on, five in total. (Remember,dw
deletes one word, and the dot .
command repeats this action.) This can be
faster than the equivalent d5w
because you don’t need to count the words
before you start deleting . The running feedback you get by seeing the words
disappear one by one is very helpful and avoids the mistakes that could have
happened due to miscounting. It is especially useful for objects that vary
considerably in size (sentences, paragraphs), because they are harder to count
quickly.
But this approach doesn’t work for common operations such as change c
or yank
y
. When you yank (copy), you most likely want all the text in the clipboard
at the same time; not one word replacing the next until you are left with only
the last word in the clipboard. Probably for the same reason, the repeat .
command doesn’t consider yanking a repeatable action. (By the way, I say ‘the
clipboard’ because it is a familiar term to many, but in Vim, they’re called
registers, and there’s a whole lot more than one of them!) Instead of repeat,
we can use visual mode, which gives both pleasant feedback and works with all
actions.
… or Speak Like Yoda
To explain visual mode, we will first pay the 1970s a brief visit. In vi, “visual mode” was a mode that was “more visual” than the Teletype oriented editors vi superseded and subsumed (ed and ex, respectively). It meant simply that you could see the file while you edited it. However, this form of visual feedback was soon considered normal. Case in point, vi’s visual mode is Vim’s normal mode.
The way to be more visual than Vim’s normal mode is to highlight the text that
will be changed before the change is executed. This is similar to selecting
text in mainstream editors with the mouse or by using the arrow keys with the
shift key held down. In these, typing while text is selected replaces the
selected text with the typed text. Vim’s visual mode however retains the
keyboard’s “gamepad role” (see my previous post). (Vim also has
a “mainstream” select mode but it is mainly used to imitate
lesser other editors.)
You enter visual mode using v
, then use text objects and motions to highlight
the text you want to affect. This reverses the word order in the vi language,
effectively making you command Vim like Yoda: “These lines delete (you must!)”
Compare:
das
: “Delete a sentence.”vasd
: “A sentence delete.”dasdw
: “Delete a sentence. Delete the next word.”vased
: “A sentence and the next word delete.”
So, visual mode is nice because it gives visual feedback on the area you are going to operate on before you commit to it and type the operator. But it doesn’t stop there.
Visual Basics
What would you do if you had a lot of gamepad real estate to go along with visual mode?
First of all, visual mode actually comes in three flavors: Character v
, line
V
, and block <c-v>
. Here I switch around between them a bit:
(The numbers in the margin show the line number for the line the cursor is on, and the distance to the other lines. This feature makes is easy to use counts with line-based operators.)
Visual character mode is the one you will find most familiar: The selection starts somewhere, continues along the direction of the text, wraps at the ends of lines, and ends somewhere. In visual line mode, every whole line from the one the selection starts in to the one it ends in, is selected. This makes it easy to select whole lines without moving the cursor to the start and end of a line. Especially useful in programming, where line is often synonymous with statement. Finally, visual block mode selects a rectangle of text. Applying operators to blocks is very powerful and enables things that would take a long time without block mode.
Block mode can also be used to insert text at several lines simultaneously.
From block mode, insert I
and append A
start insert mode, and when the
insertion is done, that text is then inserted in every line along the left or
right edge of the block, respectively.
Also, the $
motion can be used to extend the selection to the ends of
lines. If the lines have different lengths, the result is a jagged block.
Appending A
to this inserts text at the end of each line, wherever the end of
that line is. In the video I demonstrate both I
and A
. Here’s a breakdown:
1 2 3 4 5 6 7 8 9 10 |
|
All this might look scary, but that’s of course part of what makes it so cool!
In the end of the video I do the same thing in one step using Tim Pope’s
surround.vim plugin. With the same selection active, I use
Sf
to “surround with function-call”, type “foo” and enter.
Neat Tricks
Have you tried selecting text in a mainstream editor and finding out you
started the selection in the wrong place? So you do the selection again, and do
it right this time. Well, Vim is all about efficiency: In visual mode, o
moves the cursor to the other end of the selection, so you can adjust it
without starting over. As amazing as it is simple! A soft, smiling kitten is
born every time you use this feature.
Also, with visual mode, you can crawl up the DOM tree: at
extends the
selection to the enclosing tag-block (Vim-speak for an HTML/XML element).
Applied repeatedly, a bigger and bigger block of markup is selected,
corresponding to nodes further up the DOM tree.
Both visual mode and repeat .
can be used in the “speak before you think”
manner, but visual mode works with all operators. It also has another advantage
over repeat: The operation is “committed” in one step, so it can be undone in
one step. This brings us to …
Meta-Verbs
Undo is a verb. It’s a verb for a command that reverts the latest change, no surprises there. But what happens when you undo two times in a row?
In vi, undo is a change like any other. Thus, if the latest change is an undo,
undo will revert that undo action. In other words, typing uu
is a no-op! Vim,
being “vi improved”, can emulate vi or use its own improved undo,
which could be called a meta-verb: Verbs change text, but meta-verbs change
changes. So undo u
and redo <c-r>
go back and forth in the change history,
as is common in most modern programs. But there’s more:
Let’s say you are writing a blog post. Well into the process you remember an
earlier phrasing that you changed, but now you want it back. You take numerous
steps back in history (perhaps employing a count: 25u
) until you find it. You
copy it, and you’re ready to continue. But before you remember that you should
redo to return to the newest version of the document, you make a new change.
If you used a simpler editor that version would now be lost forever.
Vim knows that undo/redo is not a linear history, it is a tree. Normal, sequential changes extend a single branch of the tree. But when you go back and make a new change as in the example above, that change sprouts another branch. Vim stores this tree and let’s you recover your work.
In this video, I demonstrate the undo tree with all changes being adding small
bits of text, and the layout of the text representing the branches of the tree.
Undo u
and redo <c-r>
always go up and down the current branch (in this
video literally up and down). The commands g-
and g+
go through older and
newer changes to the text, which can be spread around the tree. I go
backwards with g-
(watch for the ‘g’ in the lower right corner) through the
events of entering “six” and “five” to the state after entering “four”, which
is in the original branch, before undoing “three” and “four”. Using g+
brings
me forward again to the changes in the new branch.
Because all changes are ordered chronologically (no matter the undos and redos
done between them and the sprouting of new branches), they can be accessed
in a linear history with g-
and g+
. You can even travel in time explicitly:
:earlier 3m
(minutes), :later 2h
(hours). But in practice all you might
need is a few g-
es once in a blue moon.
On top of that we have persistent undo between sessions, which I think makes Vim’s undo the most powerful undo functionality I have seen in a program. If you know of any contenders, please leave a comment!
Vim itself never actually shows you the tree directly, but Steve Losh’s graphical undo a.k.a. Gundo plugin looks nice for that purpose (screencast here).
Now you have seen two powerful features that are in Vim but not vi: visual mode and the undo system. Here’s one more before we end:
Record and Replay Changes
Another meta-verb is record q
— it doesn’t change the text by itself, but
it records the use of other verbs. The recording can then be played back by
(regular verb) execute @
to use the same changes in a new context.
The xkcd forums user EvanED once demonstrated how he used emacs to efficiently
1 2 3 4 5 6 7 8 9 |
|
I defended the honor of Vim with this salvo:
1 2 3 4 5 6 7 8 9 10 11 |
|
Here I will do the same using visual mode so you can better see what’s going on:
He and I parted ways amicably! As he said
vi does seem faster in the hands of someone who’s skilled. But it also seems that emacs is faster in the hands of someone who isn’t particularly skilled
And that’s probably true!