vimsyntaxsyntax-highlighting

Unexpected vim region match


I'm relatively new to vim's syntax highlighting and its regex engine, which seems to be very differnt from others I've used (mainly perl, pcre, posix). This vim syntax highlighting problem has been frustrating me all day.

I have the following syntax defined:

syntax  region  SourceDirective    start=/^\s*SOURCE\s/ end=/$/  oneline contains=SourceKeyword,SourceFilename
syntax  match   SourceKeyword      /^\s*SOURCE\s/                contained
syntax  match   SourceFilename     /\S\+\s*$/                    contained

highlight  SourceKeyword    ctermfg=darkyellow   guifg=darkyellow   cterm=bold,italic  gui=bold,italic
highlight  SourceFilename   ctermfg=lightyellow  guifg=lightyellow  cterm=bold,italic  gui=bold,italic
highlight  SourceDirective  cterm=inverse        gui=inverse

I don't understand why this sample:

SOURCE alpha.txt
SOURCE beta.txt
# See ID-1234
#SOURCE delta/delta.txt
SOURCE gamma.txt

produces this:

enter image description here

I can't figure out why the comment lines are in a SourceDirective region (as shown by the inverse text, which I added just for debugging). They don't match the region's start= pattern. Those line should be completely ignored by those syntax rules.

What I am missing?


Solution

  • Since SourceFilename contains a $, you need to either:

    You would do the former if the region can contain lots of matches because it is just one argument to add to one group and you don't have to think about each match individually.

    You would do the latter if your match can be included in several regions because it makes it self-contained.

    Or you can be super explicit and do both. "Ceinture-bretelles", as we say around here.

    From :help :syn-excludenl:

    When a pattern for a match or end pattern of a region includes a '$'
    to match the end-of-line, it will make a region item that it is
    contained in continue on the next line.  For example, a match with
    "\\$" (backslash at the end of the line) can make a region continue
    that would normally stop at the end of the line.  This is the default
    behavior.  If this is not wanted, there are two ways to avoid it:
    1. Use "keepend" for the containing item.  This will keep all
       contained matches from extending the match or region.  It can be
       used when all contained items must not extend the containing item.
    2. Use "excludenl" in the contained item.  This will keep that match
       from extending the containing match or region.  It can be used if
       only some contained items must not extend the containing item.
       "excludenl" must be given before the pattern it applies to.
    

    Here I have used both at the same time for demonstration, but only one is necessary:

    screenshot