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
|
|||
|
|
|