mirror of
https://github.com/neovim/neovim.git
synced 2025-09-06 03:18:16 +00:00
Merge pull request #20943 from zeertzjq/vim-8.2.4688
vim-patch:8.2.{4688,4693,4978},9.0.0053: regexp fixes
This commit is contained in:
@@ -372,7 +372,7 @@ Vim includes two regexp engines:
|
|||||||
1. An old, backtracking engine that supports everything.
|
1. An old, backtracking engine that supports everything.
|
||||||
2. A new, NFA engine that works much faster on some patterns, possibly slower
|
2. A new, NFA engine that works much faster on some patterns, possibly slower
|
||||||
on some patterns.
|
on some patterns.
|
||||||
|
*E1281*
|
||||||
Vim will automatically select the right engine for you. However, if you run
|
Vim will automatically select the right engine for you. However, if you run
|
||||||
into a problem or want to specifically select one engine or the other, you can
|
into a problem or want to specifically select one engine or the other, you can
|
||||||
prepend one of the following to the pattern:
|
prepend one of the following to the pattern:
|
||||||
|
@@ -97,20 +97,24 @@ static int toggle_Magic(int x)
|
|||||||
|
|
||||||
#define MAX_LIMIT (32767L << 16L)
|
#define MAX_LIMIT (32767L << 16L)
|
||||||
|
|
||||||
static char_u e_missingbracket[] = N_("E769: Missing ] after %s[");
|
static char e_missingbracket[] = N_("E769: Missing ] after %s[");
|
||||||
static char_u e_reverse_range[] = N_("E944: Reverse range in character class");
|
static char e_reverse_range[] = N_("E944: Reverse range in character class");
|
||||||
static char_u e_large_class[] = N_("E945: Range too large in character class");
|
static char e_large_class[] = N_("E945: Range too large in character class");
|
||||||
static char_u e_unmatchedpp[] = N_("E53: Unmatched %s%%(");
|
static char e_unmatchedpp[] = N_("E53: Unmatched %s%%(");
|
||||||
static char_u e_unmatchedp[] = N_("E54: Unmatched %s(");
|
static char e_unmatchedp[] = N_("E54: Unmatched %s(");
|
||||||
static char_u e_unmatchedpar[] = N_("E55: Unmatched %s)");
|
static char e_unmatchedpar[] = N_("E55: Unmatched %s)");
|
||||||
static char_u e_z_not_allowed[] = N_("E66: \\z( not allowed here");
|
static char e_z_not_allowed[] = N_("E66: \\z( not allowed here");
|
||||||
static char_u e_z1_not_allowed[] = N_("E67: \\z1 - \\z9 not allowed here");
|
static char e_z1_not_allowed[] = N_("E67: \\z1 - \\z9 not allowed here");
|
||||||
static char_u e_missing_sb[] = N_("E69: Missing ] after %s%%[");
|
static char e_missing_sb[] = N_("E69: Missing ] after %s%%[");
|
||||||
static char_u e_empty_sb[] = N_("E70: Empty %s%%[]");
|
static char e_empty_sb[] = N_("E70: Empty %s%%[]");
|
||||||
static char_u e_recursive[] = N_("E956: Cannot use pattern recursively");
|
static char e_recursive[] = N_("E956: Cannot use pattern recursively");
|
||||||
static char_u e_regexp_number_after_dot_pos_search[]
|
static char e_regexp_number_after_dot_pos_search_chr[]
|
||||||
= N_("E1204: No Number allowed after .: '\\%%%c'");
|
= N_("E1204: No Number allowed after .: '\\%%%c'");
|
||||||
static char_u e_substitute_nesting_too_deep[] = N_("E1290: substitute nesting too deep");
|
static char e_nfa_regexp_missing_value_in_chr[]
|
||||||
|
= N_("E1273: (NFA regexp) missing value in '\\%%%c'");
|
||||||
|
static char e_atom_engine_must_be_at_start_of_pattern[]
|
||||||
|
= N_("E1281: Atom '\\%%#=%c' must be at the start of the pattern");
|
||||||
|
static char e_substitute_nesting_too_deep[] = N_("E1290: substitute nesting too deep");
|
||||||
|
|
||||||
#define NOT_MULTI 0
|
#define NOT_MULTI 0
|
||||||
#define MULTI_ONE 1
|
#define MULTI_ONE 1
|
||||||
|
@@ -1971,6 +1971,11 @@ static char_u *regatom(int *flagp)
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case '#':
|
case '#':
|
||||||
|
if (regparse[0] == '=' && regparse[1] >= 48 && regparse[1] <= 50) {
|
||||||
|
// misplaced \%#=1
|
||||||
|
semsg(_(e_atom_engine_must_be_at_start_of_pattern), regparse[1]);
|
||||||
|
return FAIL;
|
||||||
|
}
|
||||||
ret = regnode(CURSOR);
|
ret = regnode(CURSOR);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@@ -2091,6 +2096,7 @@ static char_u *regatom(int *flagp)
|
|||||||
uint32_t n = 0;
|
uint32_t n = 0;
|
||||||
int cmp;
|
int cmp;
|
||||||
bool cur = false;
|
bool cur = false;
|
||||||
|
bool got_digit = false;
|
||||||
|
|
||||||
cmp = c;
|
cmp = c;
|
||||||
if (cmp == '<' || cmp == '>') {
|
if (cmp == '<' || cmp == '>') {
|
||||||
@@ -2101,6 +2107,7 @@ static char_u *regatom(int *flagp)
|
|||||||
c = getchr();
|
c = getchr();
|
||||||
}
|
}
|
||||||
while (ascii_isdigit(c)) {
|
while (ascii_isdigit(c)) {
|
||||||
|
got_digit = true;
|
||||||
n = n * 10 + (uint32_t)(c - '0');
|
n = n * 10 + (uint32_t)(c - '0');
|
||||||
c = getchr();
|
c = getchr();
|
||||||
}
|
}
|
||||||
@@ -2115,9 +2122,9 @@ static char_u *regatom(int *flagp)
|
|||||||
*regcode++ = (char_u)cmp;
|
*regcode++ = (char_u)cmp;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
} else if (c == 'l' || c == 'c' || c == 'v') {
|
} else if ((c == 'l' || c == 'c' || c == 'v') && (cur || got_digit)) {
|
||||||
if (cur && n) {
|
if (cur && n) {
|
||||||
semsg(_(e_regexp_number_after_dot_pos_search), no_Magic(c));
|
semsg(_(e_regexp_number_after_dot_pos_search_chr), no_Magic(c));
|
||||||
rc_did_emsg = true;
|
rc_did_emsg = true;
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
@@ -2094,6 +2094,12 @@ static int nfa_regatom(void)
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case '#':
|
case '#':
|
||||||
|
if (regparse[0] == '=' && regparse[1] >= 48
|
||||||
|
&& regparse[1] <= 50) {
|
||||||
|
// misplaced \%#=1
|
||||||
|
semsg(_(e_atom_engine_must_be_at_start_of_pattern), regparse[1]);
|
||||||
|
return FAIL;
|
||||||
|
}
|
||||||
EMIT(NFA_CURSOR);
|
EMIT(NFA_CURSOR);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@@ -2141,6 +2147,7 @@ static int nfa_regatom(void)
|
|||||||
int64_t n = 0;
|
int64_t n = 0;
|
||||||
const int cmp = c;
|
const int cmp = c;
|
||||||
bool cur = false;
|
bool cur = false;
|
||||||
|
bool got_digit = false;
|
||||||
|
|
||||||
if (c == '<' || c == '>') {
|
if (c == '<' || c == '>') {
|
||||||
c = getchr();
|
c = getchr();
|
||||||
@@ -2151,7 +2158,7 @@ static int nfa_regatom(void)
|
|||||||
}
|
}
|
||||||
while (ascii_isdigit(c)) {
|
while (ascii_isdigit(c)) {
|
||||||
if (cur) {
|
if (cur) {
|
||||||
semsg(_(e_regexp_number_after_dot_pos_search), no_Magic(c));
|
semsg(_(e_regexp_number_after_dot_pos_search_chr), no_Magic(c));
|
||||||
return FAIL;
|
return FAIL;
|
||||||
}
|
}
|
||||||
if (n > (INT32_MAX - (c - '0')) / 10) {
|
if (n > (INT32_MAX - (c - '0')) / 10) {
|
||||||
@@ -2161,10 +2168,15 @@ static int nfa_regatom(void)
|
|||||||
}
|
}
|
||||||
n = n * 10 + (c - '0');
|
n = n * 10 + (c - '0');
|
||||||
c = getchr();
|
c = getchr();
|
||||||
|
got_digit = true;
|
||||||
}
|
}
|
||||||
if (c == 'l' || c == 'c' || c == 'v') {
|
if (c == 'l' || c == 'c' || c == 'v') {
|
||||||
int32_t limit = INT32_MAX;
|
int32_t limit = INT32_MAX;
|
||||||
|
|
||||||
|
if (!cur && !got_digit) {
|
||||||
|
semsg(_(e_nfa_regexp_missing_value_in_chr), no_Magic(c));
|
||||||
|
return FAIL;
|
||||||
|
}
|
||||||
if (c == 'l') {
|
if (c == 'l') {
|
||||||
if (cur) {
|
if (cur) {
|
||||||
n = curwin->w_cursor.lnum;
|
n = curwin->w_cursor.lnum;
|
||||||
|
@@ -105,6 +105,31 @@ func Test_multi_failure()
|
|||||||
set re=0
|
set re=0
|
||||||
endfunc
|
endfunc
|
||||||
|
|
||||||
|
func Test_column_success_failure()
|
||||||
|
new
|
||||||
|
call setline(1, 'xbar')
|
||||||
|
|
||||||
|
set re=1
|
||||||
|
%s/\%>0v./A/
|
||||||
|
call assert_equal('Abar', getline(1))
|
||||||
|
call assert_fails('/\%v', 'E71:')
|
||||||
|
call assert_fails('/\%>v', 'E71:')
|
||||||
|
call assert_fails('/\%c', 'E71:')
|
||||||
|
call assert_fails('/\%<c', 'E71:')
|
||||||
|
call assert_fails('/\%l', 'E71:')
|
||||||
|
set re=2
|
||||||
|
%s/\%>0v./B/
|
||||||
|
call assert_equal('Bbar', getline(1))
|
||||||
|
call assert_fails('/\%v', 'E1273:')
|
||||||
|
call assert_fails('/\%>v', 'E1273:')
|
||||||
|
call assert_fails('/\%c', 'E1273:')
|
||||||
|
call assert_fails('/\%<c', 'E1273:')
|
||||||
|
call assert_fails('/\%l', 'E1273:')
|
||||||
|
|
||||||
|
set re=0
|
||||||
|
bwipe!
|
||||||
|
endfunc
|
||||||
|
|
||||||
func Test_recursive_addstate()
|
func Test_recursive_addstate()
|
||||||
throw 'skipped: TODO: '
|
throw 'skipped: TODO: '
|
||||||
" This will call addstate() recursively until it runs into the limit.
|
" This will call addstate() recursively until it runs into the limit.
|
||||||
@@ -1033,6 +1058,28 @@ func Test_using_invalid_visual_position()
|
|||||||
bwipe!
|
bwipe!
|
||||||
endfunc
|
endfunc
|
||||||
|
|
||||||
|
func Test_using_two_engines_pattern()
|
||||||
|
new
|
||||||
|
call setline(1, ['foobar=0', 'foobar=1', 'foobar=2'])
|
||||||
|
" \%#= at the end of the pattern
|
||||||
|
for i in range(0, 2)
|
||||||
|
for j in range(0, 2)
|
||||||
|
exe "set re=" .. i
|
||||||
|
call cursor(j + 1, 7)
|
||||||
|
call assert_fails("%s/foobar\\%#=" .. j, 'E1281:')
|
||||||
|
endfor
|
||||||
|
endfor
|
||||||
|
set re=0
|
||||||
|
|
||||||
|
" \%#= at the start of the pattern
|
||||||
|
for i in range(0, 2)
|
||||||
|
call cursor(i + 1, 7)
|
||||||
|
exe ":%s/\\%#=" .. i .. "foobar=" .. i .. "/xx"
|
||||||
|
endfor
|
||||||
|
call assert_equal(['xx', 'xx', 'xx'], getline(1, '$'))
|
||||||
|
bwipe!
|
||||||
|
endfunc
|
||||||
|
|
||||||
func Test_recursive_substitute_expr()
|
func Test_recursive_substitute_expr()
|
||||||
new
|
new
|
||||||
func Repl()
|
func Repl()
|
||||||
|
Reference in New Issue
Block a user