I have two syntax region defined as follows:

syntax region xBCD start="b" end="d"
hi def link xBCD Todo

syntax region xBlock start="\z(abcde\)\zs::" end=";"
hi def link xBlock Comment

and a text file like this:


I.e, I have is a syntax region that I'd like to define within the start match of another region.

When I use these regions, then only the xBCD region is highlighted.

If I try to defined xBCD as contained in xBlock, like this:

syntax region xBCD start="b" end="d" contained
hi def link xBCD Todo

syntax region xBlock start="\z(abcde\)\zs::" end=";" contains=xBCD
hi def link xBlock Comment

then I get the opposite effect; everything after start is highlighted as xBlock, but bcd is not highlighted as xBCD.

Is there some way to define and highlight other regions within the un-highlighted parts of a broader region's start match?


2 Answers 2


The fix

syntax region xBCD start="b" end="d"
syntax region xBlock start="abcde::"hs=s+5 end=";" contains=xBCD


The problem is not that Vim cannot highlight a subset of start. Instead it is your use of \zs that is causing issues. We can show this is true by removing the \zs and allowing the xBCD to be inside the xBlock:

syntax region xBlock start="abcde::" end=";" contains=xBCD

You will see that your bcd is now highlighted, but obviously now your entire xBlock is highlighted, which is not your goal.

Using a highlight offset (see :help syn-pattern-offset) fixes this.

Using a "positive lookbehind" instead (see :help /\@<=) is an alternative method of achieving your desired highlighting which might work better for your requirements:

syntax region xBlock start="\(abcde\)\@<=::" end=";"

(Your use of \z() to mark the subexpression as "external" doesn't seem to be used anywhere in your example, so I removed it. The solution still works fine with it reinserted, though.)

Why your code failed

Here is my explanation of I think was going wrong with your code. It's conjecture, but based on a reasonable amount of experimentation:

When you use \zs it moves the start of your match to after the abcde. This means that your xBlock is no longer the first piece of matching syntax in your sample file: the xBCD is now found a few characters earlier, and thus is highlighted. Vim then starts looking after the end of the matching xBCD, which is too far forwards for xBlock to match, so no more matches are found.

Your attempt to fix it by adding contains=xBCD to your xBlock definition therefore failed because the xBCD region is not inside xBlock, it's a few characters before the start of where the xBlock would be, if its own presence didn't prevent the xBlock from being matched at all.

The reason your second attempt gave different results is that you also added contained to your definition of xBCD, which does not mean that xBCD can be found inside other syntax groups, but instead that it cannot be found outside of them, at the top level. Therefore, the xBCD region is no longer found, and now your highlighting for xBlock starts working.

I also tried allowing the xBlock to start within the xBCD block (the opposite of what you tried) with appropriate use of contains, because this is closer to how Vim would see it, but that failed too: I guess because regardless of whether Vim considers the a or the : to be the "start" of the match, neither is actually within the xBCD region.

I therefore don't think it's possible to get this working using \zs.

  • 1
    Thanks so much, this is a phenomenal explanation. My MVCE was not the best, as you pointed out in an earlier edit, but you basically identified the problem which was my use of \zs. I have inherited a syntax file which used them very liberally, but your use of \@<= is working perfectly and is exactly what I need, and may solve a host of other problems. I regret that the bounty has expired but you have my and the vim-rst community's gratitude :). Commented Feb 25, 2019 at 23:46
  • @marshall.ward Glad I could help!
    – Rich
    Commented Feb 26, 2019 at 10:59

I don't think vim can do what you want (highlight region in a start match of another region -- in terms of vim regions)

But you can do simpler thing (in case you didn't find it in a documentation) -- highlight start and end of a region with a different highlight group:

enter image description here

syntax region xBlock matchgroup=String start="abcde::" end=";"
hi link xBlock Todo
  • Thanks very much for replying. Unfortunately I do need it to highlight a subset of start rather than the whole thing. (I am in fact already using something similar to this to highlight the ::). I'll keep this open a while longer, but I may need to ask this one on the vim_dev mailing list. Commented Jan 31, 2019 at 9:36

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.