如何在 vim 语法区域中使用与开始和结束相同的模式?

How do I use the same pattern as begin and end in a vim syntax-region?

所以,我正在尝试为 OCaml 的 Menhir 解析器生成器构建语法。

在该语言中,一个文件分为三个部分,由 %% 分隔(不,它不漂亮;不幸的是,它继承自古老的 ocamlyacc。)

我正在尝试为这三个中的每一个创建一个单独的语法区域,再加上一个用于无关的第三个 %%:

之后的任何内容
this should be in `menhirDeclarations`
%%
this should be in `menhirRules`
%%
this should be in `menhirOcamlFooter`
%%
this should be in `menhirSeparatorError`
%%
this should still be in the same `menhirSeparatorError`

我今天一直在研究 :h syn-define 文档,我已经定义了一个与第一个声明中的所有内容匹配的组:

syn region menhirDeclarations start=/\%^/ end=/%%/
    \ contains=@menhirComments

… 但是我在扩展它以正确匹配以下部分时遇到了很多麻烦。天真的方法对我不起作用,例如:

" These break each document into the three sections of a Menhir parser definition:
syn region menhirSeparatorError start=/%%/ end=/%%/
    \ contained contains=@menhirComments
syn region menhirOcamlFooter start=/%%/ end=/%%/
    \ contained contains=@menhirCommentsnextgroup=menhirSeparatorError
syn region menhirRules start=/%%/ end=/%%/
    \ contained contains=@menhirComments nextgroup=menhirOcamlFooter
syn region menhirDeclarations start=/\%^/ end=/%%/
    \ contains=@menhirComments nextgroup=menhirRules

我怎样才能 Vim 将一个文件的语法突出显示分成多个部分,就像这样?

您的问题是 @@ 分隔符包含在区域的开始和结束模式中,因此一个区域的结束匹配会掩盖下一个区域的潜在开始匹配。换句话说,如果部分由 @@@@ 而不是 @@.

分隔,则您的代码将有效

由于您确实需要断言一个部分的两边,您可以通过:help :syn-pattern-offset停止结束区域的匹配。 me=s-1匹配结束是匹配开始前的一个字符)偏移量仍然断言一个部分以 @@ 结束,但不消耗这两个字符不再。这样,nextgroup 就可以发挥它的魔力,在上一组结束后立即开始下一组:

syn region menhirDeclarations start=/\%^./ end=/%%/me=s-1 nextgroup=menhirRules
syn region menhirRules start=/%%/ end=/%%/me=s-1 contained nextgroup=menhirOcamlFooter
syn region menhirOcamlFooter start=/%%/ end=/%%/me=s-1 contained nextgroup=menhirSeparatorError
syn region menhirSeparatorError start=/%%/ end=/\%$/ contained

请注意,我不知何故必须匹配缓冲区开头的至少一个字符; /\%^/ 对我不起作用(在 Vim 版本 8.1.536 中)。为了避免实现最后 menhirSeparatorError 组的多次重复匹配(也可以用相同的方法解决),我只是让它通过 /\%$/.[=22 在缓冲区的末尾结束=]