346 lines
12 KiB
Diff
346 lines
12 KiB
Diff
From 04db26b36000a4677b95403ec94bd11f6cc73975 Mon Sep 17 00:00:00 2001
|
||
From: Bram Moolenaar <Bram@vim.org>
|
||
Date: Mon, 5 Jul 2021 20:15:23 +0200
|
||
Subject: [PATCH] patch 8.2.3110: a pattern that matches the cursor position is
|
||
complicated
|
||
|
||
Problem: A pattern that matches the cursor position is bit complicated.
|
||
Solution: Use a dot to indicate the cursor line and column. (Christian
|
||
Brabandt, closes #8497, closes #8179)
|
||
---
|
||
runtime/doc/pattern.txt | 31 +++++++++--
|
||
src/globals.h | 3 ++
|
||
src/regexp_bt.c | 34 +++++++++++-
|
||
src/regexp_nfa.c | 30 ++++++++++-
|
||
src/testdir/test_regexp_latin.vim | 90 +++++++++++++++++++++++++++++++
|
||
5 files changed, 182 insertions(+), 6 deletions(-)
|
||
|
||
diff --git a/runtime/doc/pattern.txt b/runtime/doc/pattern.txt
|
||
index 7ba46e2..44fef3f 100644
|
||
--- a/runtime/doc/pattern.txt
|
||
+++ b/runtime/doc/pattern.txt
|
||
@@ -922,13 +922,20 @@ $ At end of pattern or in front of "\|", "\)" or "\n" ('magic' on):
|
||
\%23l Matches in a specific line.
|
||
\%<23l Matches above a specific line (lower line number).
|
||
\%>23l Matches below a specific line (higher line number).
|
||
+\%.l Matches at the cursor line.
|
||
+\%<.l Matches above the cursor line.
|
||
+\%>.l Matches below the cursor line.
|
||
These three 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 refering 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.
|
||
|
||
@@ -936,15 +943,23 @@ $ 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.
|
||
+\%.c Matches at the cursor column.
|
||
+\%<.c Matches before the cursor column.
|
||
+\%>.c Matches after the cursor 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 multi-byte characters).
|
||
WARNING: When inserting or deleting text Vim does not automatically
|
||
update the matches. This means Syntax highlighting quickly becomes
|
||
- wrong.
|
||
+ wrong. Also when refering 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: >
|
||
@@ -955,6 +970,9 @@ $ 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.
|
||
+\%.v Matches at the current virtual column.
|
||
+\%<.v Matches before the current virtual column.
|
||
+\%>.v Matches after the current 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
|
||
values of the current window are used (e.g., 'tabstop').
|
||
@@ -964,13 +982,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 refering 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.
|
||
diff --git a/src/globals.h b/src/globals.h
|
||
index c1bb9b2..3067cfa 100644
|
||
--- a/src/globals.h
|
||
+++ b/src/globals.h
|
||
@@ -1761,3 +1761,6 @@ EXTERN char e_illegal_character_in_word[]
|
||
|
||
EXTERN char e_command_too_recursive[]
|
||
INIT(= N_("E169: Command too recursive"));
|
||
+
|
||
+EXTERN char e_regexp_number_after_dot_pos_search[]
|
||
+ INIT(= N_("E1204: No Number allowed after .: '\\%%%c'"));
|
||
diff --git a/src/regexp_bt.c b/src/regexp_bt.c
|
||
index ff92576..58a3ae1 100644
|
||
--- a/src/regexp_bt.c
|
||
+++ b/src/regexp_bt.c
|
||
@@ -1462,14 +1462,20 @@ regatom(int *flagp)
|
||
|
||
default:
|
||
if (VIM_ISDIGIT(c) || c == '<' || c == '>'
|
||
- || c == '\'')
|
||
+ || c == '\'' || c == '.')
|
||
{
|
||
long_u n = 0;
|
||
int cmp;
|
||
+ int cur = FALSE;
|
||
|
||
cmp = c;
|
||
if (cmp == '<' || cmp == '>')
|
||
c = getchr();
|
||
+ if (no_Magic(c) == '.')
|
||
+ {
|
||
+ cur = TRUE;
|
||
+ c = getchr();
|
||
+ }
|
||
while (VIM_ISDIGIT(c))
|
||
{
|
||
n = n * 10 + (c - '0');
|
||
@@ -1491,16 +1497,42 @@ regatom(int *flagp)
|
||
}
|
||
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);
|
||
+ ++vcol;
|
||
+ n = vcol;
|
||
+ }
|
||
ret = regnode(RE_VCOL);
|
||
+ }
|
||
if (ret == JUST_CALC_SIZE)
|
||
regsize += 5;
|
||
else
|
||
diff --git a/src/regexp_nfa.c b/src/regexp_nfa.c
|
||
index a5526b1..86e0140 100644
|
||
--- a/src/regexp_nfa.c
|
||
+++ b/src/regexp_nfa.c
|
||
@@ -1544,12 +1544,23 @@ nfa_regatom(void)
|
||
{
|
||
long_u n = 0;
|
||
int cmp = c;
|
||
+ int cur = FALSE;
|
||
|
||
if (c == '<' || c == '>')
|
||
c = getchr();
|
||
+ if (no_Magic(c) == '.')
|
||
+ {
|
||
+ cur = TRUE;
|
||
+ c = getchr();
|
||
+ }
|
||
while (VIM_ISDIGIT(c))
|
||
{
|
||
- long_u tmp = n * 10 + (c - '0');
|
||
+ long_u tmp;
|
||
+
|
||
+ if (cur)
|
||
+ semsg(_(e_regexp_number_after_dot_pos_search),
|
||
+ no_Magic(c));
|
||
+ tmp = n * 10 + (c - '0');
|
||
|
||
if (tmp < n)
|
||
{
|
||
@@ -1566,6 +1577,8 @@ nfa_regatom(void)
|
||
|
||
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);
|
||
@@ -1573,11 +1586,26 @@ 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);
|
||
diff --git a/src/testdir/test_regexp_latin.vim b/src/testdir/test_regexp_latin.vim
|
||
index b668f87..9232d2a 100644
|
||
--- a/src/testdir/test_regexp_latin.vim
|
||
+++ b/src/testdir/test_regexp_latin.vim
|
||
@@ -184,3 +184,93 @@ func Test_recursive_substitute_expr()
|
||
delfunc Repl
|
||
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
|
||
--
|
||
2.33.0
|
||
|