I am trying to design a custom syntax file that performs some basic error checking for an ascii input file. The input is broken up into sections, and there are input cards specific to each section. The input cards vary and can have either a single argument or multiple. A brief example of the cards with valid input is:
{FOO}
card1 100.0 !%
card2 559.0 A ![ABC]
{BAR}
The goal is to have the following input cards have bad arguments, the syntax flips to highlight the errors for the first card1 argument which needs to be positive, and highlights the second card2 argument Z which needs to be either A, B, or C:
{FOO}
card1 -100.0 !%
card2 100.0 Z ![ABC]
{BAR}
Here is what my current syntax file looks like for the above example:
syn match testComment "\s*!.*$"
syn region testFOOBlockRegion start="^\{FOO\}" end="^\{"re=e-1,he=e-1,me=e-1 contains=testComment,testFOOCards,testFOOBlockName keepend
syn region testFOOBlockName start="^\{FOO" end="\}" contained oneline
syn match testChar "\s[ABC]\{1}" contained
" Floating point number with decimal no E or e
syn match testFloat "\s[-+]\=\d\+\.\=\d*"
syn match testFloat "/[^=]\+d\+\.\=\d*"
syn match testPosFloat "\s[+]\=\d\+\.\=\d*" contained
syn match testNegFloat "\s[-]\{1}\d\+\.\=\d*" contained
" Floating point like number with E and decimal point (+,-)
syn match testFloat "\s[-+]\=\d*\.\=\d*[eE][\-+]\=\d\+"
syn match testPosFloat "\s[+]\=\d*\.\=\d*[eE][\-+]\=\d\+" contained
syn match testNegFloat "\s[-]\{1}\d*\.\=\d*[eE][\-+]\=\d\+" contained
"Arbitrary regions for cards
syn region testSecondArgPosFloat start="\s*\S\+\s\+"rs=e,ms=e,hs=e end="\S\+" contains=testPosFloat keepend contained
syn region testThirdArgChar start="\s*\S\+\s\+\S\+\s\+"rs=e,ms=e,hs=e end="\S\+" contains=testChar keepend contained
"The semi-colon is for multiple cards on one line.
syn region testFOOCards start="\s*card1" end=";\|$" contains=testComment,testSecondArgPosFloat keepend contained
syn region testFOOCards start="\s*card2" end=";\|$" contains=testComment,testSecondArgPosFloat,testThirdArgChar keepend contained
"Assign syntax groups
hi def link testFloat Number
hi def link testPosFloat Number
hi def link testNegFloat Number
hi def link testChar Todo
hi def link testComment Comment
hi def link testFOOBlockName Conditional
hi def link testFOOCards Identifier
"Assign these groups to the Error group.
"In this way, a correct match will cause the syntax to highlight the characters as defined above,
"and a bad match will indicate an error.
" If the third argument isn't a char from the list, error
hi def link testThirdArgChar Error
"If the second argument isn't a positive float, error
hi def link testSecondArgPosFloat Error
"This ensures that only valid cards are syntaxed correctly and other cards are highlighted as errors
hi def link testFOOBlockRegion Error
Essentially, with the current syntax, I am able to get a card with a single argument behaving and highlighting properly. If card1 has a negative sign placed infront of it, the syntax highlighting changes to the error syntax. For card2, only the first argument's syntax works, the second does not. I believe it is an issue with the keepend
option where the syntax reverts after the "second argument" is matched, regardless of it being correct or an error, to the syntax for testFOOCards
.
I'm afraid that the only way to get this to work is to have multiple nested permutations of things like SecondArgFloatWithThirdArgChar
regions and was wondering if anyone else had something more simple/elegant or knew where else I could be looking in the manual. Thanks in advance.
Update
Several tests using the nextgroup
suggestion that were tried were:
-
syn region testSecondArgPosFloat start="\s*\S\+\s\+"rs=e,ms=e,hs=e end="\S\+" nextgroup=testThirdArgTempUnit contains=testPosFloat keepend contained
-
syn region testFOOCards start="\s*card2" end=";\|$" nextgroup=testSecondArgPosFloat contains=testComment,testSecondArgPosFloat,testThirdArgTempUnit keepend contained
-
syn region testSecondArgPosFloat start="\s*\S\+\s\+"rs=e,ms=e,hs=e end="\S\+" nextgroup=testThirdArgTempUnit contains=testPosFloat contained
-
syn region testFOOCards start="\s*card2" end=";\|$" nextgroup=testSecondArgPosFloat contains=testComment,testSecondArgPosFloat,testThirdArgTempUnit contained
It would seem that the nextgroup
argument doesn't solve the problem. There was only a noticeable syntax change when the keepend
option was toggled.
Since this current version uses regions to march forward across the line from left to right, I tried using syn match
to match the third argument first, use nextgroup
to match the second argument, and lastly a match for card2
. That also did not work as I'd like.
I was also curious if defining the starting region in the examples above changed where subsequent matches would be found. I tested this by adding more floats between the first and second argument values in card2
to see if the highlighting would change to what I expected. That also did not work. I also tried using ^
in start
match to anchor it to the beginning of the line, and repeated adding arguments. That didn't work either.
nextgroup=
would help here? You could use it to specify which groups to use to match the following field... Right?