aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/nvim/regexp.c6
-rw-r--r--src/nvim/regexp_bt.c28
-rw-r--r--src/nvim/regexp_nfa.c24
-rw-r--r--src/nvim/testdir/test_regexp_latin.vim90
4 files changed, 142 insertions, 6 deletions
diff --git a/src/nvim/regexp.c b/src/nvim/regexp.c
index 009a26d4e0..d3c43e530a 100644
--- a/src/nvim/regexp.c
+++ b/src/nvim/regexp.c
@@ -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
diff --git a/src/nvim/regexp_bt.c b/src/nvim/regexp_bt.c
index 3835a2bbae..7d0b9a7a77 100644
--- a/src/nvim/regexp_bt.c
+++ b/src/nvim/regexp_bt.c
@@ -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) {
diff --git a/src/nvim/regexp_nfa.c b/src/nvim/regexp_nfa.c
index 7e316624f8..8a14a2864c 100644
--- a/src/nvim/regexp_nfa.c
+++ b/src/nvim/regexp_nfa.c
@@ -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);
diff --git a/src/nvim/testdir/test_regexp_latin.vim b/src/nvim/testdir/test_regexp_latin.vim
index cbd45696a9..b733e334de 100644
--- a/src/nvim/testdir/test_regexp_latin.vim
+++ b/src/nvim/testdir/test_regexp_latin.vim
@@ -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