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" }
BBBBBBBBBBBBBBBBBBBBBBBBBB
SSSSSSSSSSSSSS SS
IIIIII
Where B means Block region, S - String region and I - Identifier region.
While I'm expecting to see the following picture:
{ "string ${var} string" }
BBBBBBBBBBBBBBBBBBBBBBBBBB
SSSSSSSSSSSSSSSSSSSSSS
IIIIII
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.c 26 Apr 2006 23:58:59 -0000 1.62
--- syntax.c 20 Sep 2006 20:58:12 -0000
***************
*** 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();