3

I "inherited" a custom syntax script and I want to update it since it's a little out of date. The text file for which the syntax highlighting is written contains several blocks like this:

{Group1
key1 value1
key2 = value2
key3=value3
#A Comment
}

What's going wrong:

The problem is, that only key1 value1 is highlighted correctly, i.e. if an "=" sign is present only the key is highlighted but not the value. It seems like a trivial problem, but I could not manage to solve it for the last 3h (I should probably mention that this is my first syntax script).

Assuming key1 is a boolean variable, the corresponding commands in the syntax file are:

syn case ignore
syn keyword groupkey key1 nextgroup=group1vars skipwhite
syn match group1vars "true" contained
syn match group1vars "false" contained
syn match groupcomment "#.*$"
syn region groupsection start="{" end="}" contains=groupkey,groupcomment

" Highlighting
hi def link groupcomment Comment
hi def link groupkey Type
hi def link group1vars Constant

By the way, I'm pretty sure the guy who was working on it followed this tutorial.

So I think I understand why it is not working in case a "=" sign is in the same line: nextgroup= tells the editor to look for a match after the specified keyword ignoring whitespace due to the skipwhite. It works perfectly for key1 value1, but as soon as there's an "=" in between no match is found and therefore no highlighting of value2 and value3.

What I would like to achieve:

  1. Functioning highlighting of values even if there's an equal sign present,
  2. preferably no highlighting of the equal sign itself
  3. (optional) solution that's easily applicable for 100+ cases. For some of the keys there are 30-50 values to choose from. I'd like to avoid two versions for each value (one with and one without equal sign), but if necessary I can always script it.

What I tried:

  • Creating a specific match for the separator

    syn match groupsep "=" contained
    

    and adding it to contains= of the region definition:

    syn region groupsection start="{" end="}" contains=groupkey,groupcomment,groupsep
    

    Unfortunately, that had no effect, so I tried adding the separator match to the keyword definition instead

    syn keyword groupkey key1 nextgroup=group1vars,groupsep skipwhite
    

    which also showed no change.

  • using contains= in the keyword definition

    syn keyword groupkey key1 contains=group1vars,groupsep
    

    which threw me an error (apparently contains= cannot be used with syn keyword).

  • using a regular expression for the match, e.g. "=\=\s*true", which did work, but also highlighted the equal sign in the same color (see point 2). Also I feel it would be a bit of an overkill if I would have to write it in front of every match.

I have a feeling that the solution to my problem would be a nested match, i.e. the editor finds the keyword first, then tries to match = value and finally matches value, but unfortunately I have no idea how to write that. Perhaps even the keyword-then-match protocol has to be replaced by using matches only? Or could it be possible to skip the "=" similar to how it is done with skipwhite? Does someone have an idea what strategy I should use here?

Any help is greatly appreciated! Thanks

  • Are keys and values general? Is it the case that any two non-whitespace strings separated by a space or = can be treated as a key-value pair? – muru Oct 18 '18 at 7:58
  • I'm not quite sure what you mean by general, but yes, the program that reads this text file recognizes any two strings separated by a space or = as a key-value pair (given they're in a { } block). In the above example key1, key2 and key3 would be recognized properly. – CoffeeNerd Oct 18 '18 at 9:34
1

This set of syntax rules:

syn case ignore
syn region assignment oneline matchgroup=groupkey start=/\k\+\(\s*[[:space:]=]\)\@=/ skip=/\s*=\s*/ matchgroup=groupval end=/\S.*/
syn match groupcomment "#.*$"
syn region groupsection start="{" end="}" contains=assignment,groupcomment

" Highlighting
hi! link groupcomment Comment
hi! link groupkey Type
hi! link groupval Constant

Provides this highlighting for me:

enter image description here

I threw out the existing key/val settings, and used a new match for assignments:

syn region assignment oneline matchgroup=groupkey start=/\k\+\(\s*[[:space:]=]\)\@=/ skip=/\s*=\s*/ matchgroup=groupval end=/\S.*/

where:

  • groupkey is used for highlighting the key:
    • which is a string of keyword characters (\k\+) followed by
    • at least a space or an = (\s*[[:space:]=]) with zero-width lookahead (\@=), to keep this delimiting space/= outside the key.
  • any space and = in the middle are skipped
  • groupval highlights the value, which is a non-whitespace character followed by anything.
  • So if I understand correctly matchgroup=groupkey is there to map the match (\k\+) to groupkey and everything after the first non-whitespace character (\S.*) is mapped to groupval? This already does most of what I would like, but unfortunately wrongly typed values like Truee would also be highlighted since no explicit matching is done. – CoffeeNerd Oct 18 '18 at 14:35
  • @CoffeeNerd ah, yes, that's why I asked what the keys and values where. If they're expected to have specific values, then you'll have to list them out in the start and end patterns. – muru Oct 18 '18 at 14:42
  • Oops sry, my bad. So yes, they're expected to have specific values. And to make matters worse, key1 can adopt any from a list of 100+ values, while key2 has its own specific list. Differentiating between the two lists is at this point however not my priority. While I'm at it, the comment can also happen to be in the same line as the key-value pair (just at the end though). Thanks for your help by the way! – CoffeeNerd Oct 18 '18 at 15:03

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.