Make your own vim bar

Fri, Feb 19 15:39


The vim bar that I have been using up until now was vim airline. Don't get me wrong, it's a great bar that looks awesome, but I wanted a bar that used my terminal colors, for more consistent theming. I was also sorta in the mood for cutting down the number of plugins I was using, since chances are, vim already has that feature builtin. Finally, vim airline had a lot of information I didn't need or care about. I'm aware that it's very configurable, but it's better to start from less and add in features than start from bloat and cut down.

Anyways, I really only looked for a couple things in my bar:

The first thing we need to do is actually enable the vim bar. You can do so by adding this line to your .vimrc:

set laststatus=2
set statusline=

You can alternatively use a value of 1, which only displays the status line if there are more than 2 windows. With this option, the bar acts more like a window separator. What we really want is a statusbar, so it should be on at all times (hence the 2 option). The second line clears whatever was in your statusline before, this isn't too required.

Basic Config

You could set your statusline all in one line, but that makes it quite unreadable, especially if it wraps multiple lines. What we can do instead is append sections using

set statusline+=[stuff]
set statusline+=[more stuff]
set statusline+=[even more stuff]

Vim gives you a couple nice variables to use, the full list can be found by running: :h statusline. Here's what a minimum statusbar might look like:

set statusline+=%f
set statusline+=\ %l/%L:%c

It's not much but it's a start. We are making use of those vim variables I mentioned earlier. Specifically, the first line tells us the file name, and the second line gives us information on line number and what column we are on. Also notice the backslash space on the second line, that simply inserts a literal space character, useful for separating blocks. Play around with the variables and get a basic layout that you like, here's what I came up with:

set statusline+=\ | 
set statusline+=\ vim\ \[%{mode()}\]
set statusline+=\ %{expand('%:~:.')}\ %m
set statusline+=%=
set statusline+=%y
set statusline+=\ %r\[%{v:register}\]
set statusline+=\ %l/%L:%c
set statusline+=\ |

A couple interesting things to point out, whenever you see %{} we are calling a vim function, these can be ones you write too, which you will see a bit later. Next, %= is pretty useful since it right justifies everything after it.

Colors

The white bar is getting a bit tiring, let's see how we can set colors. The easiest way is to use:

hi StatusLine cterm=None gui=None ctermfg=black ctermbg=Yellow

These colors will be based off your terminal's colors, you can find a full list as well as what they look like by running :runtime syntax/colortest.vim in command mode.

Alright cool, so we can set the bar color, but how do we set the color of individual sections of the bar? Well, we have other highlights to our disposal that we can set and reference from within our statusline, specifically:

hi User1 cterm=None gui=None ctermfg=White ctermbg=Black
hi User2 cterm=None gui=None ctermfg=Black ctermbg=LightBlue

And inside our statusline:

set statusline+=%1*\ |
set statusline+=%0*\ vim\ \[%{mode()}\]
set statusline+=\ %1*\ %{expand('%:~:.')}\ %m
set statusline+=%=
set statusline+=%y
set statusline+=\ %2*
set statusline+=\ %r\[%{v:register}\]
set statusline+=\ %l/%L:%c\ |
set statusline+=%1*\ |

Note how our use of %1* corresponds to User1 and similarly for the other user variables. From what I've seen, StatusLine corresponds to %0*.

Responsive Bar

With this we can make our bar change color depending on what mode we are in, here's a function to do it:

function! StatusModeColor()
    if (mode() =~# '\v(n|no)')
        hi StatusLine cterm=None gui=None ctermfg=black ctermbg=Yellow
    elseif (mode() =~# '\v(v|V)')
        hi StatusLine cterm=None gui=None ctermfg=black ctermbg=Red
    elseif (mode() ==# 'i')
        hi StatusLine cterm=None gui=None ctermfg=black ctermbg=LightBlue
    elseif (mode() ==# 'c') 
        hi StatusLine cterm=None gui=None ctermfg=black ctermbg=Green
    else
        hi StatusLine cterm=None gui=None ctermfg=black ctermbg=DarkGrey
    endif

    return ''
endfunction

and just add this line to the top of your statusbar:

set statusline+=%{StatusModeColor()}

This way, the function will get called on statusbar redraw. This may not be the most efficient, and you can perhaps call the function on a mode change hook or whatever. The mode names in each of the if statements is what is returned from mode(). You can find a more or less full list here.

And finally, I wanted some sort of indication if the buffer was modified or not, so here's another function to do that:

function! StatusModifiedColor()
    if getbufinfo(1)[0].changed
        hi User1 cterm=None gui=None ctermfg=Black ctermbg=Magenta
    else
        hi User1 cterm=None gui=None ctermfg=White ctermbg=Black
    endif

    return ''
endfunction

And again, add this to the top of your statusbar:

set statusline+=%{StatusModifiedColor()}

And that's about it, a brand new, plugin-less vim bar! My full vimrc can be found here if you are interested. So far, I haven't found the nicest way of displaying open buffers, since vim's builtin tabline displays open tabs, not buffers. Perhaps that will be a post for another day when I figure it out.

Additional Reading

There's a couple of great resources you should look into