mirror of
				https://github.com/neovim/neovim.git
				synced 2025-11-04 09:44:31 +00:00 
			
		
		
		
	Merge pull request #17773 from zeertzjq/vim-8.2.3110
vim-patch:8.2.{3110,4592}: a pattern that matches the cursor position is complicated
			
			
This commit is contained in:
		@@ -914,17 +914,24 @@ $	At end of pattern or in front of "\|", "\)" or "\n" ('magic' on):
 | 
			
		||||
	becomes invalid.  Vim doesn't automatically update the matches.
 | 
			
		||||
	Similar to moving the cursor for "\%#" |/\%#|.
 | 
			
		||||
 | 
			
		||||
						*/\%l* */\%>l* */\%<l* *E951*
 | 
			
		||||
					*/\%l* */\%>l* */\%<l* *E951* *E1204*
 | 
			
		||||
\%23l	Matches in a specific line.
 | 
			
		||||
\%<23l	Matches above a specific line (lower line number).
 | 
			
		||||
\%>23l	Matches below a specific line (higher line number).
 | 
			
		||||
	These three can be used to match specific lines in a buffer.  The "23"
 | 
			
		||||
\%.l	Matches at the cursor line.
 | 
			
		||||
\%<.l	Matches above the cursor line.
 | 
			
		||||
\%>.l	Matches below the cursor line.
 | 
			
		||||
	These six can be used to match specific lines in a buffer.  The "23"
 | 
			
		||||
	can be any line number.  The first line is 1.
 | 
			
		||||
	WARNING: When inserting or deleting lines Vim does not automatically
 | 
			
		||||
	update the matches.  This means Syntax highlighting quickly becomes
 | 
			
		||||
	wrong.
 | 
			
		||||
	wrong.  Also when referring to the cursor position (".") and
 | 
			
		||||
	the cursor moves the display isn't updated for this change.  An update
 | 
			
		||||
	is done when using the |CTRL-L| command (the whole screen is updated).
 | 
			
		||||
	Example, to highlight the line where the cursor currently is: >
 | 
			
		||||
		:exe '/\%' .. line(".") .. 'l.*'
 | 
			
		||||
		:exe '/\%' .. line(".") .. 'l'
 | 
			
		||||
<	Alternatively use: >
 | 
			
		||||
		/\%.l
 | 
			
		||||
<	When 'hlsearch' is set and you move the cursor around and make changes
 | 
			
		||||
	this will clearly show when the match is updated or not.
 | 
			
		||||
 | 
			
		||||
@@ -932,15 +939,22 @@ $	At end of pattern or in front of "\|", "\)" or "\n" ('magic' on):
 | 
			
		||||
\%23c	Matches in a specific column.
 | 
			
		||||
\%<23c	Matches before a specific column.
 | 
			
		||||
\%>23c	Matches after a specific column.
 | 
			
		||||
	These three can be used to match specific columns in a buffer or
 | 
			
		||||
	string.  The "23" can be any column number.  The first column is 1.
 | 
			
		||||
	Actually, the column is the byte number (thus it's not exactly right
 | 
			
		||||
	for multibyte characters).
 | 
			
		||||
\%.c	Matches at the cursor column.
 | 
			
		||||
\%<.c	Matches before the cursor column.
 | 
			
		||||
\%>.c	Matches after the cursor column.
 | 
			
		||||
	These six can be used to match specific columns in a buffer or string.
 | 
			
		||||
	The "23" can be any column number.  The first column is 1.  Actually,
 | 
			
		||||
	the column is the byte number (thus it's not exactly right for
 | 
			
		||||
	multibyte characters).
 | 
			
		||||
	WARNING: When inserting or deleting text Vim does not automatically
 | 
			
		||||
	update the matches.  This means Syntax highlighting quickly becomes
 | 
			
		||||
	wrong.
 | 
			
		||||
	wrong.  Also when referring to the cursor position (".") and
 | 
			
		||||
	the cursor moves the display isn't updated for this change.  An update
 | 
			
		||||
	is done when using the |CTRL-L| command (the whole screen is updated).
 | 
			
		||||
	Example, to highlight the column where the cursor currently is: >
 | 
			
		||||
		:exe '/\%' .. col(".") .. 'c'
 | 
			
		||||
<	Alternatively use: >
 | 
			
		||||
		/\%.c
 | 
			
		||||
<	When 'hlsearch' is set and you move the cursor around and make changes
 | 
			
		||||
	this will clearly show when the match is updated or not.
 | 
			
		||||
	Example for matching a single byte in column 44: >
 | 
			
		||||
@@ -951,8 +965,11 @@ $	At end of pattern or in front of "\|", "\)" or "\n" ('magic' on):
 | 
			
		||||
\%23v	Matches in a specific virtual column.
 | 
			
		||||
\%<23v	Matches before a specific virtual column.
 | 
			
		||||
\%>23v	Matches after a specific virtual column.
 | 
			
		||||
	These three can be used to match specific virtual columns in a buffer
 | 
			
		||||
	or string.  When not matching with a buffer in a window, the option
 | 
			
		||||
\%.v	Matches at the current virtual column.
 | 
			
		||||
\%<.v	Matches before the current virtual column.
 | 
			
		||||
\%>.v	Matches after the current virtual column.
 | 
			
		||||
	These six can be used to match specific virtual columns in a buffer or
 | 
			
		||||
	string.  When not matching with a buffer in a window, the option
 | 
			
		||||
	values of the current window are used (e.g., 'tabstop').
 | 
			
		||||
	The "23" can be any column number.  The first column is 1.
 | 
			
		||||
	Note that some virtual column positions will never match, because they
 | 
			
		||||
@@ -960,13 +977,18 @@ $	At end of pattern or in front of "\|", "\)" or "\n" ('magic' on):
 | 
			
		||||
	one screen character.
 | 
			
		||||
	WARNING: When inserting or deleting text Vim does not automatically
 | 
			
		||||
	update highlighted matches.  This means Syntax highlighting quickly
 | 
			
		||||
	becomes wrong.
 | 
			
		||||
	becomes wrong.  Also when referring to the cursor position (".") and
 | 
			
		||||
	the cursor moves the display isn't updated for this change.  An update
 | 
			
		||||
	is done when using the |CTRL-L| command (the whole screen is updated).
 | 
			
		||||
	Example, to highlight all the characters after virtual column 72: >
 | 
			
		||||
		/\%>72v.*
 | 
			
		||||
<	When 'hlsearch' is set and you move the cursor around and make changes
 | 
			
		||||
	this will clearly show when the match is updated or not.
 | 
			
		||||
	To match the text up to column 17: >
 | 
			
		||||
		/^.*\%17v
 | 
			
		||||
<	To match all characters after the current virtual column (where the
 | 
			
		||||
	cursor is): >
 | 
			
		||||
		/\%>.v.*
 | 
			
		||||
<	Column 17 is not included, because this is a |/zero-width| match. To
 | 
			
		||||
	include the column use: >
 | 
			
		||||
		/^.*\%17v.
 | 
			
		||||
 
 | 
			
		||||
@@ -107,8 +107,10 @@ 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_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[]
 | 
			
		||||
  = N_("E1204: No Number allowed after .: '\\%%%c'");
 | 
			
		||||
 | 
			
		||||
#define NOT_MULTI       0
 | 
			
		||||
#define MULTI_ONE       1
 | 
			
		||||
 
 | 
			
		||||
@@ -1578,14 +1578,19 @@ static char_u *regatom(int *flagp)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    default:
 | 
			
		||||
      if (ascii_isdigit(c) || c == '<' || c == '>'
 | 
			
		||||
          || c == '\'') {
 | 
			
		||||
      if (ascii_isdigit(c) || c == '<' || c == '>' || c == '\'' || c == '.') {
 | 
			
		||||
        uint32_t n = 0;
 | 
			
		||||
        int cmp;
 | 
			
		||||
        bool cur = false;
 | 
			
		||||
 | 
			
		||||
        cmp = c;
 | 
			
		||||
        if (cmp == '<' || cmp == '>')
 | 
			
		||||
        if (cmp == '<' || cmp == '>') {
 | 
			
		||||
          c = getchr();
 | 
			
		||||
        }
 | 
			
		||||
        if (no_Magic(c) == '.') {
 | 
			
		||||
          cur = true;
 | 
			
		||||
          c = getchr();
 | 
			
		||||
        }
 | 
			
		||||
        while (ascii_isdigit(c)) {
 | 
			
		||||
          n = n * 10 + (uint32_t)(c - '0');
 | 
			
		||||
          c = getchr();
 | 
			
		||||
@@ -1602,14 +1607,31 @@ 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));
 | 
			
		||||
            rc_did_emsg = true;
 | 
			
		||||
            return NULL;
 | 
			
		||||
          }
 | 
			
		||||
          if (c == 'l') {
 | 
			
		||||
            if (cur) {
 | 
			
		||||
              n = curwin->w_cursor.lnum;
 | 
			
		||||
            }
 | 
			
		||||
            ret = regnode(RE_LNUM);
 | 
			
		||||
            if (save_prev_at_start) {
 | 
			
		||||
              at_start = true;
 | 
			
		||||
            }
 | 
			
		||||
          } else if (c == 'c') {
 | 
			
		||||
            if (cur) {
 | 
			
		||||
              n = curwin->w_cursor.col;
 | 
			
		||||
              n++;
 | 
			
		||||
            }
 | 
			
		||||
            ret = regnode(RE_COL);
 | 
			
		||||
          } else {
 | 
			
		||||
            if (cur) {
 | 
			
		||||
              colnr_T vcol = 0;
 | 
			
		||||
              getvvcol(curwin, &curwin->w_cursor, NULL, NULL, &vcol);
 | 
			
		||||
              n = ++vcol;
 | 
			
		||||
            }
 | 
			
		||||
            ret = regnode(RE_VCOL);
 | 
			
		||||
          }
 | 
			
		||||
          if (ret == JUST_CALC_SIZE) {
 | 
			
		||||
 
 | 
			
		||||
@@ -1639,10 +1639,20 @@ static int nfa_regatom(void)
 | 
			
		||||
    {
 | 
			
		||||
      int64_t n = 0;
 | 
			
		||||
      const int cmp = c;
 | 
			
		||||
      bool cur = false;
 | 
			
		||||
 | 
			
		||||
      if (c == '<' || c == '>')
 | 
			
		||||
      if (c == '<' || c == '>') {
 | 
			
		||||
        c = getchr();
 | 
			
		||||
      }
 | 
			
		||||
      if (no_Magic(c) == '.') {
 | 
			
		||||
        cur = true;
 | 
			
		||||
        c = getchr();
 | 
			
		||||
      }
 | 
			
		||||
      while (ascii_isdigit(c)) {
 | 
			
		||||
        if (cur) {
 | 
			
		||||
          semsg(_(e_regexp_number_after_dot_pos_search), no_Magic(c));
 | 
			
		||||
          return FAIL;
 | 
			
		||||
        }
 | 
			
		||||
        if (n > (INT32_MAX - (c - '0')) / 10) {
 | 
			
		||||
          // overflow.
 | 
			
		||||
          emsg(_(e_value_too_large));
 | 
			
		||||
@@ -1655,6 +1665,9 @@ static int nfa_regatom(void)
 | 
			
		||||
        int32_t limit = INT32_MAX;
 | 
			
		||||
 | 
			
		||||
        if (c == 'l') {
 | 
			
		||||
          if (cur) {
 | 
			
		||||
            n = curwin->w_cursor.lnum;
 | 
			
		||||
          }
 | 
			
		||||
          // \%{n}l  \%{n}<l  \%{n}>l
 | 
			
		||||
          EMIT(cmp == '<' ? NFA_LNUM_LT :
 | 
			
		||||
               cmp == '>' ? NFA_LNUM_GT : NFA_LNUM);
 | 
			
		||||
@@ -1662,10 +1675,19 @@ static int nfa_regatom(void)
 | 
			
		||||
            at_start = true;
 | 
			
		||||
          }
 | 
			
		||||
        } else if (c == 'c') {
 | 
			
		||||
          if (cur) {
 | 
			
		||||
            n = curwin->w_cursor.col;
 | 
			
		||||
            n++;
 | 
			
		||||
          }
 | 
			
		||||
          // \%{n}c  \%{n}<c  \%{n}>c
 | 
			
		||||
          EMIT(cmp == '<' ? NFA_COL_LT :
 | 
			
		||||
               cmp == '>' ? NFA_COL_GT : NFA_COL);
 | 
			
		||||
        } else {
 | 
			
		||||
          if (cur) {
 | 
			
		||||
            colnr_T vcol = 0;
 | 
			
		||||
            getvvcol(curwin, &curwin->w_cursor, NULL, NULL, &vcol);
 | 
			
		||||
            n = ++vcol;
 | 
			
		||||
          }
 | 
			
		||||
          // \%{n}v  \%{n}<v  \%{n}>v
 | 
			
		||||
          EMIT(cmp == '<' ? NFA_VCOL_LT :
 | 
			
		||||
               cmp == '>' ? NFA_VCOL_GT : NFA_VCOL);
 | 
			
		||||
 
 | 
			
		||||
@@ -787,6 +787,96 @@ func Test_regexp_error()
 | 
			
		||||
  set re&
 | 
			
		||||
endfunc
 | 
			
		||||
 | 
			
		||||
" Check patterns matching cursor position.
 | 
			
		||||
func s:curpos_test2()
 | 
			
		||||
  new
 | 
			
		||||
  call setline(1, ['1', '2 foobar eins zwei drei vier fünf sechse',
 | 
			
		||||
        \ '3 foobar eins zwei drei vier fünf sechse',
 | 
			
		||||
        \ '4 foobar eins zwei drei vier fünf sechse',
 | 
			
		||||
        \ '5	foobar eins zwei drei vier fünf sechse',
 | 
			
		||||
        \ '6	foobar eins zwei drei vier fünf sechse',
 | 
			
		||||
        \ '7	foobar eins zwei drei vier fünf sechse'])
 | 
			
		||||
  call setpos('.', [0, 2, 10, 0])
 | 
			
		||||
  s/\%.c.*//g
 | 
			
		||||
  call setpos('.', [0, 3, 15, 0])
 | 
			
		||||
  s/\%.l.*//g
 | 
			
		||||
  call setpos('.', [0, 5, 3, 0])
 | 
			
		||||
  s/\%.v.*/_/g
 | 
			
		||||
  call assert_equal(['1',
 | 
			
		||||
        \ '2 foobar ',
 | 
			
		||||
        \ '',
 | 
			
		||||
        \ '4 foobar eins zwei drei vier fünf sechse',
 | 
			
		||||
        \ '5	_',
 | 
			
		||||
        \ '6	foobar eins zwei drei vier fünf sechse',
 | 
			
		||||
        \ '7	foobar eins zwei drei vier fünf sechse'],
 | 
			
		||||
        \ getline(1, '$'))
 | 
			
		||||
  call assert_fails('call search("\\%.1l")', 'E1204:')
 | 
			
		||||
  call assert_fails('call search("\\%.1c")', 'E1204:')
 | 
			
		||||
  call assert_fails('call search("\\%.1v")', 'E1204:')
 | 
			
		||||
  bwipe!
 | 
			
		||||
endfunc
 | 
			
		||||
 | 
			
		||||
" Check patterns matching before or after cursor position.
 | 
			
		||||
func s:curpos_test3()
 | 
			
		||||
  new
 | 
			
		||||
  call setline(1, ['1', '2 foobar eins zwei drei vier fünf sechse',
 | 
			
		||||
        \ '3 foobar eins zwei drei vier fünf sechse',
 | 
			
		||||
        \ '4 foobar eins zwei drei vier fünf sechse',
 | 
			
		||||
        \ '5	foobar eins zwei drei vier fünf sechse',
 | 
			
		||||
        \ '6	foobar eins zwei drei vier fünf sechse',
 | 
			
		||||
        \ '7	foobar eins zwei drei vier fünf sechse'])
 | 
			
		||||
  call setpos('.', [0, 2, 10, 0])
 | 
			
		||||
  " Note: This removes all columns, except for the column directly in front of
 | 
			
		||||
  " the cursor. Bug????
 | 
			
		||||
  :s/^.*\%<.c//
 | 
			
		||||
  call setpos('.', [0, 3, 10, 0])
 | 
			
		||||
  :s/\%>.c.*$//
 | 
			
		||||
  call setpos('.', [0, 5, 4, 0])
 | 
			
		||||
  " Note: This removes all columns, except for the column directly in front of
 | 
			
		||||
  " the cursor. Bug????
 | 
			
		||||
  :s/^.*\%<.v/_/
 | 
			
		||||
  call setpos('.', [0, 6, 4, 0])
 | 
			
		||||
  :s/\%>.v.*$/_/
 | 
			
		||||
  call assert_equal(['1',
 | 
			
		||||
        \ ' eins zwei drei vier fünf sechse',
 | 
			
		||||
        \ '3 foobar e',
 | 
			
		||||
        \ '4 foobar eins zwei drei vier fünf sechse',
 | 
			
		||||
        \ '_foobar eins zwei drei vier fünf sechse',
 | 
			
		||||
        \ '6	fo_',
 | 
			
		||||
        \ '7	foobar eins zwei drei vier fünf sechse'],
 | 
			
		||||
        \ getline(1, '$'))
 | 
			
		||||
  sil %d
 | 
			
		||||
  call setline(1, ['1', '2 foobar eins zwei drei vier fünf sechse',
 | 
			
		||||
        \ '3 foobar eins zwei drei vier fünf sechse',
 | 
			
		||||
        \ '4 foobar eins zwei drei vier fünf sechse',
 | 
			
		||||
        \ '5	foobar eins zwei drei vier fünf sechse',
 | 
			
		||||
        \ '6	foobar eins zwei drei vier fünf sechse',
 | 
			
		||||
        \ '7	foobar eins zwei drei vier fünf sechse'])
 | 
			
		||||
  call setpos('.', [0, 4, 4, 0])
 | 
			
		||||
  %s/\%<.l.*//
 | 
			
		||||
  call setpos('.', [0, 5, 4, 0])
 | 
			
		||||
  %s/\%>.l.*//
 | 
			
		||||
  call assert_equal(['', '', '',
 | 
			
		||||
        \ '4 foobar eins zwei drei vier fünf sechse',
 | 
			
		||||
        \ '5	foobar eins zwei drei vier fünf sechse',
 | 
			
		||||
        \ '', ''],
 | 
			
		||||
        \ getline(1, '$'))
 | 
			
		||||
  bwipe!
 | 
			
		||||
endfunc
 | 
			
		||||
 | 
			
		||||
" Test that matching below, at or after the
 | 
			
		||||
" cursor position work
 | 
			
		||||
func Test_matching_pos()
 | 
			
		||||
  for val in range(3)
 | 
			
		||||
    exe "set re=" .. val
 | 
			
		||||
    " Match at cursor position
 | 
			
		||||
    call s:curpos_test2()
 | 
			
		||||
    " Match before or after cursor position
 | 
			
		||||
    call s:curpos_test3()
 | 
			
		||||
  endfor
 | 
			
		||||
  set re&
 | 
			
		||||
endfunc
 | 
			
		||||
 | 
			
		||||
func Test_using_mark_position()
 | 
			
		||||
  " this was using freed memory
 | 
			
		||||
  " new engine
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user