Technical, VIM,

Text-Objects!

This is one of those Vim posts that I promised I'd write, but just never ended up writing. Until today.

I'm going to talk about editing text using a combination of operators, text objects and motion commands. Most people using Vim probably already use these a fair bit, so it's probably not going to be very useful for them, but in case someone does want to read up, here it is without further ado!

Let's start out talking about how Vim edit commands are constructed:

A typical edit command can be broken down like this

[]([][/])

I'll explain each bit over the course of this blog post, but here's a super short summary:

  • repititions: Number of times you want to repeat the following edit instruction.
  • operator: These are the basic operations you can perform on text, such as copy, yank, delete.
    (See :h operator)
  • textobject: These are the basic units of text/code that Vim understands.
    (See :h text-objects)
  • motion: These are the basic movements to navigate text in Vim.
    (See :h {motion})

I'm not going to talk about motion commands much, and I'm not going to talk aboutrepetitions at all.

Instead let us focus on text-objects.

Text Objects

Text objects are the smallest or most basic constructs that Vim understands. Unlike other text editors, Vim is smart.

It understands quite a few natural language constructs, such as words, sentences, paragraphs. It also understands some programming language constructs, namely, blocks, strings, tags among others.

What this means is you can talk to your editor at a higher level of abstraction instead of simply communicating with it at the awkward and unnatural character level.

So you can now say:
"Hey Vim, can you copy this paragraph for me?"
Or
"This C function is bullcrap! Get rid of it!"

Vim will typically do things like for you in 3 keystrokes.

No more holding down the backspace to delete a line.
No more switching to visual mode, selecting your text/code and then copying/deleting it.
No more "I want to change the text I'm printing" and then holding down the delete key and then typing the new string all over.

But before we starting Operating on Text Objects, we need to learn to identify them.

A text object is of the form:

[/][some abstraction]

The prefix in some general selects the 'inside' of whatever abstraction follows after it. What 'inside' means varies for language constructs and programming constructs, but it makes sense on the whole, as we'll see in the examples.

The , or as I initially incorrectly called it the 'all', prefix is used to select an entire unit of the abstraction. What entire unit means again varies for language constructs and programming constructs, but hopefully the examples that follow will serve as a clarification and demonstration.

Now that that's cleared up, what are these abstractions that I've been harping on about? There's a ton of them, here follows a brief list of the ones I use commonly:

w   word
s sentence
p paragraph
" A quoted string. Pair of corresponding ".
Works for single quotes too. (Use ')
[ A [] block. Pair of corresponding [ ].
( A () block. Pair of corresponding ( ).
{ A {} block. Pair of corresponding { }.
t HTML/XML tags

There are other more powerful ones in there, but lets focus on these for now.

The best way to show you the power of these things it to literally show it to you.

So this is the basic text we start out with:

Base Text

Base Text


As some of you might recognise, it's a simple C program.

Now, this is the text we'll continuously modify and change in our examples.

Let's start out small and delete a word we don't need. In the sentence "This is not a setence I want not to write\n", we have double negatives tying the programs users in (k)nots.

To get rid of it, we navigate towards it, and then with a flash we do a daw (delete 'an' word) to remove the word. We immediately undo the change and then use diw (delete 'inner' word) . Is there a noticeable difference? Play close attention to what happens to the whitespace around the word after deletion in both cases. daw modifies surrounding whitespace, whereas diw does not touch the surrounding whitespace.

delete-'an'-word and delete-'inner'-word

delete-'an'-word and delete-'inner'-word


Not impressive you say? Okay.

How about we decide to get rid of the useless (int argc, char* argv[]) bit? We aren't really parsing CLI arguments, and have no need for it.

Three keystrokes, di( (delete 'inside' ( ), to wipe that bit clean. Neat eh?

delete-inside-(

delete-inside-(


Now how about you decide to re-write an entire crappily written C function? What do you do? You want to nuke it from orbit ofcourse. The only question is how do you do it?

Do you got into insert mode and hold down the space bar? Or maybe you hit dd multiple times to fix all this.

No need, ci{ (change 'inside' {) at your service.

change-inside-{

change-inside-{


This removes the old contents of your {} block, which happens to be a C function, and places the cursor in the next line at the correct indent level in insert mode, ready and waiting for you.

An interesting bit about text objects is that you can define your own. In other words you can teach Vim newer, shinier text-objects. You can also stand on the shoulders of other and use plugins like this.

Operators

Any Vim user probably uses a subset of the operators available in Vim on a close to daily basis. The fairly common ones are Yank, Delete, Change. These are probably by far the most useful as well.

Here's a complete list copied from Vim's help:

c   change
d delete
y yank into register (does not change the text)
~ swap case (only if 'tildeop' is set)
g~ swap case
gu make lowercase
gU make uppercase
! filter through an external program
= filter through 'equalprg' or C-indenting if empty
gq text formatting
g? ROT13 encoding
> shift right
< shift left
zf define a fold
g@ call function set with the 'operatorfunc' option

Operators are really handy because they let you think about editing as a set of higher level operations such as delete something or copy something instead of thinking about it terms of removing or deleting and re-typing a sequence of characters all over again.

Take-Away

Combine the various operators and text-objects in creative ways to make your own life easier. After a while using text-objects becomes second nature. This reduces the micro-interruptions while entering text or code. So you can now think about your higher level writing or code instead of thinking about all those extra key-presses you need to get there. Also less typing hurray!

Additional reading

  1. More in-depth treatment, still in blog form
    http://blog.carbonfive.com/2011/10/17/vim-text-objects-the-definitive-guide/
  2. Vim Documentation, Text Objects
    http://vimdoc.sourceforge.net/htmldoc/motion.html#text-objects
  3. Vim Documentation, Operators
    http://vimdoc.sourceforge.net/htmldoc/motion.html#operator
  4. Vim Documentation, Motion
    http://vimdoc.sourceforge.net/htmldoc/motion.html