How to add additional syntax highlighting in vim without sudo

Viewed 32

When vim is used to write python codes, some keywords in the comments are highlighting with different colors. And the keywords can be found in /usr/share/vim/vim80/syntax/python.vim, where there is a line:

syn keyword pythonTodo      FIXME NOTE NOTES TODO XXX contained

so the words FIXME, NOTE, NOTES, TODO, XXX in the comments will be highlighted.

Now I want to add more words in it, such as adding DEBUG, WARNING but I don't have sudo so I can not directly edit this file. Is there anyway to solve it? What if I want to specify the color for different words? For example, red for DEBUG, yellow for WARNING.

1 Answers

Syntax highlighting is a two-steps process where each step is handled by separate scripts.

  1. The syntax script is in charge of making sense of the syntax of the language: what constitutes a keyword, what constitutes a constant, etc.
  2. The color scheme is in charge of defining how those keywords, constants, etc. look.

Now, Vim uses two "runtime directories":

  • the "system" one, at /usr/share/vim/vimXX/ for you, which you shouldn't touch, sudo or not,
  • the "user" one, at $HOME/.vim/ for you, where all your customization is supposed to take place.

Both directories have the same structure so the idea is that you can put your custom stuff there and, as long as it respects the default structure, it will be picked up by Vim automatically.

In this case, your job is to write your own syntax script at $HOME/.vim/syntax/python.vim, with the following content:

syn keyword pythonTodo DEBUG WARNING contained

which would give you something like that in a new Vim session:

keywords

But then comes your second requirement:

What if I want to specify the color for different words? For example, red for DEBUG, yellow for WARNING.

The syntax script doesn't care about colors, only about syntax. It is the color scheme that handles colors but it depends on the hard work of the syntax script. If DEBUG and WARNING are both pythonTodo, then they will both be highlighted the same way.

This is a bit more complex, but not by much. Let's do it step-by-step.

  1. Define a different highlight group, say pythonTodoAlt, only for WARNING:

    syn keyword pythonTodo DEBUG contained
    syn keyword pythonTodoAlt WARNING contained
    

    Do you see that contained at the end? It means that the highlight group is to be found in other highlight groups that explicitly "contain" it. In this case, pythonTodo is supposed to be "contained" in pythonComment, which is defined on the line above in the built-in syntax script:

    syn match   pythonComment    "#.*$" contains=pythonTodo,@Spell
    

    As-is, only pythonTodo is listed and simply adding the following to your custom syntax script won't work because it will be overridden by the built-in one:

    syn match pythonComment "#.*$" contains=pythonTodoAlt,pythonTodo,@Spell
    

    nocol

    Bummer.

  2. The solution is to add the containedin attribute to pythonTodoAlt:

    syn keyword pythonTodoAlt WARNING containedin=pythonComment contained
    

    But you are not done yet, because there is no highlighting defined for pythonTodoAlt:

    bare

  3. Syntax scripts tend to define lots and lots of highlight groups but it would be ludicrous to expect every color scheme to handle every highlight group, present and future, explicitly. That's why syntax script authors link their fancy groups, like pythonTodo, to a small set of "default" groups, like Todo. In the built-in syntax script, this is done like so:

    hi def link pythonTodo           Todo
    

    Now, this is the time to decide what to do next.

    One possibility is to link pythonTodoAlt to a different default group, which would be the most "correct" move, but which one? Is there a default highlight group other than Todo that looks the way you want with the current color scheme? Here is an example where I link pythonTodoAlt to Constant because that's the first one that came to mind:

    hi def link pythonTodoAlt Constant
    

    constant

    Meh.

    The other possibility is to directly define the looks of pythonTodoAlt at the color scheme level. If you don't want or can't edit your color scheme, this is how you do it (see this gist):

    " in $MYVIMRC, before defining your color scheme
    augroup MyColors
        autocmd!
        autocmd ColorScheme * highlight pythonTodoAlt cterm=reverse ctermbg=NONE ctermfg=204 gui=reverse guibg=NONE guifg=#ff5f87
    augroup END
    

    done

Related