Using Tabs in Vim
When programming it is usual to have lots of files open and ready for viewing and/or editing. With C code this was header and source files, in PHP it is often a single file for each class used. Each language and project has their own system for splitting code across files, but once the complexity gets big enough they all do it.
Since the early days Vim has had buffers to handle multiple files at once. They did the job, and as with everything in Vim, they where efficient to use once the first hurdles where passed. In this day and ago it isn’t enough though. Everything else has support for tabs, so Vim implemented tabs as well in the latest release.
The biggest problem for me when using buffers was that I had to execute an ex-command (:ls) to view which files where opened. After working with a set of buffers for an extended period of time I would learn which numbers they where assigned so I could navigate between them fast, but it always felt like there should be a better option for it. With tabs Vim gave me the other option that I had been looking for.
Using tabs in Vim is very easy. The command for open a new file in a tab is :tabe <file name>. If the <file name> is left out you’ll open a tab with an empty and nameless file. Navigation between the tabs can be done using ex-commands:
- :tabn
- go to the next tab
- :tabp
- go to the previous tab
- :tabr
- go to the first tab
- :tabl
- go to the last tab
But if you’re switching between tabs frequently it is a bit tedious to have to resort to ex-commands. Instead the short cuts gt and gT exists, for respectively the next and previous tab.
As the short cuts go to the next/previous tab it is beneficial to move the tabs around so the related tabs are close to each other. This is done using the :tabm <n> command. That command will move the current tab to the position after tab <n>, e.g if the first tab is selected (as in the image bellow) and you type :tabm 3 your current tab will become tab number 3.

- Figure 1: The default styling of tabs in Vim
The image above shows the default layout of the tabs in Vim. As you can see the path leading up to the file names are shortened to only the first letter in each directory. This takes up a lot of extra space and it is pretty useless information. But since we’re dealing with Vim here, it can of course be customized!
The information displayed is governed by the guitablabel setting. This setting can either be set to an ordinary string with some predefined variables (file name, modified state, etc), or you can assign it a function which gives you even more options of what information to display.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 | function! GuiTabLabel() " add the tab number let label = '['.tabpagenr() " modified since the last save? let buflist = tabpagebuflist(v:lnum) for bufnr in buflist if getbufvar(bufnr, '&modified') let label .= '*' break endif endfor " count number of open windows in the tab let wincount = tabpagewinnr(v:lnum, '$') if wincount > 1 let label .= ', '.wincount endif let label .= '] ' " add the file name without path information let n = bufname(buflist[tabpagewinnr(v:lnum) - 1]) let label .= fnamemodify(n, ':t') return label endfunction set guitablabel=%{GuiTabLabel()} |
Above is the part of my .vimrc that decide how my tabs look. The last line set the guitablabel option to retrieve its’ value from the previously defined function GuiTabLabel, which is defined on lines 1 through 26. In the function the first line (3) retrieves the tab number. The second block of code (line 6 to 12) checks to see if any file in the tab has been modified, and prinst a * in the tab if it found a change. Continuing on, the next block (line 15 to 19) checks if more than one window is open in the tab, and prints the number of windows if required. The last block of code (line 22 to 23) adds the file name to the label. As this is an entry about tabs, and not function writing in Vim, I won’t go into the finer details of how the function works. Those details will be explained in a future blog post.
The result of the above is tabs that display the file name, tab number (for easy navigation), modified state and information about how many windows are open in each tab. An example can be seen bellow.

- Figure 1: The customized tabs
A lot of these things can also be accomplished with the use of buffers, but for me the use of tabs feel better. Hopefully I’m not the only one, and some of you’ll find this little introduction to them useful as a starting point for exploring their place in text editing in Vim.
Daniel Said,
August 20, 2008 @ 10:40
For me, the best thing to handle a lot of buffers is using the
bufexplorer plugin (http://vim.sourceforge.net/scripts/script.php?script_id=42),
and have the buffers sorted by ‘most recently used’.
Sushant Said,
August 20, 2008 @ 11:19
Perhaps we can map regular keys like Ctrl- to tabn or tabp so that things are consitent (with tabbed intefaces)
Sushant Said,
August 20, 2008 @ 11:19
I meant Ctrl-TAB
Peter Odding Said,
August 20, 2008 @ 12:58
Control-PageUp and Control-PageDown switch to the previous/next tab page in Vim. I’ve added the following mappings to my vimrc so that the shifted variants drag tab pages around (I don’t like the :tabmove command):
” Control-Shift-PageUp drags the active tab page to the left (wraps around)
imap :call DragLeft()
nmap :call DragLeft()
function! s:DragLeft()
let n = tabpagenr()
execute ‘tabmove’ (n == 1 ? ” : n – 2)
” force a redraw of the tab line
let &showtabline = &showtabline
endfunction
” Control-Shift-PageDown drags the active tab page to the right (wraps around)
imap :call DragRight()
nmap :call DragRight()
function! s:DragRight()
let n = tabpagenr()
execute ‘tabmove’ (n == tabpagenr(’$') ? 0 : n)
” force a redraw of the tab line
let &showtabline = &showtabline
endfunction
I hope the blog software doesn’t eat any characters — there’s no preview of comments…
Peter Odding Said,
August 20, 2008 @ 13:02
Oh crap, just like I suspected :-). I’ve published my vimrc online at http://xolox.ath.cx/vim/vimrc so if you want those mappings just follow that link and search for ‘DragLeft’.
web design company Said,
August 20, 2008 @ 18:53
Using tabs in Vim: don’t do it motherfucker, use spaces dammnit! `:set et` Oh, not those tabs…
Michael Plikk Said,
August 20, 2008 @ 23:20
@Daniel: Thanks a lot for the script-tip! I’ll have to give that one a try later on to see if I can get some more use out of those buffers.
@Sushant: That is another option, though I’ve gotten used to using the standard Vim short cuts now. To do that you would add the following to your .vimrc file:
And to make it work from insert mode:
@Peter Odding: Thanks a lot for that tip, and for linking our .vimrc file! Having an easy way to move the tabs a short distance is definitely a good thing. Those two short cuts are making their way into my own configuration right now.
I’m sorry that the the blog software ate parts of your first response. I’ll start looking into a good preview plug-in, so hopefully that will soon be solved!
@web design company: There are many kinds of tabs – some are good and some are evil ;)
Arnar Birgisson Said,
August 21, 2008 @ 19:45
Thanks for this. There seems to be a small problem with line 15 though,
let wincount = tabpagewinnr(v:lnum, ‘$’)margin: 0 auto
I removed the “margin: 0 auto” part – dunno if it was meant to be somewhere else.
Michael Plikk Said,
August 23, 2008 @ 15:07
@arnar: oh, sorry about that. I was editing the css files of this page at the same time I was posting, so the
'margin: 0 auto'must have slipped in from that. The post has been updated now. Glad you found the other parts useful!Marek Said,
June 10, 2009 @ 19:38
Hi,
How did you customize your Vim GUI? (the icons, separators, shading, etc..) It looks beautiful!
Vui Said,
December 13, 2009 @ 20:35
Hi, I’m wondering if there’s away to display the tab page total in the statusline?
Thanks
Srijith Said,
January 24, 2010 @ 11:23
Hi, I have created a blog entry explaining the tab feature in vim and how to use it. Check it out.. http://blog.sriunplugged.com/vi/tab-feature-in-vim/