I'm not sure I'm using the right tool for the job here, but I'm trying to embed Lua syntax highlighting inside a block syntax. The only way I can make this work is with a syn region. I can find the block easily enough with a syn match, but trying to embed another syntax in there (e.g. with contains=@Lua just ends up bleeding all other the place.

This is for the vim-sile syntax plugin. I've managed to do something similar embedding Lua for an inline syntax where the region end actually is just a delimiter, so that is hilghlighted correctly. See for example:

\font[family=Libertinus Serif]
-- Lua comment
.myvar = "mod4=" .. 4 % 2

% sile comment
Lorem ipsum...

\script{myvar = "mod4=" .. 4 % 2}

lorem \emph{ipsum}...

Note how the Lua code inside the \script{...} command works great, but the same code in the \begin{script}...\end{script} block does not.


I have matches already setup for parsing the details of \begin{<command>} and those are nicely highlighted for other possible values, but specifically for script when Lua is going to be embedded I can't figure out how to use my regular highlighting for the delimiters and use them in the start/end.

syn region sileBlockLua matchgroup=Delimiter start="\\begin{script}"    end="\\end{script}" contains=@LUA

This finds the blocks and does the Lua embedding right, but the start and end text ends up as Delimiter.

How can I capture a region to embed another syntax, but also capture and highlgiht the start and end delimiters?


This syntax rule works to highlight a Lua script inside a \begin{script} block:

syn region sileBlockLua
    \ start="\\begin{script}" end="\\end{script}"
    \ contains=sileBlock,@LUA keepend

You can add this rule to a file named after/syntax/sile.vim, for instance under your ~/.vim directory.

The parts in bold are the ones that make it work.

With contains=sileBlock,@LUA, you're allowing the rules that match \begin and \end (including the following {...} with a command) within this region, so this will end up highlighting the delimiters appropriately.

With keepend, you're preventing the syntax engine from parsing Lua syntax past the end delimiter. This directive makes the match on the end delimiter stronger than the contained parts.

UPDATE: An additional improvement is to remove the end tag from the region, so that incomplete Lua syntax doesn't affect it. That can be done with the further addition of:

syn region sileBlockLua
    \ start="\\begin{script}" end="\\end{script}"me=s-1
    \ contains=sileBlock,@LUA keepend

Which indicates that the match end for that tag will be 1 character before the start of where the regular expression matches.

By having that match outside of the region, it will be unaffected by the Lua syntax rules.

(Thanks @Caleb for incorporating my suggestions into an upstream commit!)

| improve this answer | |
  • 1
    Wow, thank you, and that works beautifully. It's rather amusing how the \end{script} delimiter changes highlighting when entering incomplete Lua code (such as when it's looking for an end to finish and un-closed loop, but I think that's to be expected. At least it doesn't bleed all over the rest of the file like my previous attempts. – Caleb Dec 19 '19 at 4:49
  • 1
    I hope you don't mind I credited you as the author of the code in the commit where I added this. If you don't wish for that I'm happy to overwrite it without the credit. – Caleb Dec 19 '19 at 5:03
  • Glad this worked for you! You can try changing the end tag to end="\\end{script}"me=s-1 (change match eend to one character before the start of the regex), in which case the \\end{script} will be outside the region and might be a lot more stable... (Let me know if that helps, I can update the answer to include that too!) – filbranden Dec 19 '19 at 5:04
  • Ah you're the author of the plug-in! 😁 I didn't realize that... Yeah that's totally fine, thanks a lot for the attribution! Really happy to have helped here. – filbranden Dec 19 '19 at 5:06
  • 1
    I just tried and it is indeed much more stable. Thanks for the trick. – Caleb Dec 19 '19 at 5:11

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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