vim-patch:8.2.0295: highlighting for :s wrong when using different separator (#14286)

Problem:    Highlighting for :s wrong when using different separator.
Solution:   Use separat argument for search direction and separator. (Rob
            Pilling, closes vim/vim#5665)
c036e87bd7
This commit is contained in:
Ghjuvan Lacambre
2021-04-04 20:43:22 +02:00
committed by GitHub
parent 76f5c72860
commit 0f187700ab
9 changed files with 75 additions and 26 deletions

View File

@@ -3928,7 +3928,7 @@ static linenr_T get_address(exarg_T *eap,
} }
searchcmdlen = 0; searchcmdlen = 0;
flags = silent ? 0 : SEARCH_HIS | SEARCH_MSG; flags = silent ? 0 : SEARCH_HIS | SEARCH_MSG;
if (!do_search(NULL, c, cmd, 1L, flags, NULL)) { if (!do_search(NULL, c, c, cmd, 1L, flags, NULL)) {
curwin->w_cursor = pos; curwin->w_cursor = pos;
cmd = NULL; cmd = NULL;
goto error; goto error;

View File

@@ -275,8 +275,9 @@ static void init_incsearch_state(incsearch_state_T *s)
// Return true when 'incsearch' highlighting is to be done. // Return true when 'incsearch' highlighting is to be done.
// Sets search_first_line and search_last_line to the address range. // Sets search_first_line and search_last_line to the address range.
static bool do_incsearch_highlighting(int firstc, incsearch_state_T *s, static bool do_incsearch_highlighting(int firstc, int *search_delim,
int *skiplen, int *patlen) incsearch_state_T *s, int *skiplen,
int *patlen)
FUNC_ATTR_NONNULL_ALL FUNC_ATTR_NONNULL_ALL
{ {
char_u *cmd; char_u *cmd;
@@ -303,6 +304,7 @@ static bool do_incsearch_highlighting(int firstc, incsearch_state_T *s,
search_last_line = MAXLNUM; search_last_line = MAXLNUM;
if (firstc == '/' || firstc == '?') { if (firstc == '/' || firstc == '?') {
*search_delim = firstc;
return true; return true;
} }
if (firstc != ':') { if (firstc != ':') {
@@ -371,6 +373,7 @@ static bool do_incsearch_highlighting(int firstc, incsearch_state_T *s,
p = skipwhite(p); p = skipwhite(p);
delim = (delim_optional && vim_isIDc(*p)) ? ' ' : *p++; delim = (delim_optional && vim_isIDc(*p)) ? ' ' : *p++;
*search_delim = delim;
end = skip_regexp(p, delim, p_magic, NULL); end = skip_regexp(p, delim, p_magic, NULL);
use_last_pat = end == p && *end == delim; use_last_pat = end == p && *end == delim;
@@ -431,12 +434,14 @@ static void may_do_incsearch_highlighting(int firstc, long count,
int skiplen, patlen; int skiplen, patlen;
char_u next_char; char_u next_char;
char_u use_last_pat; char_u use_last_pat;
int search_delim;
// Parsing range may already set the last search pattern. // Parsing range may already set the last search pattern.
// NOTE: must call restore_last_search_pattern() before returning! // NOTE: must call restore_last_search_pattern() before returning!
save_last_search_pattern(); save_last_search_pattern();
if (!do_incsearch_highlighting(firstc, s, &skiplen, &patlen)) { if (!do_incsearch_highlighting(firstc, &search_delim, s, &skiplen,
&patlen)) {
restore_last_search_pattern(); restore_last_search_pattern();
finish_incsearch_highlighting(false, s, true); finish_incsearch_highlighting(false, s, true);
return; return;
@@ -490,7 +495,7 @@ static void may_do_incsearch_highlighting(int firstc, long count,
ccline.cmdbuff[skiplen + patlen] = NUL; ccline.cmdbuff[skiplen + patlen] = NUL;
memset(&sia, 0, sizeof(sia)); memset(&sia, 0, sizeof(sia));
sia.sa_tm = &tm; sia.sa_tm = &tm;
found = do_search(NULL, firstc == ':' ? '/' : firstc, found = do_search(NULL, firstc == ':' ? '/' : firstc, search_delim,
ccline.cmdbuff + skiplen, count, ccline.cmdbuff + skiplen, count,
search_flags, &sia); search_flags, &sia);
ccline.cmdbuff[skiplen + patlen] = next_char; ccline.cmdbuff[skiplen + patlen] = next_char;
@@ -581,13 +586,15 @@ static int may_add_char_to_search(int firstc, int *c, incsearch_state_T *s)
FUNC_ATTR_NONNULL_ALL FUNC_ATTR_NONNULL_ALL
{ {
int skiplen, patlen; int skiplen, patlen;
int search_delim;
// Parsing range may already set the last search pattern. // Parsing range may already set the last search pattern.
// NOTE: must call restore_last_search_pattern() before returning! // NOTE: must call restore_last_search_pattern() before returning!
save_last_search_pattern(); save_last_search_pattern();
// Add a character from under the cursor for 'incsearch' // Add a character from under the cursor for 'incsearch'
if (!do_incsearch_highlighting(firstc, s, &skiplen, &patlen)) { if (!do_incsearch_highlighting(firstc, &search_delim, s, &skiplen,
&patlen)) {
restore_last_search_pattern(); restore_last_search_pattern();
return FAIL; return FAIL;
} }
@@ -604,7 +611,7 @@ static int may_add_char_to_search(int firstc, int *c, incsearch_state_T *s)
&& !pat_has_uppercase(ccline.cmdbuff + skiplen)) { && !pat_has_uppercase(ccline.cmdbuff + skiplen)) {
*c = mb_tolower(*c); *c = mb_tolower(*c);
} }
if (*c == firstc if (*c == search_delim
|| vim_strchr((char_u *)(p_magic ? "\\~^$.*[" : "\\^$"), *c) || vim_strchr((char_u *)(p_magic ? "\\~^$.*[" : "\\^$"), *c)
!= NULL) { != NULL) {
// put a backslash before special characters // put a backslash before special characters
@@ -1465,13 +1472,14 @@ static int may_do_command_line_next_incsearch(int firstc, long count,
bool next_match) bool next_match)
FUNC_ATTR_NONNULL_ALL FUNC_ATTR_NONNULL_ALL
{ {
int skiplen, patlen; int skiplen, patlen, search_delim;
// Parsing range may already set the last search pattern. // Parsing range may already set the last search pattern.
// NOTE: must call restore_last_search_pattern() before returning! // NOTE: must call restore_last_search_pattern() before returning!
save_last_search_pattern(); save_last_search_pattern();
if (!do_incsearch_highlighting(firstc, s, &skiplen, &patlen)) { if (!do_incsearch_highlighting(firstc, &search_delim, s, &skiplen,
&patlen)) {
restore_last_search_pattern(); restore_last_search_pattern();
return OK; return OK;
} }
@@ -1489,7 +1497,7 @@ static int may_do_command_line_next_incsearch(int firstc, long count,
char_u save; char_u save;
if (firstc == ccline.cmdbuff[skiplen]) { if (search_delim == ccline.cmdbuff[skiplen]) {
pat = last_search_pattern(); pat = last_search_pattern();
skiplen = 0; skiplen = 0;
patlen = (int)STRLEN(pat); patlen = (int)STRLEN(pat);

View File

@@ -5459,7 +5459,7 @@ static int normal_search(
curwin->w_set_curswant = true; curwin->w_set_curswant = true;
memset(&sia, 0, sizeof(sia)); memset(&sia, 0, sizeof(sia));
i = do_search(cap->oap, dir, pat, cap->count1, i = do_search(cap->oap, dir, dir, pat, cap->count1,
opt | SEARCH_OPT | SEARCH_ECHO | SEARCH_MSG, &sia); opt | SEARCH_OPT | SEARCH_ECHO | SEARCH_MSG, &sia);
if (wrapped != NULL) { if (wrapped != NULL) {
*wrapped = sia.sa_wrapped; *wrapped = sia.sa_wrapped;

View File

@@ -2798,7 +2798,7 @@ static void qf_jump_goto_line(linenr_T qf_lnum, int qf_col, char_u qf_viscol,
// Move the cursor to the first line in the buffer // Move the cursor to the first line in the buffer
pos_T save_cursor = curwin->w_cursor; pos_T save_cursor = curwin->w_cursor;
curwin->w_cursor.lnum = 0; curwin->w_cursor.lnum = 0;
if (!do_search(NULL, '/', qf_pattern, (long)1, SEARCH_KEEP, NULL)) { if (!do_search(NULL, '/', '/', qf_pattern, (long)1, SEARCH_KEEP, NULL)) {
curwin->w_cursor = save_cursor; curwin->w_cursor = save_cursor;
} }
} }

View File

@@ -1021,8 +1021,9 @@ static int first_submatch(regmmatch_T *rp)
* Return 0 for failure, 1 for found, 2 for found and line offset added. * Return 0 for failure, 1 for found, 2 for found and line offset added.
*/ */
int do_search( int do_search(
oparg_T *oap, /* can be NULL */ oparg_T *oap, // can be NULL
int dirc, /* '/' or '?' */ int dirc, // '/' or '?'
int search_delim, // delimiter for search, e.g. '%' in s%regex%replacement
char_u *pat, char_u *pat,
long count, long count,
int options, int options,
@@ -1101,8 +1102,8 @@ int do_search(
searchstr = pat; searchstr = pat;
dircp = NULL; dircp = NULL;
/* use previous pattern */ // use previous pattern
if (pat == NULL || *pat == NUL || *pat == dirc) { if (pat == NULL || *pat == NUL || *pat == search_delim) {
if (spats[RE_SEARCH].pat == NULL) { // no previous pattern if (spats[RE_SEARCH].pat == NULL) { // no previous pattern
searchstr = spats[RE_SUBST].pat; searchstr = spats[RE_SUBST].pat;
if (searchstr == NULL) { if (searchstr == NULL) {
@@ -1122,15 +1123,15 @@ int do_search(
* If there is a matching '/' or '?', toss it. * If there is a matching '/' or '?', toss it.
*/ */
ps = strcopy; ps = strcopy;
p = skip_regexp(pat, dirc, p_magic, &strcopy); p = skip_regexp(pat, search_delim, p_magic, &strcopy);
if (strcopy != ps) { if (strcopy != ps) {
/* made a copy of "pat" to change "\?" to "?" */ /* made a copy of "pat" to change "\?" to "?" */
searchcmdlen += (int)(STRLEN(pat) - STRLEN(strcopy)); searchcmdlen += (int)(STRLEN(pat) - STRLEN(strcopy));
pat = strcopy; pat = strcopy;
searchstr = strcopy; searchstr = strcopy;
} }
if (*p == dirc) { if (*p == search_delim) {
dircp = p; /* remember where we put the NUL */ dircp = p; // remember where we put the NUL
*p++ = NUL; *p++ = NUL;
} }
spats[0].off.line = FALSE; spats[0].off.line = FALSE;
@@ -1320,7 +1321,7 @@ int do_search(
RE_LAST, sia); RE_LAST, sia);
if (dircp != NULL) { if (dircp != NULL) {
*dircp = dirc; // restore second '/' or '?' for normal_cmd() *dircp = search_delim; // restore second '/' or '?' for normal_cmd()
} }
if (!shortmess(SHM_SEARCH) if (!shortmess(SHM_SEARCH)
@@ -1400,6 +1401,7 @@ int do_search(
} }
dirc = *++pat; dirc = *++pat;
search_delim = dirc;
if (dirc != '?' && dirc != '/') { if (dirc != '?' && dirc != '/') {
retval = 0; retval = 0;
EMSG(_("E386: Expected '?' or '/' after ';'")); EMSG(_("E386: Expected '?' or '/' after ';'"));

View File

@@ -3035,7 +3035,7 @@ void ex_spellrepall(exarg_T *eap)
sub_nlines = 0; sub_nlines = 0;
curwin->w_cursor.lnum = 0; curwin->w_cursor.lnum = 0;
while (!got_int) { while (!got_int) {
if (do_search(NULL, '/', frompat, 1L, SEARCH_KEEP, NULL) == 0 if (do_search(NULL, '/', '/', frompat, 1L, SEARCH_KEEP, NULL) == 0
|| u_save_cursor() == FAIL) { || u_save_cursor() == FAIL) {
break; break;
} }

View File

@@ -2811,7 +2811,7 @@ static int jumpto_tag(
// start search before first line // start search before first line
curwin->w_cursor.lnum = 0; curwin->w_cursor.lnum = 0;
} }
if (do_search(NULL, pbuf[0], pbuf + 1, (long)1, if (do_search(NULL, pbuf[0], pbuf[0], pbuf + 1, (long)1,
search_options, NULL)) { search_options, NULL)) {
retval = OK; retval = OK;
} else { } else {
@@ -2821,8 +2821,8 @@ static int jumpto_tag(
/* /*
* try again, ignore case now * try again, ignore case now
*/ */
p_ic = TRUE; p_ic = true;
if (!do_search(NULL, pbuf[0], pbuf + 1, (long)1, if (!do_search(NULL, pbuf[0], pbuf[0], pbuf + 1, (long)1,
search_options, NULL)) { search_options, NULL)) {
// Failed to find pattern, take a guess: "^func (" // Failed to find pattern, take a guess: "^func ("
found = 2; found = 2;
@@ -2830,11 +2830,12 @@ static int jumpto_tag(
cc = *tagp.tagname_end; cc = *tagp.tagname_end;
*tagp.tagname_end = NUL; *tagp.tagname_end = NUL;
snprintf((char *)pbuf, LSIZE, "^%s\\s\\*(", tagp.tagname); snprintf((char *)pbuf, LSIZE, "^%s\\s\\*(", tagp.tagname);
if (!do_search(NULL, '/', pbuf, (long)1, search_options, NULL)) { if (!do_search(NULL, '/', '/', pbuf, (long)1, search_options, NULL)) {
// Guess again: "^char * \<func (" // Guess again: "^char * \<func ("
snprintf((char *)pbuf, LSIZE, "^\\[#a-zA-Z_]\\.\\*\\<%s\\s\\*(", snprintf((char *)pbuf, LSIZE, "^\\[#a-zA-Z_]\\.\\*\\<%s\\s\\*(",
tagp.tagname); tagp.tagname);
if (!do_search(NULL, '/', pbuf, (long)1, search_options, NULL)) { if (!do_search(NULL, '/', '/', pbuf, (long)1,
search_options, NULL)) {
found = 0; found = 0;
} }
} }

View File

@@ -723,6 +723,30 @@ func Test_incsearch_substitute_dump()
call delete('Xis_subst_script') call delete('Xis_subst_script')
endfunc endfunc
func Test_incsearch_highlighting()
if !exists('+incsearch')
return
endif
if !CanRunVimInTerminal()
throw 'Skipped: cannot make screendumps'
endif
call writefile([
\ 'set incsearch hlsearch',
\ 'call setline(1, "hello/there")',
\ ], 'Xis_subst_hl_script')
let buf = RunVimInTerminal('-S Xis_subst_hl_script', {'rows': 4, 'cols': 20})
" Give Vim a chance to redraw to get rid of the spaces in line 2 caused by
" the 'ambiwidth' check.
sleep 300m
" Using a different search delimiter should still highlight matches
" that contain a '/'.
call term_sendkeys(buf, ":%s;ello/the")
call VerifyScreenDump(buf, 'Test_incsearch_substitute_15', {})
call term_sendkeys(buf, "<Esc>")
endfunc
" Similar to Test_incsearch_substitute_dump() for :sort " Similar to Test_incsearch_substitute_dump() for :sort
func Test_incsearch_sort_dump() func Test_incsearch_sort_dump()
if !exists('+incsearch') if !exists('+incsearch')

View File

@@ -507,7 +507,21 @@ describe('search highlighting', function()
{1:~ }| {1:~ }|
:syntax keyword MyGroup special | :syntax keyword MyGroup special |
]]) ]])
end)
it('highlights entire pattern on :%g@a/b', function()
command('set inccommand=nosplit')
feed('ia/b/c<Esc>')
feed(':%g@a/b')
screen:expect([[
{3:a/b}/c |
{1:~ }|
{1:~ }|
{1:~ }|
{1:~ }|
{1:~ }|
:%g@a/b^ |
]])
end) end)
end) end)