Back to Home

VIM syntax highlighting: full immersion

VIM is notable for how simple and flexible it can be configured. In this article I will describe in detail how easy and simple it is to create your own rules for syntax highlighting on various ...

VIM syntax highlighting: full immersion

    VIM is notable for how simple and flexible it can be configured. In this article I will describe in detail how easy and simple it is to create your own syntax highlighting rules using various examples.

    Yes, there was already an article about it in Habr , but the topic was considered very superficially in it, and I will try to understand this in detail. We will cover from the simplest examples, including html highlighting enhancements for highlighting habra marking tags, to creating highlighting for full-fledged programming languages, with "context-sensitive" syntax highlighting.

    What is especially convenient - you can play with backlight without any additional movements right while editing your file, immediately observing the result. So I suggest everyone open VIM and try the examples in my article.

    Keyword Highlighting


    To begin with, consider a simple example: you edit the text and for yourself leave notes in it like “todo - rewrite this sentence so that it would be easier to read”. Let's simplify our reading of the text and highlight the word todo. To do this, in command mode, enter
    :synkeywordKeywordtodo

    Voila! Now we are in the editor, apparently something like:



    The syn (syntax) command with the first keyword parameter means the following: highlight the word todo with the Keyword style. The color of this style depends on your color scheme. You can list many keywords at once:

    :synkeywordKeywordtodorewritedone


    Regular Expression Highlighting


    The following command is used to highlight regular expressions in a wim:
    :syn match AnyHighlightStyle /herer-is-regexp/

    The main thing to remember is that the syntax of Wim's regular expressions is significantly different from Perl-like regular expressions (which many are used to):
    Perl-likeVim
    oneOrMany +oneOrMany \ +
    (group)\ (group \)
    (optional)\ (optional \) \ =
    (notSoManyTimes) {2, 4}\ (notSoManyTimes \) \ {2, 4}
    something (? = lookAhead)something \ (lookAhead \) \ @ =
    something (?! shouldNotBeThere)something \ (shouldNotBeThere \) \ @!
    (? <= lookBackward) something\ (lookBackword \) \ @ <= ssomething


    As a first example, consider the highlighting of numbers:

    :syn match Float /\d\+\(\.\d\)\=/



    Now let's look at an example more complicated - let's highlight the function calls. A function call is defined as follows: an identifier followed by an opening bracket (but you don’t need to highlight the bracket itself. To do this, use the look-ahead construction \ ze, which requires an atom to the right, but does not include it in the result of matching (thus, the parenthesis will not be highlighted with the color of the function):

    :syn match Function /\w\+\((\)\@=/



    Or let's highlight the constructor call: new SomeClassName. To do this, it will use a construction similar to \ ze, only scanning “backward”: \ zs

    :syn match Function /\(new\s\+\)\@<=\w\+/


    Highlighting regions


    Highlighting regions exists in order to simplify the highlighting of blocks with certain opening and closing constructions, for example: comments, lines, tags in html, etc. The syntax for setting regions is as follows:
    :syn region SomeHighlightStyle start=/start-regexp/ end=/end-regexp/ skip=/regexp-to-skip-and-not-treat-as-an-end-regexp/


    Consider use on reamers. First, highlight C-style multi-line comments:

    :syn region Comment start=/\/\*/end=/\*\//

    Now let's look at an example a little more complicated: let's highlight the line in the limited by double quotes:

    :syn region String start=/"/end=/"/

    However, there is a flaw in such a construction - we cannot include the character itself in the string. Let's fix this flaw and make the escaped quotes not be considered the end of the string. It is for this that the skip parameter is created, which “swallows” the expression without giving it away checking at the end of the region:

    :syn region String start=/"/ skip=/\\"/end=/"/



    Now it works as it should.

    "Folding" (folding) of regions


    Vim allows you to “collapse” blocks (for example, long comments or blocks of code). To do this, the command: syn has an optional fold parameter. So if you want to let the user collapse comments, just add fold to the end of the syn command:

    :syn region Comment start=/\/\*/end=/\*\// fold

    You just need to make sure that the information from syntax highlighting is used for “folding”:

    set foldmethod=syntax

    In order to describe the folding of the contents of {} brackets in the code, but at the same time leave the code highlighting inside (which by default will “eat”: syn region), you can use the transparent parameter at: syn region:

    :syn region CodeBlock start=/{/end=/}/ transparent fold

    In this case, the command will not change the appearance of the block inside {}, but will make it possible to collapse it.

    Highlight Styles


    The second argument to the command: syn - the style to be marked up can be any line. And in a good way, in order to separate “structure” and “presentation”, in: syn indicate “structural names” with the language prefix, for example:

    :syn keyword pascalKeyword beginendvarprocedurefunction
    :syn keyword pascalBuiltinFunction WriteLn ReadLn Assign 
    

    And then they compare these styles with the styles described in VIM color schemes using the hi (hilight) command:

    :hi link pascalKeyword Keyword
    :hi link pascalBuiltinFunction Keyword
    


    Nested blocks


    Now let's look at the following example: we want to highlight our keywords in the comments: TODO, NOTE, which are often left by programmers. To do this, VIM has two parameters contained and contains in the construct: syn. contained means that the highlighting rule is not applied “in the global” region. And contains = Style1, Style2 means that inside the rule it is worth looking for rules that describe the style of Style1 and Style2. Let's see how it looks:

    :syn keyword CommentKeyword TODO NOTE contained
    :syn region Comment  start=/\/\*/end=/\*\// contains CommentKeyword
    :hi link CommentKeyword Keyword
    

    Thus, outside TODO and NOTE comments will not be highlighted, and only they will be highlighted in the comments.

    You can “contain” not only keywords, but also any highlighting rules. For example, you can select escapable characters in a string: \ n, \ t, \ r, \ b:

    :syn region String start=/"/ skip=/\\"/end=/"/ contains=EscapeSymbol
    :syn match EscapeSymbol /\\[ntrb"]/ contained
    :highlight link EscapeSymbol Keyword
    



    Practical example: Habrateg highlighting in .html files


    If you write habraposts in VIM in .html files, then, unfortunately, hub-specific tags like habracut, hh will not be highlighted. Correct this misunderstanding. To do this, we climb into the html: .vim / syntax / html.vim highlighting file and find out that the tag name highlighting style is called htmlTagName, so by entering the command:

    :syn keyword htmlTagName habracut source hh video slideshow



    Backlight by extension


    Each time, enter commands to highlight all designs, of course, no one requires. All commands need to be issued in a file (for example) my.vim in the directory (required) .vim / syntax / Now for your files like my this script will be automatically applied. And so that the type is automatically affixed depending on the extension, you need to add the line in .vimrc:

    au BufRead,BufNewFile *.my set filetype=my

    BufRead and BufNewFile mean to apply the rule both for opened existing and for created new files.

    By the way, if suddenly you did not know this command, it can also be used to automatically highlight files with non-standard extensions: for example, if you store a database dump in .dump files, then the line

    au BufRead,BufNewFile *.dumpset filetype=sql

    Automatically when you open it will color you it as a sql file.

    Whole example


    Now let's look at a simple example as a whole: let's colorize a subset of the javascript language:

    "В javascript строчки бывают в одинарных и двойных кавычках, и экранировать 
    if exists("b:current_syntax") 
      finish
    endif
    "В javascript строчки бывают в одинарных и двойных кавычках, и экранировать соответсвенно надо разные символы
    syn region jsString start=/"/ skip=/\\"/ end=/"/ contains=jsEscapeSymbol,jsDoubleQuoteEscape
    syn region jsString start=/'/ skip=/\\'/ end=/'/ contains=jsEscapeSymbol,jsSingleQuoteEscape
    syn match jsEscapeSymbol /\\[ntrb]/ contained
    syn match jsSingleQuoteEscape /\\'/ contained
    syn match jsDoubleQuoteEscape /\\"/ contained
    syn match jsFunction /\w\+\((\)\@=/
    syn match jsFunction /\(new\s\+\)\@<=\w\+/
     "многострочный коментарий /* *
    syn region jsComment start=/\/\*/ end=/\*\// 
     "однострочный коментарий //
    syn region jsComment start=/\/\// end=/$/    
    syn keyword jsKeyword ifelsewhilenewfor throw catch function
    hi link jsKeyword Keyword
    hi link jsString String
    hi link jsEscapeSymbol jsEscape 
    hi link jsDoubleQuoteEscape jsEscape
    hi link jsSingleQuoteEscape jsEscape
    hi link jsEscape Keyword 
    hi link jsComment Comment
    hi link jsFunction Function"помечаем, что правила для языка javascript уже загружены
    let b:current_syntax="javascript" 
    


    Well, lastly



    If the language for which you are highlighting is not case sensitive - use the command
    syn case ignore
    at the beginning of the backlight description.

    When editing the backlight, I want to constantly see the result. To do this, open the coloring text in another buffer and when you want to update the result simply enter: e or: syn off | syn on

    UPD: Thanks to Goder for a lot of comments about errors in the article :)

    Read Next