Tabbed editing in Vim

Tabs in Vim are conceptually very similar to tabs in a browser. Each one represents its own little world. In graphical clients you can click on the tab to switch to it. In the terminal you’ll have to learn a few easy commands. Fortunately these also work in Graphical clients so you will never need to reach for your mouse if you don’t want to.

Like a browser you can have the same page/file in the multiple tabs. Unlike a browser editing it in one edits it in all of them. This is because the tab is just a window displaying a buffer. Just like a house. There may be multiple windows looking at the same thing and the changes you can see through one window are visible to every window looking at the same thing.

My personal opinion is that tabs are great in the visual clients, acceptable in the terminal when you only have a few files open, and frustrating when you’ve got too many to display.

Displaying tabs

In a graphical client, tabs look like you’d expect. They work like you’d expect. The same key combo you use to create a new tab in a browser should work in your graphical Vim client. I’m not going to spend any time discussing them or their configuration because there’s not much to discuss. Navigation works the same in GUI and terminal clients, except you can, of course, use your mouse in the GUI.

Tabs in GUI vim

Here’s what tabs look like in the terminal with no plugins and the default styling. Note that in the first and second tab the path has been shortened to only show the 1st letter of the 2 directories above the file: c/p/<filename>. In the 3rd tab the file name was so long that there’s no indication of folder and the 1st letter of the file name was removed.

Tabs in terminal with default styling

To style them you’ll want to configure TabLine, TabLineSel, and TabLineFill. You can find a list of the approximate color names associated with each number here, along with their hex and rgb values.

Here’s what mine looks like after tweaking those to match my Airline theme at the bottom.

Tabs in terminal with custom colors

" an inactive tab
hi TabLine      ctermfg=255 ctermbg=238     cterm=NONE
" the selected tab
hi TabLineSel   ctermfg=17  ctermbg=190  cterm=NONE
" the unused portion of the tab line (not enough tabs)
hi TabLineFill  ctermfg=255  ctermbg=238     cterm=NONE

Plugins

As with many things in Vim, plugins make life better. I’m currently using a fork of tabline.vim and the results look like this.

Tabs in terminal with the tabline plugin

There’s one huge advantage to this plugin (and many others) over the default. The numbers. The plugin itself is relatively simple and there are a bunch of forks with subtle tweaks to what is displayed, like including square brackets or not.

To me though, the numbers are critical, and you’ll see why when we get to navigating tabs.

Airline has a typically stylish approach to this, but as we’ll see later, it has problems when you’ve got too many tabs to fit in the window.

Tabs in the terminal with the airline plugin

Using Tabs

Before I jump into actual commands I need to note that in addition to what I’m covering here, you can find a lot more under :help tab-page

Opening files in tabs

tabedit and / or tabfind are the commands you need if you’re already in vim.

:tabedit path/to/file.md
" or 
:tabfind file.md

tabfind will search throug the current project’s directories to find a file that matches the name supplied. What’s particularly cool is that it supports tab completion. For example: I wanted to open “emergency_vim_quickstart.md” which lived 2 down in the project. I typed :tabf emer<tab> and it found it, autocompleted the name, and then waited for me to hit enter to open it, or hit tab again for the next match.

With tabedit I would have had to type this before I could start tabbing through matches.

:tabedit content/post/e

Of course, like :edit I could use tab completion along the way:

:tabedit cont<tab>p<tab>e<tab>

You can add a number before tabedit and tabfind to specify where in the list the new tab should appear. So :2tabf buffers.md will open buffers.md after the second tab, making it tab #3 and making me wonder why Vim didn’t make it tab 2 since that’s what I typed.

If you want to boot vim with multiple files each in their own tab, you’ll use the -p option.

$ vim -p file_one.md file_two.md file_three.md

Within Vim there’s another interesting option that I’ll mention just so you know it exists when you eventually find a need for it. If your file contains the path to another file you can highlight it with a visual selection and then say

<CTRL>-w gf

Closing tabs

I usually close them just like anything else: :q

There are other commands that let you do this, but I’ve only got so much mental bandwidth and that works. See :help tabclose if you want to learn them.

To go Type This Which means
left one tabp tab previous
right one tabn tab next
to the 1st tab tabr tab rewind
to the last tab tabl tab last
to the 3rd tab tabn3 “next” got reused as a keyword

See :help tabn for more ways to jump between tabs.

For Mac Vim I’ve added the following to my ~/.vimrc. This allows me to type Command+4 to jump to tab #4.

" it's important to limit these to the GUI client
if has('gui_running')
	" Go left with Control+Tab
	noremap <C-Tab> :tabnext<CR>
	" Go right with Control+Shift+Tab
	noremap <C-S-Tab> :tabprev<CR>

	" Switch to specific tab numbers with Command+Number
	noremap <D-1> :tabn 1<CR>
	noremap <D-2> :tabn 2<CR>
	noremap <D-3> :tabn 3<CR>
	noremap <D-4> :tabn 4<CR>
	noremap <D-5> :tabn 5<CR>
	noremap <D-6> :tabn 6<CR>
	noremap <D-7> :tabn 7<CR>
	noremap <D-8> :tabn 8<CR>
	noremap <D-9> :tabn 9<CR>
	" Command-0 goes to the last tab
	noremap <D-0> :tablast<CR>
endif

Troubleshooting

Too Many Tabs

Sooner or later you’ll load up more tabs than can fit in the window. In GUI clients like MacVim, getting to the unused tabs is pretty simple. Just click on the chevron (or similar) at the end of the tab line.

hidden tabs chevron

In the terminal it’s not so easy. In this screenshot the #1 tab is not shown. I then navigated to it with :tabn 1 and now the < on the left is highlighted, but the “tab” for my “markdown.md” file never reappeared even after I told Vim to switch to that file.

too many tabs in terminal

As far as I can tell there is no way to make the built-in tabline functionality always show you the current tab. If you know how, please let me know so that I can update this post.

Airline does the best job of always displaying the name of the current tab. Once the list of buffers becomes too long to display on the screen the display changes like this:

airline's handling of too many tabs

The list of tabs becomes an elipsis (...) and the current tab is highlighted. It’s not perfect though. Sometimes the highlighted tab is on the right side, sometimes the left, and sometimes both.

airline's handling of too many tabs