Custom Syntax Highlighting for Vim

Hey everybody, it’s your favorite tech-savvy psychopath with another informative tutorial for you to enjoy. This time I’m going to show you the system I use for adding my own custom syntax highlighting to Vim, using the scripting language informally known as Vimscript. I say “the system I use” rather than “how to do XYZ” because in all honesty I don’t know half of the syntax constructs used by Vimscript for creating syntax highlighting and colorschemes. Basically all I know is how to add keywords to Vim’s syntax highlighting repertoire and how to modify colorscheme files so they use the colors I want (on a side note, syntax files and colorschemes are technically two different kinds of scripts).

Since I never got around to learning advanced metacharacters in Vimscript, I can’t really write a full tutorial on the subject, though I’m sure several good ones exist. Instead, I’m going to show you the system I personally use, which is a subset of Vim’s syntax highlighting capabilities combined with some key bindings and auxiliary scripts that I use.

First let’s look at how to create a basic syntax file in Vimscript. There are basically two levels to a syntax file: linking patterns and keywords to syntax classes specific to the given language, and linking the language-specific classes to universal classes. The language-specific classes take the form of langElement, where Element is the name of a syntactic element (which could be a universal class) and lang is the codename for the language, specifically the value of the environment variable b:current_syntax corresponding to the current window. There are seven universal classes: Statement, Constant, Comment, Type, Function, PreProc, and Special. To find out what language code corresponds to the language you’re using, type :let b:current_syntax. To get an exhaustive, color-coded list showing what patterns and keywords are mapped to what classes, type :syntax.

This is all rather abstract at the moment. Hopefully a couple screenshots of the output of :syntax will make it clearer.

Vim syntax highlighting rules for the C language

Vim syntax highlighting rules for C with function keywords that I added

Notice how there are three columns – first the syntax class, then the color assigned to that syntax class, then a description of what that syntax class does (matches a pattern or links to something else). Also notice the long list of keywords that are mapped to the cFunction class. By default Vim doesn’t even highlight C functions. These are rules that I added through the use of Vimscript syntax files.

There are two basic commands used in a syntax file: syntax and highlight. syntax is used to link keywords and patterns to language-specific classes while highlight is used to link language-specific classes with universal classes. As an illustration, here is the syntax file I use for libc:

  1 " Syntax highlighting for libc constructs
  3 syntax keyword cFunction abort
  4 syntax keyword cFunction abs
  5 syntax keyword cFunction acos
  6 syntax keyword cFunction acosh
  7 syntax keyword cFunction alarm
  8 syntax keyword cFunction asctime
  9 syntax keyword cFunction asin
 10 syntax keyword cFunction asinh
 11 syntax keyword cFunction atan
 12 syntax keyword cFunction atanh
 13 syntax keyword cFunction atexit
 14 syntax keyword cFunction atof
 15 syntax keyword cFunction atoi
 16 syntax keyword cFunction atol
 17 syntax keyword cFunction brk
 18 syntax keyword cFunction calloc
 19 syntax keyword cFunction ceil
 20 syntax keyword cFunction cfgetispeed
 21 syntax keyword cFunction cfgetospeed
 22 syntax keyword cFunction cfsetispeed
 23 syntax keyword cFunction cfsetospeed
 24 syntax keyword cFunction chdir
 25 syntax keyword cFunction chmod
 26 syntax keyword cFunction chown
 27 syntax keyword cFunction chroot
 28 syntax keyword cFunction clearerr
 29 syntax keyword cFunction clock
 30 syntax keyword cFunction close
 31 syntax keyword cFunction closedir
 32 syntax keyword cFunction cos
303 syntax keyword cConstant O_RDONLY
304 syntax keyword cConstant O_WRONLY
305 syntax keyword cConstant O_RDWR
306 syntax keyword cConstant O_CREAT
307 syntax keyword cConstant O_EXCL
308 syntax keyword cConstant O_NOCTTY
309 syntax keyword cConstant O_TRUNC
310 syntax keyword cConstant O_APPEND
311 syntax keyword cConstant O_NONBLOCK
312 syntax keyword cConstant O_NDELAY
313 syntax keyword cConstant O_SYNC
314 syntax keyword cConstant O_FSYNG
315 syntax keyword cConstant O_ASYNC
316 syntax keyword cConstant O_LARGEFILE
317 syntax keyword cConstant O_ACCMODE
318 syntax keyword cConstant S_ISDIR
319 syntax keyword cConstant S_ISCHR
320 syntax keyword cConstant S_ISBLK
321 syntax keyword cConstant S_ISREG
322 syntax keyword cConstant S_ISFIFO
323 syntax keyword cConstant S_ISLNK
324 syntax keyword cConstant S_IRUSR
325 syntax keyword cConstant S_IWUSR
326 syntax keyword cConstant S_IXUSR
327 syntax keyword cConstant S_IRGRP
328 syntax keyword cConstant S_IWGRP
329 syntax keyword cConstant S_IXGRP
330 syntax keyword cConstant S_IROTH
331 syntax keyword cConstant S_IWOTH
332 syntax keyword cConstant S_IXOTH
446 syntax keyword cType dev_t
447 syntax keyword cType gid_t
448 syntax keyword cType ino_t
449 syntax keyword cType mode_t
450 syntax keyword cType nlink_t
451 syntax keyword cType pid_t
452 syntax keyword cType pthread_attr_t
453 syntax keyword cType pthread_t
454 syntax keyword cType speed_t
455 syntax keyword cType uid_t
456 syntax keyword cType key_t
458 highlight link cFunction Function

Notice how the code at the top designates certain keywords as belonging to the cFunction class, and the line at the bottom links the cFunction class to the universal class Function. This last part need only be done for classes that aren’t yet linked. There’s no need to do it for the cConstant and cType classes.

The idea of these syntax files is that you will have a separate one for each language you’re coding in. And that’s exactly what I’ve done with my system. If I find the default syntax file for a language lacking in any way, I add my own syntax rules via an auxiliary file storied in my .vim directory. I then write another Vimscript file to multiplex these files together, which I will now show here. This script is very easy to understand, even if you don’t know Vimscript. All it does is look at the value of b:current_syntax and decide which auxiliary syntax script to run based on that value. I have several versions of this script, depending on whether I’m using Vim from the DOS prompt, Cygwin, my Arch Linux Live CD, or my Ubuntu VM. The version you see here is what I use in Cygwin.

 1 " Add custom syntax highlighting
 3 if b:current_syntax == 'c' || b:current_syntax == 'cpp'
 4         so /cygdrive/c/Users/Public/.vim/libc.vim
 5         so /cygdrive/c/Users/Public/.vim/Xlib.vim
 6 elseif b:current_syntax == 'bash' || b:current_syntax == 'sh'
 7         so /cygdrive/c/Users/Public/.vim/bash.vim
 8 elseif b:current_syntax == 'basic'
 9         so /cygdrive/c/Users/Public/.vim/qbasic.vim
10 endif

Currently I only have scripts for C, Unix shell, and QBASIC, because those were the only languages where I found important keywords missing from the the default syntax files.

Of course, ideally, this script should be run automatically, with as little user intervention as possible. The ideal case would be to put an so command for it in the _vimrc file so that it runs every time I start up. Unfortunately, I found that when I did this I ended up getting weird errors and not being able to use syntax highlighting at all. I still haven’t figured out why these errors occurred. But in any case, I used the next best alternative – using Vim’s keybinding feature to bind a key that I never use to that script. I added this line to my _vimrc file:

nmap + :so ~/.vim/syntax.vim<CR>

Now whenever I type the plus key in normal mode in Vim, my custom syntax highlighting rules are activated, based on what language I’m currently using. And therein lies my entire system. See you next time and happy hacking!


Leave a Reply

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s