Ted Logan

Secrets of tabs in vim

Thursday, 17 January 2008

I spend much of my day working on other people's code. People who have uncivilized ideas about how to indent their code. (Given some of the code I've seen, I sometimes think I should be simply pleased that they bothered to indent their code at all.) Until civilization aligns and we finally have elastic tabstops, I'll have to deal with different tab styles. The popular ones tend to be:

I've seen some especially ... creative tab styles not listed above, including code indented with various innovative mixture of tabs and spaces. Out of the box, my favorite text editor (vim and its gui cousin, gvim) will default to indent using eight-column tabs, but vim can handle any (consistent) indentation style I've seen using four easy commands: tabstop, shiftwidth, expandtab, and softtabstop. (Each command listed below has links to the vim documentation for more details.)

tabstop

Set tabstop to tell vim how many columns a tab counts for. Linux kernel code expects each tab to be eight columns wide. Visual Studio expects each tab to be four columns wide. This is the only command here that will affect how existing text displays.

expandtab

When expandtab is set, hitting Tab in insert mode will produce the appropriate number of spaces.

shiftwidth

Set shiftwidth to control how many columns text is indented with the reindent operations (<< and >>) and automatic C-style indentation.

softtabstop

Set softtabstop to control how many columns vim uses when you hit Tab in insert mode. If softtabstop is less than tabstop and expandtab is not set, vim will use a combination of tabs and spaces to make up the desired spacing. If softtabstop equals tabstop and expandtab is not set, vim will always use tabs. When expandtab is set, vim will always use the appropriate number of spaces.

Indentation in the real world

Putting it all together, the following incantations will configure vim for each of the cases listed above:

Just to prove it's possible, here are some more ... creative indentation styles and their vim representation:

... you get the idea.

Remembering these settings

So how do you make vim remember what indentation to use for all of your files? vim will read your personal startup file every time it runs; you can put your favorite indentation incantations there. (That's ~/.vimrc on Unix; $HOME/_vimrc on Windows. In gvim, you can click Edit -> Startup Settings to quickly edit this file.) On the opposite end of the spectrum, you can add special incantations to each file you edit, which will override the settings vim reads from elsewhere -- but see modeline because this is often disabled by default as a security feature:

/* vim: set tabstop=8 softtabstop=8 shiftwidth=8 noexpandtab : */

(Obviously, wrap the text in your favorite comments to make sure your compiler doesn't try to compile the vim incantations.)

vim will also read .vimrc in the current directory (when the exrc option is set in your normal vimrc), which is useful when editing large numbers of source files in the same directory, or to avoid corrupting source files you don't control.

Visualizing tabs

So what do you do when you open a new source file and you're trying to figure out what tab style the last author used? (And how do you make sure you're doing the Right Thing to avoid mixing tab styles in your new code intermixed with the old code?) I find syntax highlighting useful. In gvim, I like seeing my tabs with underlines. (This tends not to work well on the text terminal for reasons I haven't been able to determine.) The following incantation will tell vim to match tabs, underline them in gvim, and highlight them in blue in color terminals:

syntax match Tab /\t/
hi Tab gui=underline guifg=blue ctermbg=blue

You can't just throw this into your .vimrc and expect all to work, though, because vim will flush its syntax highlighting rules when it loads new files. To hijack this process, add syntax files for your favorite languages in $HOME/.vim/syntax/. For C, the syntax file is c.vim. (Look in $VIM/syntax for a list of existing files.) vim will load the system-wide syntax file and then run your custom file, and you'll be able to visualize your tabs every time you load a C file.