Vim Tip #13: Movement for Programmers


tags: Vim

Vim Tips

In "Vim Tip #9: More Basic Movement" I covered moving around a text document by words, sentences, and paragraphs. Vim is also equipped to move around quickly in programs.

Line Numbers

Before we get to movement, let's set up an easy way to turn line numbering on and off. Vim's default way of doing this is for you to issue (in Normal Mode) the command :set number. This is a bit cumbersome. So let's utilize mappings (read it: what I'm about to suggest won't work if you copy verbatim, you need to do a bit of setup and understand first). In your configuration file, add this command: nnoremap <leader>n :setlocal invnumber<cr>. My leader is mapped to "-" (this works well for Dvorak users but is pretty lousy for most people: the semicolon is the Scholes equivalent), so now -n toggles the display of line numbers for the current file only.

You can jump to a particular line number by at least a couple methods: I learned to type :30 in Normal Mode to go to line 30, but the more commonly advertised method is 30G (upper case "G"). Both work.

Re-indenting a File

A commonly asked question is "how do I re-indent the whole file?" I've concluded that this is a much better question to ask about Java or C than it is about HTML ... and it's a flat-out bad question for Python. (I'm getting too philosophical here, but you need to think about this before you re-indent the wrong file.) Java and C (and a lot of other languages) delimit statements with braces and parentheses, so Vim can tell how a file should be indented and it usually works fine. With HTML ... well, Vim can tell - but I really don't like what it does so I avoid using this functionality in HTML (try it yourself and make your own decision). And in Python ... don't even ask the question. If you're a Python programmer asking that question, I'm worried for you. Python REQUIRES block indentation: loops and if/then and many other constructs are dependent on it. And since indentation is required to determine blocks, braces and parentheses aren't used at all (at least not to delineate code blocks). So Vim has no indicators and can't re-indent files. It'll still try, and it'll be ugly. DON'T DO THIS IF YOU USE PYTHON.

So the answer: gg=G. gg goes to the beginning of the file, and =G does the re-indentation. Remember that u is undo.

Indenting a Block

If you prefer to indent and outdent code blocks by hand (particularly recommended for Python, but useful in many contexts), use a line number range and the ">" or "<" characters. To indent lines 5 to 10 the command is :5,10> and Enter. To outdent a block by two steps, use :5,10<<.

How far the block is indented is controlled by your shiftwidth setting if it's set or tabstop if it's not - the default behaviour should work for you, but investigate these if it doesn't.

Keywords and Matching Braces

Search forward for the keyword under your cursor: *. Search backward for the keyword under the cursor: #. In either case, the keyword becomes your current search, so you can then use n to continue searching for the next occurrence, or N to search in the opposite direction.

If your cursor is on a brace or parentheses, press % to go to the matching item.

Searching Associated Files for Functions

If you have a program that extends across several files, the above tip may seem less useful than you'd hoped. But don't worry: with a little more work, you can jump to a method/function definition in another file. First, install Exuberant Ctags.

(Digression: on most versions of Linux the only versions of ctags available are "exuberant," but on Mac you'll want to do brew install ctags-exuberant because OS X supplies a horrible old version of plain ctags that supports only one or two languages while the "exuberant" version supports dozens of languages and is better maintained.)

Once it's installed, you want to run either ctags * (if everything is in one folder) or ctags -R if there are subfolders containing code. (man ctags wouldn't be a bad idea ...) This generates a file called "tags" that editors can use to find where methods are defined. This would be a good time if you're a git user to add "tags" to your .gitignore. With the tags generated, Vim can jump to method definitions under the cursor across files on the command g]. This is probably a good time to point out Ctrl-o to move back in the buffer list - that is, if you jumped to another file by jumping to a definition, Ctrl-o takes you back to the previous file. And Ctrl-i will take you forward again.

As you make changes to your programs, you'll occasionally need to update your tags file by re-running ctags * or ctags -R.

Replacing a Block

This is a Vim behaviour I use most in HTML. Let's start with "change inner tag," Vim command cit - if done anywhere on or in an HTML tag will empty the tag and put you in Insert Mode. With small changes, you can do much, much more. dit is "delete inner tag" - the tag is emptied, but you don't go into Insert Mode. Or yi( which is "yank inner parentheses." Those contents can now be pasted elsewhere. Also works on braces ("{}"), angle brackets ("<>"), quotes ... Experiment: it's incredibly useful.