Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Vim syntax: Highlight a match only at the beginning of a region

Tags:

vim

I am writing vim syntax highlighting for a DSL where functions follow the following format:

# A function with no arguments
<function>

# A function with arguments
<function(arg1, arg2)>

# A function with text
<function block of normal text>

# A function with args and text
<function(arg1,arg2) text>

# Line breaks are allowed pretty much everywhere.
<function(
        arg1,
        arg2)
    a block of text>

# As is nesting
<function(<subfunc>) Some text with <another(subfunction) etc.>>

# Backslash escape
<function(single arg with a comma: "\,") contained bracket between quotes: "\>">

It's a text-processing language (think markdown on steroids), so the text blocks must be non-restrictive.

I'm having a lot of trouble writing a vim syntax file for this.

I can do

syn region myFunction start='<' end='>' skip='\\>'
syn region myArgs start='(' end=')' skip='\\)'

But myFunction can't contain myArgs, because then the parens are wrongly highlighted in the following example:

<function(arg) some text (with parenthesis) that aren't arguments>

Specifically, I want the function name and argument list to be highlighted only at the immediate beginning of the region. However, I can't do

syn region myFunction start='<(regex to match name and arg list)' ...

Because, even if regex to match name and arg list weren't horrifying, this breaks my ability to syntax highlight nested functions.

What I want is something like nextgroup for the start of a syntax region, but I can't find one.

Is this possible? How do I do this in vimscript?

like image 914
So8res Avatar asked Nov 28 '12 17:11

So8res


1 Answers

Define a contained syntax match for the function name that overlaps with the leading < character of the myFunction region, then use nextgroup to attempt a match with myArgs only directly after it, not subsequent occurrences.

:syn region myFunction start='<' end='>' contains=myFunctionName
:syn match myFunctionName '<\i\+' contained nextgroup=myArgs
:syn region myArgs start='(' end=')' contained

Edit: Here's a variant with matchgroup on the <...> elements; the matchgroup cannot be used for the start element, because that prevents the anchoring of myFunctionName:

:syn region myFunction start='<' matchgroup=myMarker end='>' contains=myFunctionName
:syn match myFunctionName '<\i\+' contained nextgroup=myArgs contains=myMarker
:syn match myMarker '<' contained
:syn region myArgs start='(' end=')' contained
like image 72
Ingo Karkat Avatar answered Oct 14 '22 11:10

Ingo Karkat