Hello.
I've already posted about this bug in syntax matching code. But now I
have a fix.
Test case
=
Having following syntax rules
:syn cluster Top contains=Block,String,Identifier
:syn region Block start=+{+ end=+}+ keepend extend [EMAIL PROTECTED]
:syn region String start=+"+ end=+"+ contains=Identifier
:syn region Identifier start=+\${+ end=+}+ extend
and the following buffer is matched incorrectly
{ "string ${var} string" }
on current vim version (7.0.109) I'm getting following syntax groups:
{ "string ${var} string" }
BB
SS SS
II
Where B means Block region, S - String region and I - Identifier region.
While I'm expecting to see the following picture:
{ "string ${var} string" }
BB
SS
II
Bug description
===
Bug appears, when one have an extend region inside a normal region
inside a keepend region. Currently, when any extend region ends vim
checks all the outer keepend regions to see, if theirs ends should be
"extended", but it does not checks intermediate normal (non keepend)
regions and theirs ends should also be checked otherwise one could end
up with a normal region been forcefully ended by enclosing keepend
region and this keepend region later be extended by a containing extend
region.
Just as it is seen in the first picture in the test case. Block region
ends String region on a first '}'. But later when Identifier region
consumes that first '}' Block region is extended, while String region is
not.
Solution
Test intermediate normal region ends along with keepend region ends when
an extend region ends.
Here is a patch for syntax.c that does this check. I'm getting correct
behavior with this patch for my test case.
--
Ilya Bobir
Index: syntax.c
===
RCS file: /cvsroot/vim/vim7/src/syntax.c,v
retrieving revision 1.62
diff -c -r1.62 syntax.c
*** syntax.c26 Apr 2006 23:58:59 - 1.62
--- syntax.c20 Sep 2006 20:58:12 -
***
*** 977,982
--- 977,983
{
stateitem_T *cur_si;
int i;
+ int seen_keepend;
if (startofline)
{
***
*** 1002,1008
/*
* Need to update the end of a start/skip/end that continues from the
* previous line. And regions that have "keepend", because they may
! * influence contained items.
* Then check for items ending in column 0.
*/
i = current_state.ga_len - 1;
--- 1003,1012
/*
* Need to update the end of a start/skip/end that continues from the
* previous line. And regions that have "keepend", because they may
! * influence contained items. If we've just removed "extend"
! * (startofline == 0) then we should update ends of normal regions
! * contained inside "keepend" because "extend" could have extended
! * these "keepend" regions as well as contained normal regions.
* Then check for items ending in column 0.
*/
i = current_state.ga_len - 1;
***
*** 1010,1019
--- 1014,1026
for ( ; i > keepend_level; --i)
if (CUR_STATE(i).si_flags & HL_EXTEND)
break;
+
+ seen_keepend = 0;
for ( ; i < current_state.ga_len; ++i)
{
cur_si = &CUR_STATE(i);
if ((cur_si->si_flags & HL_KEEPEND)
+ || (seen_keepend && !startofline)
|| (i == current_state.ga_len - 1 && startofline))
{
cur_si->si_h_startpos.col = 0; /* start highl. in col 0 */
***
*** 1021,1026
--- 1028,1036
if (!(cur_si->si_flags & HL_MATCHCONT))
update_si_end(cur_si, (int)current_col, !startofline);
+
+ if(!startofline && (cur_si->si_flags & HL_KEEPEND))
+ seen_keepend = 1;
}
}
check_keepend();