Vim: Line Following Syntax Match is also a Syntax Match - vim

I would like to highlight lines matching this regex RED:
syn match RedLine "^\*\*\* .* \*\*\*\n"
Then I'd like to highlight the following line BLUE no matter what text it contains.
I tried using \zs to match the following line's pattern like this:
syn match BlueLine "^\*\*\* .* \*\*\*\n\zs.*"
But that doesn't work (my understanding is that the read position has passed the portion of the match before \zs already).
So I tried the "look behind" atom like this:
syn match BlueLine "\(^\*\*\* .* \*\*\*\n\)\#50<=.*"
But that was way too slow even with the 50 byte limit.
How can I always match an entire line whenever the previous line matches a certain pattern?
e.g.
*** this line's RED since it's surrounded by pairs of 3 stars ***
this line's always BLUE because of the preceding line

You actually don't need to re-parse the first line to capture the second, following line (which indeed is highly inefficient). Vim has :help :syn-nextgroup, which directs the parser to continue parsing with preference to the specified group. The skipnl keyword skips over the newline in between. As you indiscriminately want to highlight the entire next line, a simple .* pattern will do. The only important detail for that rule is the contained keyword, so that this rule only matches triggered by the nextgroup=, but never on its own (which would color the entire buffer blue).
syn match RedLine "^\*\*\* .* \*\*\*$" skipnl nextgroup=BlueLine
syn match BlueLine ".*" contained

Related

How to match specific letters in words

I'm currently learning Russian, and there is one caveat in the encoding of Cyrillic letters: Some look exactly like ASCII. Example. The word »облако« (cloud) does neither contain an »a« nor an »o« but instead, it contains a »а« and a »о«. If you're not getting it yet, try to fire up your browsers search dialog, enter an »a« or an »o«, use some highlight-all functionality, and you will see, that »а« and »о« both remain dark.
So, now I want to highlight this problem in vim. Since I'm using mixed language text files, I can't just highlight every ASCII letter (that would be easy), instead, I want all ASCII letters in all words that contain at least one Cyrillic letter to be error-highlighted. My current approach is to use this matches:
" Here, I use бакло as a shortcut for the list of all cyrillic letters,
" this makes this a small self contained example for the word used in the
" problem desctiption, without having the full list in all lines.
" To get the file I actually have, run
" :%s/бакло/ЖжФфЭэЗзЧчБбАаДдВЬвьЪъЫыСсЕеёНнЮюІіКкМмИиЙйПпЛлОоРрЯяГгТтЦцШшЩщХхУу/g
syn match russianWordOk "[бакло]\+"
syn match russianWordError "[бакло][a-zA-Z0-9_]\+"hs=s+1
syn match russianWordError "[a-zA-Z0-9_]\+[бакло]"he=e-1
syn match russianWordError "[бакло][a-zA-Z0-9_]\+[бакло]"hs=s+1,he=e-1
However, like in »облaко« (now a is ASCII), the highlighting would still mark »обл« as valid, »a« as invalid, »к« as not being part of a keyword (it is part of the matching russianWordError keyword) and finally the remaining »о« as valid again. What I want instead is to have the entire word being part of the matching russianWordError keyword but still only the »a« being highlighted as illegal. Is there a way and if yes, how do I accomplish that?
In order to only match whole words, not fragments inside other words, wrap your patterns in \< and \>. These assertions will then be based on Vim's 'iskeyword' setting, and should be fine. (Alternatively, you can do other lookbehind and lookahead assertions via \#<= and \#=.)
syn match russianWordOk "\<[бакло]\+\>"
I would approach the highlighting of the wrong ASCII character not via hs= / he=, but via a contained group. First, identify bad mixed words. There has to be at least one cyrillic letter, either at the beginning, or at the end. The rest is at least one (i.e. repeating the \%(...\) group with \+, or else you would only match single-error words) ASCII, potentially other cyrillics in between:
syn match russianWordBad "\<\%([бакло]*[a-zA-Z0-9_]\)\+[бакло]\+\>" contains=russianWordError
syn match russianWordBad "\<[бакло]\+\%([a-zA-Z0-9_][бакло]*\)\+\>" contains=russianWordError
This contains the ASCII syntax group that does the error highlighting. Because of contained, it only matches inside another group (here: russianWordBad).
syn match russianWordError "[a-zA-Z0-9_]" contained

How can I use syntax match with literal `*` correctly?

Consider the following vim syntax rules, which I am using to change the color of words surrounded by *.
syntax match boldme /\*.\{-1,}\*/
highlight boldme ctermfg=Red
For some reason, this rule only works if the word is at the beginning of a line, *hello* is red in the first line below but not the second line.
*hello* works
Another word and *hello* does not work.
How can I make syn match work in the middle of a line for the scenario above?
Update: This problem appears to be specific to using the literal * character as part of the match. The following match works fine for using _ instead.
syntax match boldme /_.\+_/
Thus the question is really, how do I force vim to treat a literal * character correctly in syn match?
try this:
syntax match boldme /\*.\+\*/
Update
I don't know how did you do the test, see this gif animation with vim -u NONE:

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.

Vim syntax highlighting and certain characters

I am attempting to write a syntax file for Vim.
One of the lines of code reads
syn match constant "\**\*"
while one of many other lines reads
syn keyword aiOperators up-build
The code for highlighting is the following:
hi constant gui=bold
hi aiOperators guifg=green
However, the result of the above is that only the following is highlighted:
The asterisks of every constant, but not the characters between them.
Characters up until the first hyphen of aiOperators.
What seems to be the issue?
The regular expression for your constant specifies a literal asterisk, zero or more times, followed by a literal asterisk. If you intend to match characters delimited by asterisks, you need something like \*\w\+\*: a literal asterisk, followed by one or more word characters, followed by a literal asterisk.
The :syn keyword only works for keyword characters; by default, the hyphen is not included, so the match stops there. If, for your filetype, the hyphen belongs to the set of keyword characters, use
:setlocal iskeyword+=-
This should not be placed into the syntax file itself, but into ~/.vim/ftplugin/myfiletype.vim. Otherwise, use :syn match.

How to change word recognition in vim spell?

I like that vim 7.0 supports spell checking via :set spell, and I like that it by default only checks comments and text strings in my C code. But I wanted to find a way to change the behavior so that vim will know that when I write words containing underscores, I don't want that word spell checked.
The problem is that I often will refer to variable or function names in my comments, and so right now vim thinks that each piece of text that isn't a complete correct word is a spelling error. Eg.
/* The variable proj_abc_ptr is used in function do_func_stuff' */
Most of the time, the pieces seperated by underscores are complete words, but other times they are abbreviations that I would prefer not to add to a word list. Is there any global way to tell vim to include _'s as part of the word when spell checking?
Here are some more general spell-checking exception rules to put in .vim/after/syntax/{LANG}.vim files:
" Disable spell-checking of bizarre words:
" - Mixed alpha / numeric
" - Mixed case (starting upper) / All upper
" - Mixed case (starting lower)
" - Contains strange character
syn match spellingException "\<\w*\d[\d\w]*\>" transparent contained containedin=pythonComment,python.*String contains=#NoSpell
syn match spellingException "\<\(\u\l*\)\{2,}\>" transparent contained containedin=pythonComment,python.*String contains=#NoSpell
syn match spellingException "\<\(\l\+\u\+\)\+\l*\>" transparent contained containedin=pythonComment,python.*String contains=#NoSpell
syn match spellingException "\S*[/\\_`]\S*" transparent contained containedin=pythonComment,python.*String contains=#NoSpell
Change pythonComment,python.*String for your language.
transparent means that the match inherits its highlighting properties from the containing block (i.e. these rules do not change the way text is displayed).
contained prevents these matches from extending past the containing block (the last rule ends with \S* which would likely match past the end of a block)
containedin holds a list of existing syntax groups to add these new rules to.
contains=#NoSpell overrides any and all inherited groups, thus telling the spellchecker to skip the matched text.
You'll need to move it into its own group. Something like this:
hi link cCommentUnderscore cComment
syn match cCommentUnderscore display '\k\+_\w\+'
syn cluster cCommentGroup add=cCommentUnderscore
In some highlighters you may need contains=#NoSpell on the end of the match line, but in C, the default is #NoSpell, so it should be fine like that.

Resources