Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Vim syntax highlighting for a match on several lines

I am implementing on vim a syntax file to highlight a hierarchy like this

| text at level 1
| | text at level 2
| | text at level 2
| | | text at level 3
| text at level 1

For example I use

syn match myMatch +^\(| \)\++

to highlight the level indicators. However, I would also like to highlight wrong patterns like these

| text at level 1
| | | text at level 3

which increment the levels by more than one. I have written the following syntax match

syn match myWrongMatch +^\(\(| \)*\)\(\n\|[^|].*\n\)\1\(| \)\{2,}+

It may not be optimal but it does the job. The problem is that the matches are checked by vim on the line which is being edited so that if I fix the error by removing a level on the second line it will stop highlighting the second line but still highlight the first one until I also edit it (like remove and rewrite a character).

This problem is that I can only match a line using the next line information but not the opposite. Since this doesn't seem possible with a regex match, I would like to know if it is possible to ask vim to check for matches in both the currently edited line and the previous one (or a broader context) ? Another solution may be to implement this by a region which checks the context but I have been unsuccessful with that so far.

EDIT: The answer is actually in the vim help at :syn-sync-linebreaks (thanks Herbert Sitz for pointing me to the right section).

When using a pattern that matches multiple lines, a change in one line may cause a pattern to no longer match in a previous line. This means has to start above where the change was made. How many lines can be specified with the "linebreaks" argument. For example, when a pattern may include one line break use this:

:syntax sync linebreaks=1

The result is that redrawing always starts at least one line before where a change was made. The default value for "linebreaks" is zero. Usually the value for "minlines" is bigger than "linebreaks".

This works perfectly.

like image 535
udscbt Avatar asked Nov 23 '11 04:11

udscbt


1 Answers

You can try automating a syntax sync operation. For example, try putting this in the InsertEnter autocmd, which will sync syntax whenever you exit insert mode:

au InsertLeave * syntax synch minlines=50

Not a perfect solution. Maybe adding more autocmds would help. It depends partially on what your documents are going to look like, how big they're going to be, how you're editing.

For help read more about syntax syncing: :h syn-sync This isn't typical use of syncing, since main purpose, as I understand it, is to automatically search around edited lines when they're in syntax regions. You're not using regions, so you need to initiate sync using the autocmd. Maybe you could define a region just for purpose of making sure syntax sync reevaluates syntax over group of lines--without needing the autocmd--even if the region is not going to be used for highlighting.

like image 87
Herbert Sitz Avatar answered Oct 20 '22 02:10

Herbert Sitz