mirror of
https://github.com/neovim/neovim.git
synced 2026-07-31 04:39:07 +00:00
vim-patch:9.2.0825: regexp: submatch in a look-behind is empty with the NFA engine (#40899)
Problem: With the NFA engine a sub-expression inside a variable width
look-behind, e.g. "\v(.)@<=", is empty for the first match on
every line except the first one. The old engine is correct
(Mukundan)
Solution: The look-behind is retried from the previous line, because the
width of "." is over-estimated. While scanning that line the
start state is added at the end of the line, where it gets the
position of the line break as its start position, even though
the match actually starts on the next line. Use the position
of the start of the next line in that case (Hirohito Higashi).
fixes: vim/vim#20802
closes: vim/vim#20805
ade577e4dc
Co-authored-by: Hirohito Higashi <h.east.727@gmail.com>
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -15525,7 +15525,30 @@ static int nfa_regmatch(nfa_regprog_T *prog, nfa_state_T *start, regsubs_T *subm
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (addstate(nextlist, start, m, NULL, clen) == NULL) {
|
||||
uint8_t *save_line = rex.line;
|
||||
uint8_t *save_input = rex.input;
|
||||
linenr_T save_lnum = rex.lnum;
|
||||
|
||||
// At the end of a line the match can only start on the next
|
||||
// line, use that position instead of the line break.
|
||||
if (REG_MULTI && clen == 0 && nfa_endp != NULL
|
||||
&& rex.lnum < nfa_endp->se_u.pos.lnum) {
|
||||
char *next_line = reg_getline(rex.lnum + 1);
|
||||
|
||||
if (next_line != NULL) {
|
||||
rex.line = (uint8_t *)next_line;
|
||||
rex.input = rex.line;
|
||||
rex.lnum++;
|
||||
}
|
||||
}
|
||||
|
||||
r = addstate(nextlist, start, m, NULL, clen);
|
||||
|
||||
rex.line = save_line;
|
||||
rex.input = save_input;
|
||||
rex.lnum = save_lnum;
|
||||
|
||||
if (r == NULL) {
|
||||
nfa_match = NFA_TOO_EXPENSIVE;
|
||||
goto theend;
|
||||
}
|
||||
|
||||
@@ -656,4 +656,29 @@ func Test_regex_collection_range_with_composing_crash()
|
||||
bwipe!
|
||||
endfunc
|
||||
|
||||
" A submatch in a look-behind must not start on the previous line. See
|
||||
" issue #20802.
|
||||
func Test_lookbehind_submatch_on_second_line()
|
||||
new
|
||||
for re in range(0, 2)
|
||||
exe "set re=" .. re
|
||||
call setline(1, ['testing', 'testing'])
|
||||
%s/\v(.)@<=/[\1]/g
|
||||
call assert_equal(['t[t]e[e]s[s]t[t]i[i]n[n]g',
|
||||
\ 't[t]e[e]s[s]t[t]i[i]n[n]g'], getline(1, '$'), 're=' .. re)
|
||||
%d _
|
||||
|
||||
" With "\_." the look-behind can match the line break, then the submatch
|
||||
" does start on the previous line.
|
||||
call setline(1, ['abc', 'def'])
|
||||
%s/\v(\_.)@<=/[\1]/g
|
||||
call assert_equal(['a[a]b[b]c[c]', '[]d[d]e[e]f[f]'],
|
||||
\ getline(1, '$'), 're=' .. re)
|
||||
%d _
|
||||
endfor
|
||||
|
||||
set re&
|
||||
bwipe!
|
||||
endfunc
|
||||
|
||||
" vim: shiftwidth=2 sts=2 expandtab
|
||||
|
||||
Reference in New Issue
Block a user