A powerful VIM command I never knew about until now.

Being a long-time "vi" user I find that I am constantly surprised by the little (and not-so-little) enhancements vim has added. One of them is the "inner" concept.

Any vi user knows that "c" starts a c change and the next keystroke determines what will be changed. "cw" changes from where the cursor is until the end of the word. For example, "c$" chances from where the cursor is to the end of the line. Think of a cursor movement command, type it after "c" and you are pretty sure that you will change from where the cursor is to.... wherever you've directed.

"d" works the same way. "dw" deletes word. "d$" deletes to the end of the line. "d^" deletes to the beginning of the line ("^"? "$"? gosh, whoever invented this stuff must have known a lot about regular expressions).

VIM adds the concept of "inner text". Text is structured. We put things in quotes, in parenthesis, between mustaches (that's "{" and "}") and so on. The text between those two things are the "inner text".

So suppose we have:

<span style="clean">Interesting quote here.</span>

but we want to change the style from "clean" to "unruly". Move the cursor anywhere between the quotes and type ci then a quote (read that as "change inner quote"). VIM will seek out the opening and closing quotes that surround the cursor and the next stuff you type will replace it.

It works for all three kinds of quotes (single, double, and backtick), it works for all the various braces: ( { and <. You can type the opening or the closing brace, they both do the same thing.

Therefore you can move the cursor to the word "style" in the above example and type "ci<" to change everything within that tag.

I find this particularly useful when editing python code. I'm often using ci' to change a single quoted string.

If there is an "inner", you'd expect there is an "outer" too, right? (How many of you tried typing co" to see if it worked?) Well, there is an there isn't.

In VIM the opposite of "inner" is "block". A block is kind of special. It don't just include the opening and closing elements plus sometimes a the space or two that follow. Given this text:

  • The quick <span class="foo">>brown</span> fox.

If the cursor is in the <span> element, "cb<" will replace the entire element from the < all the way to the >. The whitespace after the element is also replaced for text-related things like change word (caw) and change sentence (cas).

Not having to move the cursor to the beginning of an element to change the entire thing is a great time saver. It is these little enhancements that makes using VIM so much more pleasant that using VI.

Give it a try!

More information about this is in the "Text Objects" section of Michael Jakl's excellent VIM tutorial.


P.S. My second favorite thing about VIM? gVIM (The graphical version of VIM) preserves TABs when you use the windowing system to cut and paste.

Posted by Tom Limoncelli in Technical Tips

No TrackBacks

TrackBack URL: http://everythingsysadmin.com/cgi-bin/mt-tb.cgi/1172

7 Comments | Leave a comment

Great post and in my case serendipitous! I was just wondering the other day if there is a better way to do this:

I do: s/"xyz abc"/"123 456"/ in [g]vim by positioning cursor on the 'x' and then typing 'cf"'. That would need me to retype/readd the closing quote. Not a big deal of course, but nice to know there's a proper way to do this.

And if I understand this right, it will even work multi-line? If so, this is quite useful.

ravi: to avoid retyping/readding the quote, use 'ct"' (works in plain vi as well). The 't' movement stops just before where 'f' would stop (t == till). In fact, if you are already between the quotes, the following plain vi command changes the inside: 'T"ct"' (move to the position behind the previous quote, change till (but not up to) the next quote).

My understanding is that the "b" in cb< is a standard motion and means "back", not "block" - in other words, it'll delete from the cursor back to the beginning of the word and put you in insert mode.

In your example, if you want to replace the contents of the entire <span> (including the <> characters), you can do ca< ("change around <")

The correct command that does the "inner block" selection is i, not b, hence the correct command would be 'ci"' or 'ci<'. The full documentation about this feature would be at :help text-objects. Note that not all characters work as block delimiters, so for deleting between the previous and next 'a', one would need to do 'Tacta'.

As a sysadmin I find I use very often the 'ap' text object ("a paragraph") since config files tend to be clumped together in logical paragraphs - works great for Nagios, for instance.

Vim is full of such gems and I strongly recommend people to reread the vim docs once in a while to discover new timesaving tools.

ca' changes the quotes as well, not only inside the quotes.

cit changes inside a xml-tag

also you can check the record and play command in VI editor by following the below link

The beautiful thing is that ci is actually even better than described here. At least when it comes to ' and " you don't actually have to position the cursor within the section, start of the line works as well!

Leave a comment

  • Don't Miss Out - Register Today