Skip to content

How to override a colorscheme?

Romain Lafourcade edited this page Jun 8, 2022 · 3 revisions

TL;DR

To override some of the colors of an existing colorscheme, for example desert, put the following into your vimrc:

augroup desert_override
    autocmd!
    " I like green statements
    autocmd ColorScheme desert hi Statement guifg=#5FD75F ctermfg=green
    " I like transparent background for terminals
    autocmd ColorScheme desert hi Normal ctermbg=NONE
    " I like italic comments
    autocmd ColorScheme desert hi Comment cterm=italic gui=italic
    " etc ...
augroup END
colorscheme desert

Highlighting

Vim's screen is entirely made of text. Some of that text constitutes the chrome of the editor and the rest is dedicated to displaying the syntax highlighted content of files edited in the editor.

In order to style all those items, Vim uses something called "highlight groups", kind of like tags applied to some specific pieces of text. The whole mechanism is made of two parts: the part responsible for applying specific highlight groups to specific pieces of text and the part responsible for determining how those highlight groups look. The latter is the part we are focusing on in this guide.

The job of a highlight group is to determine how a given item will look in a given environment. In the somewhat maximalist example below:

highlight Visual guifg=#87afd7 guibg=#262626 gui=reverse ctermfg=110 ctermbg=235 cterm=reverse term=reverse
  • Visual is the name of the highlight group,
  • guifg is the foreground color in GUI Vim,
  • guibg is the background color in GUI Vim,
  • gui is a comma-separated list of typographic attributes in GUI Vim,
  • ctermfg is the foreground color in color terminals,
  • ctermbg is the background color in color terminals,
  • cterm is the typographic attributes in color terminals,
  • term is the typographic attributes in monochrome terminals.

See :help highlight-gui, :help highlight-ctermfg, and :help highlight-term.

But highlight groups don't have to be so extensive. The following line would be just as valid, if less portable:

highlight Visual gui=reverse

And, sometimes, all you want is for a given highlight group to look like another:

highlight link Terminal Normal

See :help :highlight-link.

Colorschemes like desert, distributed with Vim, or lucius, available as a third-party plugin are essentially a way to put together a bunch of highlight commands like the ones above into a convenient package. If you want to override some highlight groups, you will have to write your own highlight commands.

My editor, my style

Whether your favorite colorscheme came with Vim or not, you might find yourself in a situation where you would like to alter the style of some highlight groups… but without going through the trouble of editing the original colorscheme or creating your own. This is a two-steps process: identify the highlight groups you want to override, then override them.

Identifying highlight groups

As mentioned above, highlight groups can be applied to Vim's chrome or to syntax items, but, as they are handled by two separate mechanisms, we can't inspect them the same way. We will deal with syntax items first, and then with chrome items.

Syntax items

Vim provides a bunch of functions that can be used to identify highlight groups but they are a tad too low-level for everyday use. Here is a convenient higher-level wrapper:

command! Inspect echo map(synstack(line('.'), col('.')), 'synIDattr(v:val, "name")')

To use it…

  1. put the line above in your vimrc, write the file and quit Vim with :wq, and start Vim again,
  2. position the cursor on the piece of text you want to inspect,
  3. do :Inspect<CR>.

You should see a list of highlight groups being printed in the command-line:

['vimAugroup', 'vimAutoEventList', 'vimAutoEvent']

As mentioned above, highlight groups can be, and usually are, linked to other highlight groups. This helps keep colorschemes manageable by reducing the amount of highlight groups to style explicitly while also creating a bit of indirection. In the example above, you could choose to override vimAutoEvent but that would only work for the vim syntax and you would have to engage in a gigantic game of whack-a-mole to override other highlight groups with similar semantics. Follow along to find out how to narrow down your search.

In some cases, you might get an empty list:

[]

which means that there is no highlight group applied to the character under the cursor. Vim falls back to the Normal highlight group in those cases so you should be targeting Normal.

Chrome items

Chrome items can't be inspected interactively but they are all documented under :help highlight-groups. All you have to do is search for the one you want in that section. If you think you have found the right one, the next section tells you how to inspect a highlight group.

Finding the one

You should further inspect any highlight group you may have found earlier with:

:hi NameOfHighlightGroup

which might print a few different things:

vimAugroup      xxx cleared                             " case 1: this highlight group has no style attribute and no link
vimAutoEvent    xxx links to Type                       " case 2: this highlight group is linked to another one
Type            xxx term=bold ctermfg=14 guifg=#ffdf00  " case 3: this highlight group is defined explicitly

Syntax-level highlight groups are expected to be linked to a small number of generic highlight groups so it is rare to see the 3rd case on first try, but the 1st and second cases are pretty common. What to do next depends on the current case:

  • Case 1, write down the name somewhere for the second step of the process.
  • Case 2, repeat the process with BazQuux, and again until you get to either case 1 or case 3.
  • Case 3, write down the name somewhere for the second step of the process.

At that point, you should have identified the desired highlight group.

Overriding highlight groups

Now that you have identified the highlight group you want to override it is time to figure out how to apply that override at runtime.

Two principles first:

  • the override has to be applied after the colorscheme is sourced,
  • the override has to be applied every time the colorscheme is sourced.

Satisfying the first principle is easy enough, you put your own highlight commands after the colorscheme command in your vimrc:

colorscheme desert
" I like green statements
hi Statement guifg=#5FD75F ctermfg=green
" I like transparent background for terminals
hi Normal ctermbg=NONE
" I like italic comments
hi Comment cterm=italic gui=italic

But what if you try a new colorscheme, and go back with :colorscheme desert? Well, your override is lost. To satisfy the second principle, you can use a neat feature: when Vim sources a colorscheme, it emits the ColorScheme event with the name of the new colorscheme as value. From there, it is easy to craft an autocommand that will apply the override every time the colorscheme is sourced:

augroup desert_override
    autocmd!
    autocmd ColorScheme desert hi Statement guifg=#5FD75F ctermfg=green
    autocmd ColorScheme desert hi Normal ctermbg=NONE
    autocmd ColorScheme desert hi Comment cterm=italic gui=italic
augroup END

Of course, this has to be put before any colorscheme line to take effect:

augroup desert_override
    autocmd!
    autocmd ColorScheme desert hi Statement guifg=#5FD75F ctermfg=green
    autocmd ColorScheme desert hi Normal ctermbg=NONE
    autocmd ColorScheme desert hi Comment cterm=italic gui=italic
augroup END
colorscheme desert

And you can even use a wildcard to have your style override every colorscheme:

augroup highlight_override
    autocmd!
    autocmd ColorScheme * hi Statement guifg=#5FD75F ctermfg=green
    autocmd ColorScheme * hi Normal ctermbg=NONE
    autocmd ColorScheme * hi Comment cterm=italic gui=italic
augroup END
colorscheme desert

Reference

For all things concerning autocommands, see :help autocommands. For all things concerning syntax highlighting, see :help syntax.

You can see all the groups currently active with the following command: :runtime syntax/hitest.vim, see :help hitest.vim.