◄ Articles


Contents

Making code highlighters for vim

Friday, 18/07/2025

Vim makes it absolutely easy to build code highlighters for your domain specific languages. Regular expressions are at the core of vim syntax configuration files.

Target grammar

Let’s consider a toy scripting language (called smsh script) I wrote a while back, that resembles yaml.

utils.smsh (library)

 
@python3 -c
Click:
	import pyautogui
	pyautogui.mouseDown(%args%, 'left')

@python3 -c
Press:
	import pyautogui
	pyautogui.hotkey(%args%)
	#echo Button %args% was pressed

@python3 -c
Type:
	import pyautogui
	pyautogui.write('%args%')
	#echo Sequence of characters %args% was simulated on keyboard

Open async:
	xfce4-terminal -e %args%

Screenshot:
	Open async xfce4-screenshooter
	Press 'Up'
	Press 'Up'
	Press 'Up'
	Press 'Enter'
	sleep 2
	Press 'Up'
	Press 'Up'
	Press 'Up'
	Press 'Down'
	Press 'Enter'

Exit screenshot window:
	Press 'Alt', 'F4' 

Wait:
	sleep %args%
 


example.smsh (Main code)

 
using utils

Open browser:
	Open async firefox
	#Open async google-chrome
Goto URL:
	#Press 'F6'
	echo 'Going to url %args%'
	Type %args%
	Press 'Enter'
New tab:
	Press 'Ctrl', 'T' 
Close browser:
	Press 'Alt', 'F4' 

Open browser
New tab
Goto URL "www.google.com"
Close browser
 


As you can see the constructs of this language are pretty simple, and so will be the syntax configuration.

Tokenizing the text

A tool like regex101 is quite handy for testing out regular expressions
Below are the regular expressions that single out the language constructs for this example:

Element Type

Regex Pattern

String on its own line ending with colon

/:$/

Indented strings

/^\s\s*.*$/

Non-indented strings without colon

/^\S.*[^:]$/

import keyword

/^import\s/

using keyword

/^using\s/

Decorator

/^@[^" "\t]*/

Comment

/^\s*#[^if].*$/

#if Statement

/^\s*#if.*$/

 

Picking out the colors

Execute:highlight’ in the vim console

 

This shows you a list of various styles as rendered by the active color theme. Keeping this as a reference, we can specify in our language file how each token is rendered.

Note: these colors vary depending on the active color theme.

The syntax file

This is what the final syntax file looks like:

smsh.vim 📥

 
" smsh.vim

" Define the language name and the file extensions it applies to
" Put this syntax file in the 'syntax' directory in Vim runtime
" e.g., ~/.vim/syntax/smsh.vim
" Use 'au BufRead,BufNewFile *.your_file_extension' for custom file extensions
if exists("b:current_syntax")
  finish
endif
syntax clear

" Define the color for different language elements
" String on its own line ending with colon (yellow)
syntax match customString /:$/ contains=customStringText
highlight link customString BlueSign

" Indented strings (blue)
syntax match customStringText /^\s\s*.*$/
highlight link customStringText AquaSign

" Non-indented strings without colon (yellow)
syntax match customNonIndentedString /^\S.*[^:]$/ contains=customNonIndentedStringText
highlight link customNonIndentedString AquaSign

" Import keyword (pink)
syntax match customImport /^import\s/
syntax match customImport /^using\s/
highlight link customImport AquaSign

" Decorator
syntax match decorator /^@[^" "\t]*/
highlight link decorator BlueSign

" Comment (grayed out)
syntax match customComment /^\s*#[^if].*$/
highlight link customComment Comment

syntax match ifStmt /^\s*#if.*$/
highlight link ifStmt BlueSign
 

As shown, putting this file in ~/.vim/syntax/ directory will register your language syntax in vim every time vim loads.

Thats it !!

From here, it is straight forward. You could either:

  • Open a .smsh script file in vim or 

  • use the command [:set filetype=smsh] to activate syntax highlighting in an already opened file. 

Refer

superuser QA