Vim Color Schemes

One of the joys of [Neo]Vim is the amount of color schemes available. The editor ships with several colorschemes by default, but adding more is what Vim was made to do!

Before we begin, know that Vim, NeoVim, and the various terminals they work with can be finicky with colors. On Windows, I'm using neovim-qt. On Mac, I'm using MacVim or iTerm2 with NeoVim. On Linux I'm using LXTerminal on Ubuntu 16.04 with NeoVim. The following notes with my setup.

There are a couple of notes to keep in mind when using colorschemes:

  • Some terminals do not support some colors. A nice overview of this can be found in one of my favorite colorscheme's documentation
  • Sometimes (on Windows/Mac, but oddly not on my Linux) termguicolors should be set. See :help termguicolors for more information
  • Your background can be light or dark and many colorschemes will adjust. I universally prefer a dark terminal so I always set background=dark to inform Vim about my dark background.

Because I work on several servers/VMs that don't have NeoVim or vim-plug installed, or all the features I prefer on my main development machines, I have to be careful to avoid or handle any missing features or errors that might arise. I need to be able to scp my vim initialization file to a machine and just use it. With this in mind, the main thrusts of this post are to document how I use features when available but gracefully fall back to good defaults, my favorite colorscheme plugins, and how to change the colorscheme for new Vim instances from the command line.

Diverse Features, One Configuration

The first trick I use to (borrowed from somewhere on StackOverflow) is to use a try/catch block to set a default colorscheme if my plugin colorscheme isn't able to be loaded:

" Try to use a colorscheme plugin
" but fallback to a default one
try
    colorscheme gruvbox
catch /^Vim\%((\a\+)\)\=:E185/
    " no plugins available
    colorscheme elflord
endtry

Likewise, termguicolors can be detected using an if block:

" Linux has termguicolors but it ruins the colors...
if has('termguicolors') && (has('mac') || has('win32'))
    set termguicolors
endif

I'm sure if I put some more work into it, I could change LXTerminal's settings to work with Vim, but... I haven't.

Colorscheme Plugins!

I used the builtin elflord colorscheme for quite a while, and I still do occasionally, but here are some colorscheme plugins I really like:

I've also come across a few plugins that add many colorschemes at once!

That last NeoVim specific plugin can be wrapped in an if block:

if has('nvim')
    Plug 'Soares/base16.nvim'
endif

Tons of colorschemes are now available, so having a plugin that can quickly switch between them is practically necessary. I use vim-colorscheme-switcher. With this gem of a plugin, the F8 key switches to the next colorscheme available and the :RandomColorScheme command becomes available. Unfortunately, Vim wasn't designed to cleanly switch colorschemes, so sometimes they won't load properly. This section of the README explains further.

Colorschemes before startup (untested on Windows)

With this menagerie of colorschemes, editing an initialization file each time a color scheme deserves to be changed can become annoying. I used to have a long list of commented-out colorscheme lines in my init.vim, but recently I've found a way to mitigate the problem- setting the colorscheme from the terminal.

The "hook" between the terminal and Vim can be created using environmental variables- set an environmental variable in the terminal, and read it in Vim on startup to do things. I prefix all such environmental variables with vim_, so vim_colorscheme is the variable I chose. I use the try/catch block described earlier to catch and handle errors.

" Try to use a colorscheme plugin
" but fallback to a default one
try
    " get the colorscheme from the environment if it's there
    if !empty($vim_colorscheme)
        colorscheme $vim_colorscheme
    else
        colorscheme gruvbox
    endif
catch /^Vim\%((\a\+)\)\=:E185/
    " no plugins available
    colorscheme elflord
endtry
set background=dark

Now in BASH/ZSH I can define a function to easily set a colorscheme:

set_vim_colorscheme()
{
    export vim_colorscheme="$1"
}

I don't have an encyclopedic knowledge of the colorschemes I want, so I also define a completion function with the colorschemes I like (drop this in ~/.bashrc or ~/.zshrc)

# make zsh emulate bash if necessary
if [[ -n "$ZSH_VERSION" ]]; then
    autoload bashcompinit
    bashcompinit
fi

# make the autocompletions
# https://www.gnu.org/software/bash/manual/html_node/Programmable-Completion-Builtins.html
_vim_colorschemes='abbott elflord gruvbox desert-warm-256 elflord railscasts dracula 0x7A69_dark desertedocean'
complete -W "${_vim_colorschemes}" 'set_vim_colorscheme'

After sourcing these functions, I can use set_vim_colorscheme <TAB> to get a nice list of colorschemes. One note: when I use tab completion to auto-complete the command set_vim_colorscheme itself, I have to type SPACE before TAB to convince BASH that the colorscheme is ready for completion.

With graceful feature usage, many colorschemes, and the ability to switch them easily from inside Vim and outside Vim, my sense of style is satisfied and my ability to procrastinate is enhanced.

I keep my Vim/NeoVim configurations on GitHub.

This blog post is now on Reddit!