Skip to content

Commit edaad6e

Browse files
committed
patch 8.1.2207: "gn" doesn't work quite right
Problem: "gn" doesn't work quite right. (Jaehwang Jerry Jung) Solution: Improve and simplify the search logic. (Christian Brabandt, closes #5103, closes #5075)
1 parent 2868668 commit edaad6e

3 files changed

Lines changed: 101 additions & 92 deletions

File tree

src/search.c

Lines changed: 78 additions & 92 deletions
Original file line numberDiff line numberDiff line change
@@ -4676,7 +4676,73 @@ current_quote(
46764676

46774677
#endif /* FEAT_TEXTOBJ */
46784678

4679-
static int is_one_char(char_u *pattern, int move, pos_T *cur, int direction);
4679+
/*
4680+
* Check if the pattern is one character long or zero-width.
4681+
* If move is TRUE, check from the beginning of the buffer, else from position
4682+
* "cur".
4683+
* "direction" is FORWARD or BACKWARD.
4684+
* Returns TRUE, FALSE or -1 for failure.
4685+
*/
4686+
static int
4687+
is_zero_width(char_u *pattern, int move, pos_T *cur, int direction)
4688+
{
4689+
regmmatch_T regmatch;
4690+
int nmatched = 0;
4691+
int result = -1;
4692+
pos_T pos;
4693+
int save_called_emsg = called_emsg;
4694+
int flag = 0;
4695+
4696+
if (pattern == NULL)
4697+
pattern = spats[last_idx].pat;
4698+
4699+
if (search_regcomp(pattern, RE_SEARCH, RE_SEARCH,
4700+
SEARCH_KEEP, &regmatch) == FAIL)
4701+
return -1;
4702+
4703+
// init startcol correctly
4704+
regmatch.startpos[0].col = -1;
4705+
// move to match
4706+
if (move)
4707+
{
4708+
CLEAR_POS(&pos);
4709+
}
4710+
else
4711+
{
4712+
pos = *cur;
4713+
// accept a match at the cursor position
4714+
flag = SEARCH_START;
4715+
}
4716+
4717+
if (searchit(curwin, curbuf, &pos, NULL, direction, pattern, 1,
4718+
SEARCH_KEEP + flag, RE_SEARCH, NULL) != FAIL)
4719+
{
4720+
// Zero-width pattern should match somewhere, then we can check if
4721+
// start and end are in the same position.
4722+
called_emsg = FALSE;
4723+
do
4724+
{
4725+
regmatch.startpos[0].col++;
4726+
nmatched = vim_regexec_multi(&regmatch, curwin, curbuf,
4727+
pos.lnum, regmatch.startpos[0].col, NULL, NULL);
4728+
if (nmatched != 0)
4729+
break;
4730+
} while (direction == FORWARD ? regmatch.startpos[0].col < pos.col
4731+
: regmatch.startpos[0].col > pos.col);
4732+
4733+
if (!called_emsg)
4734+
{
4735+
result = (nmatched != 0
4736+
&& regmatch.startpos[0].lnum == regmatch.endpos[0].lnum
4737+
&& regmatch.startpos[0].col == regmatch.endpos[0].col);
4738+
}
4739+
}
4740+
4741+
called_emsg |= save_called_emsg;
4742+
vim_regfree(regmatch.regprog);
4743+
return result;
4744+
}
4745+
46804746

46814747
/*
46824748
* Find next search match under cursor, cursor at end.
@@ -4697,7 +4763,7 @@ current_search(
46974763
char_u old_p_ws = p_ws;
46984764
int flags = 0;
46994765
pos_T save_VIsual = VIsual;
4700-
int one_char;
4766+
int zero_width;
47014767

47024768
/* wrapping should not occur */
47034769
p_ws = FALSE;
@@ -4706,29 +4772,20 @@ current_search(
47064772
if (VIsual_active && *p_sel == 'e' && LT_POS(VIsual, curwin->w_cursor))
47074773
dec_cursor();
47084774

4775+
orig_pos = pos = curwin->w_cursor;
47094776
if (VIsual_active)
47104777
{
4711-
orig_pos = curwin->w_cursor;
4712-
4713-
pos = curwin->w_cursor;
4714-
4715-
/* make sure, searching further will extend the match */
4716-
if (VIsual_active)
4717-
{
4718-
if (forward)
4719-
incl(&pos);
4720-
else
4721-
decl(&pos);
4722-
}
4778+
if (forward)
4779+
incl(&pos);
4780+
else
4781+
decl(&pos);
47234782
}
4724-
else
4725-
orig_pos = pos = curwin->w_cursor;
47264783

47274784
/* Is the pattern is zero-width?, this time, don't care about the direction
47284785
*/
4729-
one_char = is_one_char(spats[last_idx].pat, TRUE, &curwin->w_cursor,
4786+
zero_width = is_zero_width(spats[last_idx].pat, TRUE, &curwin->w_cursor,
47304787
FORWARD);
4731-
if (one_char == -1)
4788+
if (zero_width == -1)
47324789
{
47334790
p_ws = old_p_ws;
47344791
return FAIL; /* pattern not found */
@@ -4747,7 +4804,7 @@ current_search(
47474804
dir = !i;
47484805

47494806
flags = 0;
4750-
if (!dir && !one_char)
4807+
if (!dir && !zero_width)
47514808
flags = SEARCH_END;
47524809
end_pos = pos;
47534810

@@ -4784,7 +4841,6 @@ current_search(
47844841
ml_get(curwin->w_buffer->b_ml.ml_line_count));
47854842
}
47864843
}
4787-
p_ws = old_p_ws;
47884844
}
47894845

47904846
start_pos = pos;
@@ -4797,10 +4853,11 @@ current_search(
47974853
curwin->w_cursor = end_pos;
47984854
if (LT_POS(VIsual, end_pos))
47994855
dec_cursor();
4856+
else if (VIsual_active && LT_POS(curwin->w_cursor, VIsual))
4857+
curwin->w_cursor = pos; // put the cursor on the start of the match
48004858
VIsual_active = TRUE;
48014859
VIsual_mode = 'v';
48024860

4803-
redraw_curbuf_later(INVERTED); /* update the inversion */
48044861
if (*p_sel == 'e')
48054862
{
48064863
/* Correction for exclusive selection depends on the direction. */
@@ -4828,77 +4885,6 @@ current_search(
48284885
return OK;
48294886
}
48304887

4831-
/*
4832-
* Check if the pattern is one character long or zero-width.
4833-
* If move is TRUE, check from the beginning of the buffer, else from position
4834-
* "cur".
4835-
* "direction" is FORWARD or BACKWARD.
4836-
* Returns TRUE, FALSE or -1 for failure.
4837-
*/
4838-
static int
4839-
is_one_char(char_u *pattern, int move, pos_T *cur, int direction)
4840-
{
4841-
regmmatch_T regmatch;
4842-
int nmatched = 0;
4843-
int result = -1;
4844-
pos_T pos;
4845-
int save_called_emsg = called_emsg;
4846-
int flag = 0;
4847-
4848-
if (pattern == NULL)
4849-
pattern = spats[last_idx].pat;
4850-
4851-
if (search_regcomp(pattern, RE_SEARCH, RE_SEARCH,
4852-
SEARCH_KEEP, &regmatch) == FAIL)
4853-
return -1;
4854-
4855-
/* init startcol correctly */
4856-
regmatch.startpos[0].col = -1;
4857-
/* move to match */
4858-
if (move)
4859-
{
4860-
CLEAR_POS(&pos);
4861-
}
4862-
else
4863-
{
4864-
pos = *cur;
4865-
/* accept a match at the cursor position */
4866-
flag = SEARCH_START;
4867-
}
4868-
4869-
if (searchit(curwin, curbuf, &pos, NULL, direction, pattern, 1,
4870-
SEARCH_KEEP + flag, RE_SEARCH, NULL) != FAIL)
4871-
{
4872-
/* Zero-width pattern should match somewhere, then we can check if
4873-
* start and end are in the same position. */
4874-
called_emsg = FALSE;
4875-
do
4876-
{
4877-
regmatch.startpos[0].col++;
4878-
nmatched = vim_regexec_multi(&regmatch, curwin, curbuf,
4879-
pos.lnum, regmatch.startpos[0].col, NULL, NULL);
4880-
if (nmatched != 0)
4881-
break;
4882-
} while (direction == FORWARD ? regmatch.startpos[0].col < pos.col
4883-
: regmatch.startpos[0].col > pos.col);
4884-
4885-
if (!called_emsg)
4886-
{
4887-
result = (nmatched != 0
4888-
&& regmatch.startpos[0].lnum == regmatch.endpos[0].lnum
4889-
&& regmatch.startpos[0].col == regmatch.endpos[0].col);
4890-
// one char width
4891-
if (!result && nmatched != 0
4892-
&& inc(&pos) >= 0 && pos.col == regmatch.endpos[0].col)
4893-
result = TRUE;
4894-
}
4895-
}
4896-
4897-
called_emsg |= save_called_emsg;
4898-
vim_regfree(regmatch.regprog);
4899-
return result;
4900-
}
4901-
49024888
#if defined(FEAT_LISP) || defined(FEAT_CINDENT) || defined(FEAT_TEXTOBJ) \
49034889
|| defined(PROTO)
49044890
/*

src/testdir/test_gn.vim

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -128,6 +128,27 @@ func Test_gn_command()
128128
call assert_equal([' nnoremap', '', 'match'], getline(1,'$'))
129129
sil! %d_
130130

131+
" make sure it works correctly for one-char wide search items
132+
call setline('.', ['abcdefghi'])
133+
let @/ = 'a'
134+
exe "norm! 0fhvhhgNgU"
135+
call assert_equal(['ABCDEFGHi'], getline(1,'$'))
136+
call setline('.', ['abcdefghi'])
137+
let @/ = 'b'
138+
exe "norm! 0fhvhhgngU"
139+
call assert_equal(['abcdefghi'], getline(1,'$'))
140+
sil! %d _
141+
call setline('.', ['abcdefghi'])
142+
let @/ = 'f'
143+
exe "norm! 0vllgngU"
144+
call assert_equal(['ABCDEFghi'], getline(1,'$'))
145+
sil! %d _
146+
call setline('.', ['12345678'])
147+
let @/ = '5'
148+
norm! gg0f7vhhhhgnd
149+
call assert_equal(['12348'], getline(1,'$'))
150+
sil! %d _
151+
131152
set wrapscan&vim
132153
endfu
133154

src/version.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -741,6 +741,8 @@ static char *(features[]) =
741741

742742
static int included_patches[] =
743743
{ /* Add new patch number below this line */
744+
/**/
745+
2207,
744746
/**/
745747
2206,
746748
/**/

0 commit comments

Comments
 (0)