0
0
mirror of https://github.com/vim/vim.git synced 2025-07-04 23:07:33 -04:00

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)
This commit is contained in:
Bram Moolenaar 2019-10-24 15:23:37 +02:00
parent 28686682e7
commit edaad6e0a0
3 changed files with 101 additions and 92 deletions

View File

@ -4676,7 +4676,73 @@ abort_search:
#endif /* FEAT_TEXTOBJ */
static int is_one_char(char_u *pattern, int move, pos_T *cur, int direction);
/*
* Check if the pattern is one character long or zero-width.
* If move is TRUE, check from the beginning of the buffer, else from position
* "cur".
* "direction" is FORWARD or BACKWARD.
* Returns TRUE, FALSE or -1 for failure.
*/
static int
is_zero_width(char_u *pattern, int move, pos_T *cur, int direction)
{
regmmatch_T regmatch;
int nmatched = 0;
int result = -1;
pos_T pos;
int save_called_emsg = called_emsg;
int flag = 0;
if (pattern == NULL)
pattern = spats[last_idx].pat;
if (search_regcomp(pattern, RE_SEARCH, RE_SEARCH,
SEARCH_KEEP, &regmatch) == FAIL)
return -1;
// init startcol correctly
regmatch.startpos[0].col = -1;
// move to match
if (move)
{
CLEAR_POS(&pos);
}
else
{
pos = *cur;
// accept a match at the cursor position
flag = SEARCH_START;
}
if (searchit(curwin, curbuf, &pos, NULL, direction, pattern, 1,
SEARCH_KEEP + flag, RE_SEARCH, NULL) != FAIL)
{
// Zero-width pattern should match somewhere, then we can check if
// start and end are in the same position.
called_emsg = FALSE;
do
{
regmatch.startpos[0].col++;
nmatched = vim_regexec_multi(&regmatch, curwin, curbuf,
pos.lnum, regmatch.startpos[0].col, NULL, NULL);
if (nmatched != 0)
break;
} while (direction == FORWARD ? regmatch.startpos[0].col < pos.col
: regmatch.startpos[0].col > pos.col);
if (!called_emsg)
{
result = (nmatched != 0
&& regmatch.startpos[0].lnum == regmatch.endpos[0].lnum
&& regmatch.startpos[0].col == regmatch.endpos[0].col);
}
}
called_emsg |= save_called_emsg;
vim_regfree(regmatch.regprog);
return result;
}
/*
* Find next search match under cursor, cursor at end.
@ -4697,7 +4763,7 @@ current_search(
char_u old_p_ws = p_ws;
int flags = 0;
pos_T save_VIsual = VIsual;
int one_char;
int zero_width;
/* wrapping should not occur */
p_ws = FALSE;
@ -4706,29 +4772,20 @@ current_search(
if (VIsual_active && *p_sel == 'e' && LT_POS(VIsual, curwin->w_cursor))
dec_cursor();
orig_pos = pos = curwin->w_cursor;
if (VIsual_active)
{
orig_pos = curwin->w_cursor;
pos = curwin->w_cursor;
/* make sure, searching further will extend the match */
if (VIsual_active)
{
if (forward)
incl(&pos);
else
decl(&pos);
}
if (forward)
incl(&pos);
else
decl(&pos);
}
else
orig_pos = pos = curwin->w_cursor;
/* Is the pattern is zero-width?, this time, don't care about the direction
*/
one_char = is_one_char(spats[last_idx].pat, TRUE, &curwin->w_cursor,
zero_width = is_zero_width(spats[last_idx].pat, TRUE, &curwin->w_cursor,
FORWARD);
if (one_char == -1)
if (zero_width == -1)
{
p_ws = old_p_ws;
return FAIL; /* pattern not found */
@ -4747,7 +4804,7 @@ current_search(
dir = !i;
flags = 0;
if (!dir && !one_char)
if (!dir && !zero_width)
flags = SEARCH_END;
end_pos = pos;
@ -4784,7 +4841,6 @@ current_search(
ml_get(curwin->w_buffer->b_ml.ml_line_count));
}
}
p_ws = old_p_ws;
}
start_pos = pos;
@ -4797,10 +4853,11 @@ current_search(
curwin->w_cursor = end_pos;
if (LT_POS(VIsual, end_pos))
dec_cursor();
else if (VIsual_active && LT_POS(curwin->w_cursor, VIsual))
curwin->w_cursor = pos; // put the cursor on the start of the match
VIsual_active = TRUE;
VIsual_mode = 'v';
redraw_curbuf_later(INVERTED); /* update the inversion */
if (*p_sel == 'e')
{
/* Correction for exclusive selection depends on the direction. */
@ -4828,77 +4885,6 @@ current_search(
return OK;
}
/*
* Check if the pattern is one character long or zero-width.
* If move is TRUE, check from the beginning of the buffer, else from position
* "cur".
* "direction" is FORWARD or BACKWARD.
* Returns TRUE, FALSE or -1 for failure.
*/
static int
is_one_char(char_u *pattern, int move, pos_T *cur, int direction)
{
regmmatch_T regmatch;
int nmatched = 0;
int result = -1;
pos_T pos;
int save_called_emsg = called_emsg;
int flag = 0;
if (pattern == NULL)
pattern = spats[last_idx].pat;
if (search_regcomp(pattern, RE_SEARCH, RE_SEARCH,
SEARCH_KEEP, &regmatch) == FAIL)
return -1;
/* init startcol correctly */
regmatch.startpos[0].col = -1;
/* move to match */
if (move)
{
CLEAR_POS(&pos);
}
else
{
pos = *cur;
/* accept a match at the cursor position */
flag = SEARCH_START;
}
if (searchit(curwin, curbuf, &pos, NULL, direction, pattern, 1,
SEARCH_KEEP + flag, RE_SEARCH, NULL) != FAIL)
{
/* Zero-width pattern should match somewhere, then we can check if
* start and end are in the same position. */
called_emsg = FALSE;
do
{
regmatch.startpos[0].col++;
nmatched = vim_regexec_multi(&regmatch, curwin, curbuf,
pos.lnum, regmatch.startpos[0].col, NULL, NULL);
if (nmatched != 0)
break;
} while (direction == FORWARD ? regmatch.startpos[0].col < pos.col
: regmatch.startpos[0].col > pos.col);
if (!called_emsg)
{
result = (nmatched != 0
&& regmatch.startpos[0].lnum == regmatch.endpos[0].lnum
&& regmatch.startpos[0].col == regmatch.endpos[0].col);
// one char width
if (!result && nmatched != 0
&& inc(&pos) >= 0 && pos.col == regmatch.endpos[0].col)
result = TRUE;
}
}
called_emsg |= save_called_emsg;
vim_regfree(regmatch.regprog);
return result;
}
#if defined(FEAT_LISP) || defined(FEAT_CINDENT) || defined(FEAT_TEXTOBJ) \
|| defined(PROTO)
/*

View File

@ -128,6 +128,27 @@ func Test_gn_command()
call assert_equal([' nnoremap', '', 'match'], getline(1,'$'))
sil! %d_
" make sure it works correctly for one-char wide search items
call setline('.', ['abcdefghi'])
let @/ = 'a'
exe "norm! 0fhvhhgNgU"
call assert_equal(['ABCDEFGHi'], getline(1,'$'))
call setline('.', ['abcdefghi'])
let @/ = 'b'
exe "norm! 0fhvhhgngU"
call assert_equal(['abcdefghi'], getline(1,'$'))
sil! %d _
call setline('.', ['abcdefghi'])
let @/ = 'f'
exe "norm! 0vllgngU"
call assert_equal(['ABCDEFghi'], getline(1,'$'))
sil! %d _
call setline('.', ['12345678'])
let @/ = '5'
norm! gg0f7vhhhhgnd
call assert_equal(['12348'], getline(1,'$'))
sil! %d _
set wrapscan&vim
endfu

View File

@ -741,6 +741,8 @@ static char *(features[]) =
static int included_patches[] =
{ /* Add new patch number below this line */
/**/
2207,
/**/
2206,
/**/