From 78e69412acb481c7ad56e68c541f5c5383992d5b Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Sat, 5 Nov 2022 15:51:26 +0800 Subject: vim-patch:8.2.4688: new regexp engine does not give an error for "\%v" Problem: New regexp engine does not give an error for "\%v". Solution: Check for a value argument. (issue vim/vim#10079) https://github.com/vim/vim/commit/91ff3d4f52a55a7c37a52aaad524cd9dd12efae4 Co-authored-by: Bram Moolenaar --- src/nvim/regexp.c | 28 +++++++++++++++------------- src/nvim/regexp_bt.c | 2 +- src/nvim/regexp_nfa.c | 6 +++++- src/nvim/testdir/test_regexp_latin.vim | 12 ++++++++++++ 4 files changed, 33 insertions(+), 15 deletions(-) diff --git a/src/nvim/regexp.c b/src/nvim/regexp.c index 68ffc70457..3e8724c1ef 100644 --- a/src/nvim/regexp.c +++ b/src/nvim/regexp.c @@ -97,20 +97,22 @@ static int toggle_Magic(int x) #define MAX_LIMIT (32767L << 16L) -static char_u e_missingbracket[] = N_("E769: Missing ] after %s["); -static char_u 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_u e_unmatchedpp[] = N_("E53: Unmatched %s%%("); -static char_u e_unmatchedp[] = N_("E54: Unmatched %s("); -static char_u e_unmatchedpar[] = N_("E55: Unmatched %s)"); -static char_u 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_u e_missing_sb[] = N_("E69: Missing ] after %s%%["); -static char_u e_empty_sb[] = N_("E70: Empty %s%%[]"); -static char_u e_recursive[] = N_("E956: Cannot use pattern recursively"); -static char_u e_regexp_number_after_dot_pos_search[] +static char e_missingbracket[] = N_("E769: Missing ] after %s["); +static char e_reverse_range[] = N_("E944: Reverse range in character class"); +static char e_large_class[] = N_("E945: Range too large in character class"); +static char e_unmatchedpp[] = N_("E53: Unmatched %s%%("); +static char e_unmatchedp[] = N_("E54: Unmatched %s("); +static char e_unmatchedpar[] = N_("E55: Unmatched %s)"); +static char e_z_not_allowed[] = N_("E66: \\z( not allowed here"); +static char e_z1_not_allowed[] = N_("E67: \\z1 - \\z9 not allowed here"); +static char e_missing_sb[] = N_("E69: Missing ] after %s%%["); +static char e_empty_sb[] = N_("E70: Empty %s%%[]"); +static char e_recursive[] = N_("E956: Cannot use pattern recursively"); +static char e_regexp_number_after_dot_pos_search_chr[] = 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_substitute_nesting_too_deep[] = N_("E1290: substitute nesting too deep"); #define NOT_MULTI 0 #define MULTI_ONE 1 diff --git a/src/nvim/regexp_bt.c b/src/nvim/regexp_bt.c index ac33fc0f13..bde2962d3b 100644 --- a/src/nvim/regexp_bt.c +++ b/src/nvim/regexp_bt.c @@ -2117,7 +2117,7 @@ static char_u *regatom(int *flagp) break; } else if (c == 'l' || c == 'c' || c == 'v') { 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; return NULL; } diff --git a/src/nvim/regexp_nfa.c b/src/nvim/regexp_nfa.c index fbd4e26c75..a2f4e209f1 100644 --- a/src/nvim/regexp_nfa.c +++ b/src/nvim/regexp_nfa.c @@ -2151,7 +2151,7 @@ static int nfa_regatom(void) } while (ascii_isdigit(c)) { 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; } if (n > (INT32_MAX - (c - '0')) / 10) { @@ -2165,6 +2165,10 @@ static int nfa_regatom(void) if (c == 'l' || c == 'c' || c == 'v') { int32_t limit = INT32_MAX; + if (!cur && n == 0) { + semsg(_(e_nfa_regexp_missing_value_in_chr), no_Magic(c)); + return FAIL; + } if (c == 'l') { if (cur) { n = curwin->w_cursor.lnum; diff --git a/src/nvim/testdir/test_regexp_latin.vim b/src/nvim/testdir/test_regexp_latin.vim index 2a9a0e9d50..2671313997 100644 --- a/src/nvim/testdir/test_regexp_latin.vim +++ b/src/nvim/testdir/test_regexp_latin.vim @@ -105,6 +105,18 @@ func Test_multi_failure() set re=0 endfunc +func Test_column_failure() + set re=1 + call assert_fails('/\%v', 'E71:') + call assert_fails('/\%c', 'E71:') + call assert_fails('/\%l', 'E71:') + set re=2 + call assert_fails('/\%v', 'E1273:') + call assert_fails('/\%c', 'E1273:') + call assert_fails('/\%l', 'E1273:') + set re=0 +endfunc + func Test_recursive_addstate() throw 'skipped: TODO: ' " This will call addstate() recursively until it runs into the limit. -- cgit From 77e25e56d8ccc0c174305f9fe64ad06f0223ab2d Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Sat, 5 Nov 2022 15:56:15 +0800 Subject: vim-patch:8.2.4693: new regexp does not accept pattern "\%>0v" Problem: new regexp does not accept pattern "\%>0v". Solution: Do accept digit zero. https://github.com/vim/vim/commit/72bb10df1fb3eb69bc91f5babfb8881ce098cba1 Co-authored-by: Bram Moolenaar --- src/nvim/regexp_bt.c | 4 +++- src/nvim/regexp_nfa.c | 4 +++- src/nvim/testdir/test_regexp_latin.vim | 15 ++++++++++++++- 3 files changed, 20 insertions(+), 3 deletions(-) diff --git a/src/nvim/regexp_bt.c b/src/nvim/regexp_bt.c index bde2962d3b..f0efd06cc0 100644 --- a/src/nvim/regexp_bt.c +++ b/src/nvim/regexp_bt.c @@ -2091,6 +2091,7 @@ static char_u *regatom(int *flagp) uint32_t n = 0; int cmp; bool cur = false; + bool got_digit = false; cmp = c; if (cmp == '<' || cmp == '>') { @@ -2101,6 +2102,7 @@ static char_u *regatom(int *flagp) c = getchr(); } while (ascii_isdigit(c)) { + got_digit = true; n = n * 10 + (uint32_t)(c - '0'); c = getchr(); } @@ -2115,7 +2117,7 @@ static char_u *regatom(int *flagp) *regcode++ = (char_u)cmp; } break; - } else if (c == 'l' || c == 'c' || c == 'v') { + } else if ((c == 'l' || c == 'c' || c == 'v') && (cur || got_digit)) { if (cur && n) { semsg(_(e_regexp_number_after_dot_pos_search_chr), no_Magic(c)); rc_did_emsg = true; diff --git a/src/nvim/regexp_nfa.c b/src/nvim/regexp_nfa.c index a2f4e209f1..c93164ed7e 100644 --- a/src/nvim/regexp_nfa.c +++ b/src/nvim/regexp_nfa.c @@ -2141,6 +2141,7 @@ static int nfa_regatom(void) int64_t n = 0; const int cmp = c; bool cur = false; + bool got_digit = false; if (c == '<' || c == '>') { c = getchr(); @@ -2161,11 +2162,12 @@ static int nfa_regatom(void) } n = n * 10 + (c - '0'); c = getchr(); + got_digit = true; } if (c == 'l' || c == 'c' || c == 'v') { int32_t limit = INT32_MAX; - if (!cur && n == 0) { + if (!cur && !got_digit) { semsg(_(e_nfa_regexp_missing_value_in_chr), no_Magic(c)); return FAIL; } diff --git a/src/nvim/testdir/test_regexp_latin.vim b/src/nvim/testdir/test_regexp_latin.vim index 2671313997..5312c6f26a 100644 --- a/src/nvim/testdir/test_regexp_latin.vim +++ b/src/nvim/testdir/test_regexp_latin.vim @@ -105,16 +105,29 @@ func Test_multi_failure() set re=0 endfunc -func Test_column_failure() +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('/\%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('/\% Date: Sat, 5 Nov 2022 15:59:17 +0800 Subject: vim-patch:8.2.4978: no error if engine selection atom is not at the start Problem: No error if engine selection atom is not at the start. Solution: Give an error. (Christian Brabandt, closes vim/vim#10439) https://github.com/vim/vim/commit/360da40b47a84ee8586c3b5d062f8c64a2ac9cc6 Co-authored-by: Christian Brabandt --- runtime/doc/pattern.txt | 2 +- src/nvim/regexp.c | 2 ++ src/nvim/regexp_bt.c | 5 +++++ src/nvim/regexp_nfa.c | 6 ++++++ src/nvim/testdir/test_regexp_latin.vim | 18 ++++++++++++++++++ 5 files changed, 32 insertions(+), 1 deletion(-) diff --git a/runtime/doc/pattern.txt b/runtime/doc/pattern.txt index 371a210847..5357aaa3f1 100644 --- a/runtime/doc/pattern.txt +++ b/runtime/doc/pattern.txt @@ -372,7 +372,7 @@ Vim includes two regexp engines: 1. An old, backtracking engine that supports everything. 2. A new, NFA engine that works much faster on some patterns, possibly slower on some patterns. - + *E1281* 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 prepend one of the following to the pattern: diff --git a/src/nvim/regexp.c b/src/nvim/regexp.c index 3e8724c1ef..7a96889f22 100644 --- a/src/nvim/regexp.c +++ b/src/nvim/regexp.c @@ -112,6 +112,8 @@ static char e_regexp_number_after_dot_pos_search_chr[] = N_("E1204: No Number allowed after .: '\\%%%c'"); 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 diff --git a/src/nvim/regexp_bt.c b/src/nvim/regexp_bt.c index f0efd06cc0..6f63b38a90 100644 --- a/src/nvim/regexp_bt.c +++ b/src/nvim/regexp_bt.c @@ -1971,6 +1971,11 @@ static char_u *regatom(int *flagp) break; 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); break; diff --git a/src/nvim/regexp_nfa.c b/src/nvim/regexp_nfa.c index c93164ed7e..2f4b1b98c1 100644 --- a/src/nvim/regexp_nfa.c +++ b/src/nvim/regexp_nfa.c @@ -2094,6 +2094,12 @@ static int nfa_regatom(void) break; 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); break; diff --git a/src/nvim/testdir/test_regexp_latin.vim b/src/nvim/testdir/test_regexp_latin.vim index 5312c6f26a..3a4a7ad910 100644 --- a/src/nvim/testdir/test_regexp_latin.vim +++ b/src/nvim/testdir/test_regexp_latin.vim @@ -1058,6 +1058,24 @@ func Test_using_invalid_visual_position() bwipe! 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) + call cursor( (i+1), 7) + call assert_fails("%s/foobar\\%#=" .. i, 'E1281:') + endfor + + " \%#= 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() new func Repl() -- cgit From e33ffab1a776518dbf59ba5fe82453fa019569eb Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Sat, 5 Nov 2022 16:03:00 +0800 Subject: vim-patch:9.0.0053: E1281 not tested with the old regexp engine MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Problem: E1281 not tested with the old regexp engine. Solution: Loop over the values of 'regexp'. (Dominique Pellé, closes vim/vim#10695) https://github.com/vim/vim/commit/3a393790a4fd7a5edcafbb55cd79438b6e641714 Co-authored-by: Dominique Pelle --- src/nvim/testdir/test_regexp_latin.vim | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/nvim/testdir/test_regexp_latin.vim b/src/nvim/testdir/test_regexp_latin.vim index 3a4a7ad910..ece6ae518e 100644 --- a/src/nvim/testdir/test_regexp_latin.vim +++ b/src/nvim/testdir/test_regexp_latin.vim @@ -1063,13 +1063,17 @@ func Test_using_two_engines_pattern() call setline(1, ['foobar=0', 'foobar=1', 'foobar=2']) " \%#= at the end of the pattern for i in range(0, 2) - call cursor( (i+1), 7) - call assert_fails("%s/foobar\\%#=" .. i, 'E1281:') + 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) + call cursor(i + 1, 7) exe ":%s/\\%#=" .. i .. "foobar=" .. i .. "/xx" endfor call assert_equal(['xx', 'xx', 'xx'], getline(1, '$')) -- cgit