On 14/05/11 10:27 PM, Ben Schmidt wrote:
I've tried to look into the code to find the source of this behavior,
but eventually decided that trying to understand what it does would
take me too much time so I gave up.
I had a quick look, too, and haven't spotted the bug yet.
I have tracked it down now. The problem is that when an extend syntax
group ends, check_state_ends() calls syn_update_ends() which then calls
check_state_ends() again. However, that first call happens before
check_state_ends() has finished its current iteration which updates the
location where end-checking should continue. Thus the end-checking
commences too early, and a syntax group higher up the stack can end,
though it shouldn't.
As there is only one call to syn_update_ends() with startofline being
false, and that is from check_state_ends() which will continue its work
after the call, this one-line change can fix it:
diff --git a/src/syntax.c b/src/syntax.c
--- a/src/syntax.c
+++ b/src/syntax.c
@@ -1064,7 +1064,7 @@
}
}
check_keepend();
- check_state_ends();
+ if (startofline) check_state_ends();
}
/****************************************
However, I am a bit concerned this makes the code (even) less readable.
A comment in the middle of the function does draw attention to the fact
that startofline==0 when an extend item has just been removed. As I
mentioned above, this is the only time this is the case. It turns out
that there is also only one call when startofline is true, and this is,
funnily enough, when starting a line. The two situations are pretty
different, and even though some similar updating is necessary there are
plenty of differences, and the function is, though short, littered with
checks of startofline. I think it might be better to create two versions
of the code (corresponding to startofline being true and false), and
either put them in two functions, or even at the locations of the two
existing calls (I don't deem the functions too large for this). What do
you think, Bram? I would be happy to make such a patch.
While investigating the issue, I found an inefficiency, too; more
checking is done than necessary because had_extend in check_state_ends()
is only initialised at function start, not each iteration of the loop.
This fixes it:
diff --git a/src/syntax.c b/src/syntax.c
--- a/src/syntax.c
+++ b/src/syntax.c
@@ -2533,7 +2533,7 @@
check_state_ends()
{
stateitem_T *cur_si;
- int had_extend = FALSE;
+ int had_extend;
cur_si = &CUR_STATE(current_state.ga_len - 1);
for (;;)
@@ -2583,8 +2583,7 @@
/* When the ended item has "extend", another item with
* "keepend" now needs to check for its end. */
- if (cur_si->si_flags & HL_EXTEND)
- had_extend = TRUE;
+ had_extend = (cur_si->si_flags & HL_EXTEND);
pop_current_state();
Cheers,
Ben.
--
You received this message from the "vim_dev" maillist.
Do not top-post! Type your reply below the text you are replying to.
For more information, visit http://www.vim.org/maillist.php