Why taskinfo syntax file does not work as expect? - vim

I have following syntax file:
syn match TaskName /^\[.*\]/
syn match TaskType /^\[.*\]\s*\zs[a-z]*/
syn match TaskDescription /^\[.*\]\s*[a-z]*\s\+\zs.*/
hi def link TaskName Title
hi def link TaskType Todo
hi def link TaskDescription Comment
and the context is:
Task Type Command
[file-run] local no description
why only [file-run] is matched?
If I type /^\[.*\]\s*\zs[a-z]* in normal mode, local will be matched.

The reason it is not matching is that :syn match does not try and
evaluate text it has already matched. So, it cannot match against the text already matched by :syn match TaskName.
Additionally, there's a lot that could be improved upon your patterns, notably:
You have a lot of pattern atoms that will match the empty string.
This makes pattern matching slow, as patterns like [a-z]* will match
everywhere (this pattern in particular is even pointed out as an example of
a pattern to avoid in the help documentation for :syn-pattern). In most
cases it is better to match 1 or more matches with \+ than 0 or
more matches with *.
You can make all of your patterns more brief and more clear using other
arguments of :syn match.
I would suggest leveraging the power of the nextgroup argument in combination
with the skipwhite argument of :syn match:
nextgroup allows you to tell
Vim to try and match the groups specified after this match.
The skipwhite argument allows you to skip over tabs and spaces when
trying to match the next group with nextgroup.
Keeping these in mind, you could rewrite your patterns to look like:
syn match TaskName /^\[.\+\]/ nextgroup=TaskType skipwhite
syn match TaskType /[a-z]\+/ nextgroup=TaskDescription skipwhite
syn match TaskDescription /\w\+\(\s\+\w\+\)*/
In order to do this, I've also edited your TaskDescription match to be “a word,
followed by 0 or more words separated by whitespace".
You can see that utilizing nextgroup and skipwhite makes each syntax match
more brief, in addition to making the contents of each group more clear.
Relevant :help queries:
:h :syn-match
:h :syn-pattern
:h :syn-nextgroup
:h :syn-skipwhite

Related

vim syntax: how to use contained fields

Following up on this question
The syntax of my logs has changed. I now have to include a username before the time, so the new format is:
[username] time LEVEL filepath:line - message
I have no problem defining the various regions:
syn region logUser start=+^\[+ end=+\] +me=e-1 contained
syn match logTime "\d\{4}-\d\{2}-\d\{2} \d\{2}:\d\{2}:\d\{2},\d\{3}" contained
syn keyword logCritical CRITICAL contained
syn keyword logError ERROR contained
syn keyword logWarn WARN contained
syn keyword logInfo INFO contained
syn keyword logDebug DEBUG contained
syn match logFileAndNumber " \S\+:\d\+ - " contains=logFile,logLineNumber
syn match logFile " \S\+:" contained
syn match logLineNumber "\d\+" contained
The problem is I can't figure out how to create a region at the beginning, so that I don't get highlighting any time I see one of the log levels, or if a timestamp appears in the message or something. The answer to the linked question works for the previous format, but doesn't have much in the way of explanation so I don't really understand what it's doing.
EDIT: Is there no way to simply define the smaller regions and then define the larger region as a sequence of the smaller ones? I know this wouldn't work, but something along the lines of:
syn match logBeginning "$logUser $logTime [$logCritical|$logError|$logWarn|$logInfo|$logDebug]"
If the sequence (user, time, severity, ...) is fixed, you can use nextgroup=... attribute to chain them together. So, make the first (logUser) an uncontained one (so that it matches anywhere), and instruct Vim to check for logTime after it (only followed by whitespace). All other groups are contained to avoid matches elsewhere.
syn region logUser start=+^\[+ end=+\] +me=e-1 nextgroup=logTime skipwhite
syn match logTime "\d\{4}-\d\{2}-\d\{2} \d\{2}:\d\{2}:\d\{2},\d\{3}" contained nextgroup=logCritical,logError,logWarn,logInfo,logDebug skipwhite
...
Cp. :help :syn-nextgroup.

How can I add a "::" operator to my VIM syntax highlighting file?

I am using a language embedded inside of Scala that has a :: operator. I would like to modify my scala.vim syntax file to recognize this new operator.
This is what I've tried (the first line works fine, but I don't know how to add the :: operator to it):
syn match COperator "[&|~><!)(*#%#+/=?:;}{,.\^\-\[\]]"
syn match COperator "\v::"
syn match COperator "\v\:\:"
hi link COperator Special
Any advice?
An existing scalaOperator ":\{2,\}" was causing all sequences of : to match (if there are two or more series of :), overriding my own syn match COperator statements.
The solution to get :: to match as a COperator was to simply rename the scalaOperator that matches series of : to a COperator:
syn match COperator ":\{2,\}"
Summary: check for existing match rules that override your own match rules.

vim regex & highlight syntax: find a match and ignore sub-match in it

I am trying to write a syntax highlighter in VIM. How do you highlight a match within another match?
To find each match, I created two syn match lines, which work where the matches are separate.
syn match celString "^xpath=.\{-};" -> matches "xpath=.........;"
syn match celComment "\${.\{-}}" -> matches "${LIB_METADATA};"
The first line is pink for the xpath string and blue for the ${..} string.
The second line is pink for the xpath string, but the ${..} contained inside that string is ignored.
I've tried to change the order of the syn match lines, but that doesn't have any effect.
I'd appreciate your ideas.
By default, Vim only applies the syntax groups to text that hasn't yet been assigned a syntax. To specify that one group can contain other groups, use the contains=... attribute:
:syn match celString "^xpath=.\{-};" contains=celComment
The order of definition shouldn't matter here. See :help :syn-contains for more information.

In a VIM syntax file how can I use a start match in the end match?

In VIM syntax files one can write a syntax region match like this:
syn region xqString start=+'+ end=+'+
syn region xqString start=+"+ end=+"+
What I want to write instead is
syn region xqString start=+(['"])+ end=+\1+
where \1 is the match found in start. Any answers on how to do this or if it's not possible?
See :help :syn-ext-match
External matches :syn-ext-match
These extra regular expression items are available in region patterns:
*/\z(* */\z(\)* *E50* *E52*
\z(\) Marks the sub-expression as "external", meaning that it is can
be accessed from another pattern match. Currently only usable
in defining a syntax region start pattern.
*/\z1* */\z2* */\z3* */\z4* */\z5*
\z1 ... \z9 */\z6* */\z7* */\z8* */\z9* *E66* *E67*
Matches the same string that was matched by the corresponding
sub-expression in a previous start pattern match.
So you could do syn region xqString start=+\z(['"]\)+ skip=+\\.+ end=+\z1+

Sub-match syntax highlighting in Vim

First, I'll show the specific problem I'm having, but I think the problem can be generalized.
I'm working with a language that has explicit parenthesis syntax (like Lisp), but has keywords that are only reserved against the left paren. Example:
(key key)
the former is a reserved word, but the latter is a reference to the variable named "key"
Unfortunately, I find highlighting the left paren annoying, so I end up using
syn keyword classification key
instead of
syn keyword classification (key
but the former triggers on the variable uses as well.
I'd take a hack to get around my problem, but I'd be more interested in a general method to highlight just a subset of a given match.
Using syn keyword alone for this situation doesn't work right because you want your highlighting to be more aware of the surrounding syntax. A combination of syn region, syn match, and syn keyword works well.
hi link lispFuncs Function
hi link lispFunc Identifier
hi link sExpr Statement
syn keyword lispFuncs key foo bar contained containedin=lispFunc
syn match lispFunc "(\#<=\w\+" contained containedin=sExpr contains=lispFuncs
syn region sExpr matchgroup=Special start="(" end=")" contains=sExpr,lispFuncs
The above will only highlight key, foo, and bar using the Function highlight group, only if they're also matched by lispFunc.
If there are any words other than key, foo, and bar which come after a (, they will be highlighted using the Identifier highlight group. This allows you to distinguish between standard function names and user-created ones.
The ( and ) will be highlighted using the Special highlight group, and anything inside the () past the first word will be highlighted using the Statement highlight group.
There does appear to be some capability for layered highlighting, as seen here: Highlighting matches in Vim over an inverted pattern
which gives ex commands
:match myBaseHighlight /foo/
:2match myGroup /./
I haven't been able to get anything like that to work in my syntax files, though. I tried something like:
syn match Keyword "(key"
syn match Normal "("
The highlighting goes to Normal or Keyword over the whole bit depending on what gets picked up first (altered by arrangement in the file)
Vim soundly rejected using "2match" as a keyword after "syn".

Resources