Search code examples
vimvim-pluginvim-syntax-highlighting

How do I start a Vim syntax-region at the very start of the document, while also allowing a keyword-match in that same position?


Thanks to another question, I've managed to assign a syntax-region to my document that starts at the very start (\%^) of the document:

syn region menhirDeclarations start=/\%^./rs=e-1 end=/%%/me=s-1

To get that to work, the start pattern had to match the very first character of the document. That is, the above won't work with just start=/\%^/; it needs that last . (The match, when successful, then excludes that character; but it has to actually match before that happens …)

Problem is, any :syn-keyword match at the same location — even one lower in :syn-priority — is going to preempt my above region-match. Basically, this means I can't have any keyword that's allowed to match at the start of the document, or that keyword, when so placed, will prevent the above "whole-top-of-the-document" region from matching at all.

Concrete example. With the following syntax:

syn keyword menhirDeclarationKeyword %parameter %token " ...
syn region menhirDeclarations start=/\%^./rs=e-1 end=/%%/me=s-1

… the document …

%token <blah> blah
blah blah blah

… will not contain the requisite menhirDeclarations region, because menhirDeclarationKeyword matched at the very first character, consuming it, and preventing menhirDeclarations from matching.

I can bypass this by declaring everything in the syntax definition as a :syn-match or :syn-region, and defining the above region very last … but that's probably a performance problem, and more importantly, really difficult to manage.

tl;dr: Is there any way to match a region at the very start of the document, and allow keywords to match at the same location?


Solution

  • To keep the keywords, you have to make them contained. Else, Vim's syntax rules will always give them precedence, and they won't allow your region(s) to match. If I remember correctly from your last question, the whole document is parsed as a sequence of different regions; that would be great. Else, you have to create new regions or matches for those parts of the document that are not yet covered, but may also contain keywords.

    syn keyword menhirDeclarationKeyword contained %parameter %token
    syn region menhirDeclarations start=/\%^%token\>/rs=e-1 end=/%%/me=s-1 contains=menhirDeclarationKeyword
    

    If that isn't feasible, you indeed have to use :syntax match instead:

    syn match menhirDeclarationKeyword "\<%token\>"
    

    Don't assume that this will be slower; measure it via :help :syntime, on various complex input files.

    The "difficult to manage" part can be addressed via Vimscript metaprogramming. For example, you can keep all keywords in a list and build the definitions dynamically with a loop:

    for s:keyword in ['parameter', 'token']
        execute printf('syntax match menhirDeclarationKeyword "\<%%%s\>"', s:keyword)
    endfor