mirror of
https://github.com/vim/vim.git
synced 2025-09-23 03:43:49 -04:00
patch 8.0.1238: incremental search only shows one match
Problem: Incremental search only shows one match. Solution: When 'incsearch' and and 'hlsearch' are both set highlight all matches. (haya14busa, closes #2198)
This commit is contained in:
@@ -4447,7 +4447,17 @@ A jump table for the options with a short description can be found at |Q_op|.
|
|||||||
match may not be found. This is to avoid that Vim hangs while you
|
match may not be found. This is to avoid that Vim hangs while you
|
||||||
are typing the pattern.
|
are typing the pattern.
|
||||||
The highlighting can be set with the 'i' flag in 'highlight'.
|
The highlighting can be set with the 'i' flag in 'highlight'.
|
||||||
See also: 'hlsearch'.
|
When 'hlsearch' is on, all matched strings are highlighted too while typing
|
||||||
|
a search command. See also: 'hlsearch'.
|
||||||
|
If you don't want turn 'hlsearch' on, but want to highlight all matches
|
||||||
|
while searching, you can turn on and off 'hlsearch' with autocmd.
|
||||||
|
Example: >
|
||||||
|
augroup vimrc-incsearch-highlight
|
||||||
|
autocmd!
|
||||||
|
autocmd CmdlineEnter [/\?] :set hlsearch
|
||||||
|
autocmd CmdlineLeave [/\?] :set nohlsearch
|
||||||
|
augroup END
|
||||||
|
<
|
||||||
CTRL-L can be used to add one character from after the current match
|
CTRL-L can be used to add one character from after the current match
|
||||||
to the command line. If 'ignorecase' and 'smartcase' are set and the
|
to the command line. If 'ignorecase' and 'smartcase' are set and the
|
||||||
command line has no uppercase characters, the added character is
|
command line has no uppercase characters, the added character is
|
||||||
|
@@ -1715,8 +1715,9 @@ getcmdline(
|
|||||||
if (p_is && !cmd_silent && (firstc == '/' || firstc == '?'))
|
if (p_is && !cmd_silent && (firstc == '/' || firstc == '?'))
|
||||||
{
|
{
|
||||||
pos_T t;
|
pos_T t;
|
||||||
int search_flags = SEARCH_KEEP + SEARCH_NOOF;
|
int search_flags = SEARCH_NOOF;
|
||||||
|
|
||||||
|
save_last_search_pattern();
|
||||||
cursor_off();
|
cursor_off();
|
||||||
out_flush();
|
out_flush();
|
||||||
if (c == Ctrl_G)
|
if (c == Ctrl_G)
|
||||||
@@ -1726,6 +1727,8 @@ getcmdline(
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
t = match_start;
|
t = match_start;
|
||||||
|
if (!p_hls)
|
||||||
|
search_flags += SEARCH_KEEP;
|
||||||
++emsg_off;
|
++emsg_off;
|
||||||
i = searchit(curwin, curbuf, &t,
|
i = searchit(curwin, curbuf, &t,
|
||||||
c == Ctrl_G ? FORWARD : BACKWARD,
|
c == Ctrl_G ? FORWARD : BACKWARD,
|
||||||
@@ -1777,6 +1780,7 @@ getcmdline(
|
|||||||
# endif
|
# endif
|
||||||
old_botline = curwin->w_botline;
|
old_botline = curwin->w_botline;
|
||||||
update_screen(NOT_VALID);
|
update_screen(NOT_VALID);
|
||||||
|
restore_last_search_pattern();
|
||||||
redrawcmdline();
|
redrawcmdline();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@@ -1934,12 +1938,17 @@ cmdline_changed:
|
|||||||
}
|
}
|
||||||
incsearch_postponed = FALSE;
|
incsearch_postponed = FALSE;
|
||||||
curwin->w_cursor = search_start; /* start at old position */
|
curwin->w_cursor = search_start; /* start at old position */
|
||||||
|
save_last_search_pattern();
|
||||||
|
|
||||||
/* If there is no command line, don't do anything */
|
/* If there is no command line, don't do anything */
|
||||||
if (ccline.cmdlen == 0)
|
if (ccline.cmdlen == 0)
|
||||||
|
{
|
||||||
i = 0;
|
i = 0;
|
||||||
|
SET_NO_HLSEARCH(TRUE); /* turn off previous highlight */
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
int search_flags = SEARCH_OPT + SEARCH_NOOF + SEARCH_PEEK;
|
||||||
cursor_off(); /* so the user knows we're busy */
|
cursor_off(); /* so the user knows we're busy */
|
||||||
out_flush();
|
out_flush();
|
||||||
++emsg_off; /* So it doesn't beep if bad expr */
|
++emsg_off; /* So it doesn't beep if bad expr */
|
||||||
@@ -1947,8 +1956,10 @@ cmdline_changed:
|
|||||||
/* Set the time limit to half a second. */
|
/* Set the time limit to half a second. */
|
||||||
profile_setlimit(500L, &tm);
|
profile_setlimit(500L, &tm);
|
||||||
#endif
|
#endif
|
||||||
|
if (!p_hls)
|
||||||
|
search_flags += SEARCH_KEEP;
|
||||||
i = do_search(NULL, firstc, ccline.cmdbuff, count,
|
i = do_search(NULL, firstc, ccline.cmdbuff, count,
|
||||||
SEARCH_KEEP + SEARCH_OPT + SEARCH_NOOF + SEARCH_PEEK,
|
search_flags,
|
||||||
#ifdef FEAT_RELTIME
|
#ifdef FEAT_RELTIME
|
||||||
&tm, NULL
|
&tm, NULL
|
||||||
#else
|
#else
|
||||||
@@ -2005,6 +2016,7 @@ cmdline_changed:
|
|||||||
save_cmdline(&save_ccline);
|
save_cmdline(&save_ccline);
|
||||||
update_screen(SOME_VALID);
|
update_screen(SOME_VALID);
|
||||||
restore_cmdline(&save_ccline);
|
restore_cmdline(&save_ccline);
|
||||||
|
restore_last_search_pattern();
|
||||||
|
|
||||||
/* Leave it at the end to make CTRL-R CTRL-W work. */
|
/* Leave it at the end to make CTRL-R CTRL-W work. */
|
||||||
if (i != 0)
|
if (i != 0)
|
||||||
|
@@ -5,6 +5,8 @@ char_u *reverse_text(char_u *s);
|
|||||||
void save_re_pat(int idx, char_u *pat, int magic);
|
void save_re_pat(int idx, char_u *pat, int magic);
|
||||||
void save_search_patterns(void);
|
void save_search_patterns(void);
|
||||||
void restore_search_patterns(void);
|
void restore_search_patterns(void);
|
||||||
|
void save_last_search_pattern(void);
|
||||||
|
void restore_last_search_pattern(void);
|
||||||
void free_search_patterns(void);
|
void free_search_patterns(void);
|
||||||
int ignorecase(char_u *pat);
|
int ignorecase(char_u *pat);
|
||||||
int ignorecase_opt(char_u *pat, int ic_in, int scs);
|
int ignorecase_opt(char_u *pat, int ic_in, int scs);
|
||||||
|
41
src/search.c
41
src/search.c
@@ -100,10 +100,13 @@ static int lastc_bytelen = 1; /* >1 for multi-byte char */
|
|||||||
#if defined(FEAT_AUTOCMD) || defined(FEAT_EVAL) || defined(PROTO)
|
#if defined(FEAT_AUTOCMD) || defined(FEAT_EVAL) || defined(PROTO)
|
||||||
/* copy of spats[], for keeping the search patterns while executing autocmds */
|
/* copy of spats[], for keeping the search patterns while executing autocmds */
|
||||||
static struct spat saved_spats[2];
|
static struct spat saved_spats[2];
|
||||||
static int saved_last_idx = 0;
|
|
||||||
# ifdef FEAT_SEARCH_EXTRA
|
|
||||||
static int saved_no_hlsearch = 0;
|
|
||||||
#endif
|
#endif
|
||||||
|
# ifdef FEAT_SEARCH_EXTRA
|
||||||
|
/* copy of spats[RE_SEARCH], for keeping the search patterns while incremental
|
||||||
|
* searching */
|
||||||
|
static struct spat saved_last_search_spat;
|
||||||
|
static int saved_last_idx = 0;
|
||||||
|
static int saved_no_hlsearch = 0;
|
||||||
# endif
|
# endif
|
||||||
|
|
||||||
static char_u *mr_pattern = NULL; /* pattern used by search_regcomp() */
|
static char_u *mr_pattern = NULL; /* pattern used by search_regcomp() */
|
||||||
@@ -360,6 +363,38 @@ free_search_patterns(void)
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef FEAT_SEARCH_EXTRA
|
||||||
|
/*
|
||||||
|
* Save and restore the search pattern for incremental highlight search
|
||||||
|
* feature.
|
||||||
|
*
|
||||||
|
* It's similar but differnt from save_search_patterns() and
|
||||||
|
* restore_search_patterns(), because the search pattern must be restored when
|
||||||
|
* cannceling incremental searching even if it's called inside user functions.
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
save_last_search_pattern(void)
|
||||||
|
{
|
||||||
|
saved_last_search_spat = spats[RE_SEARCH];
|
||||||
|
if (spats[RE_SEARCH].pat != NULL)
|
||||||
|
saved_last_search_spat.pat = vim_strsave(spats[RE_SEARCH].pat);
|
||||||
|
saved_last_idx = last_idx;
|
||||||
|
saved_no_hlsearch = no_hlsearch;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
restore_last_search_pattern(void)
|
||||||
|
{
|
||||||
|
vim_free(spats[RE_SEARCH].pat);
|
||||||
|
spats[RE_SEARCH] = saved_last_search_spat;
|
||||||
|
# if defined(FEAT_EVAL)
|
||||||
|
set_vv_searchforward();
|
||||||
|
# endif
|
||||||
|
last_idx = saved_last_idx;
|
||||||
|
SET_NO_HLSEARCH(saved_no_hlsearch);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Return TRUE when case should be ignored for search pattern "pat".
|
* Return TRUE when case should be ignored for search pattern "pat".
|
||||||
* Uses the 'ignorecase' and 'smartcase' options.
|
* Uses the 'ignorecase' and 'smartcase' options.
|
||||||
|
@@ -1,5 +1,7 @@
|
|||||||
" Test for the search command
|
" Test for the search command
|
||||||
|
|
||||||
|
source shared.vim
|
||||||
|
|
||||||
func Test_search_cmdline()
|
func Test_search_cmdline()
|
||||||
if !exists('+incsearch')
|
if !exists('+incsearch')
|
||||||
return
|
return
|
||||||
@@ -431,3 +433,118 @@ func Test_search_regexp()
|
|||||||
set undolevels&
|
set undolevels&
|
||||||
enew!
|
enew!
|
||||||
endfunc
|
endfunc
|
||||||
|
|
||||||
|
func Test_search_cmdline_incsearch_highlight()
|
||||||
|
if !exists('+incsearch')
|
||||||
|
return
|
||||||
|
endif
|
||||||
|
set incsearch hlsearch
|
||||||
|
" need to disable char_avail,
|
||||||
|
" so that expansion of commandline works
|
||||||
|
call test_override("char_avail", 1)
|
||||||
|
new
|
||||||
|
call setline(1, ['aaa 1 the first', ' 2 the second', ' 3 the third'])
|
||||||
|
|
||||||
|
1
|
||||||
|
call feedkeys("/second\<cr>", 'tx')
|
||||||
|
call assert_equal('second', @/)
|
||||||
|
call assert_equal(' 2 the second', getline('.'))
|
||||||
|
|
||||||
|
" Canceling search won't change @/
|
||||||
|
1
|
||||||
|
let @/ = 'last pattern'
|
||||||
|
call feedkeys("/third\<C-c>", 'tx')
|
||||||
|
call assert_equal('last pattern', @/)
|
||||||
|
call feedkeys("/third\<Esc>", 'tx')
|
||||||
|
call assert_equal('last pattern', @/)
|
||||||
|
call feedkeys("/3\<bs>\<bs>", 'tx')
|
||||||
|
call assert_equal('last pattern', @/)
|
||||||
|
call feedkeys("/third\<c-g>\<c-t>\<Esc>", 'tx')
|
||||||
|
call assert_equal('last pattern', @/)
|
||||||
|
|
||||||
|
" clean up
|
||||||
|
set noincsearch nohlsearch
|
||||||
|
bw!
|
||||||
|
endfunc
|
||||||
|
|
||||||
|
func Test_search_cmdline_incsearch_highlight_attr()
|
||||||
|
if !exists('+incsearch') || !has('terminal') || has('gui_running')
|
||||||
|
return
|
||||||
|
endif
|
||||||
|
let h = winheight(0)
|
||||||
|
if h < 3
|
||||||
|
return
|
||||||
|
endif
|
||||||
|
let g:buf = term_start([GetVimProg(), '--clean', '-c', 'set noswapfile'], {'term_rows': 3})
|
||||||
|
|
||||||
|
" Prepare buffer text
|
||||||
|
let lines = ['abb vim vim vi', 'vimvivim']
|
||||||
|
call term_sendkeys(g:buf, 'i' . join(lines, "\n") . "\<esc>gg0")
|
||||||
|
call term_wait(g:buf, 200)
|
||||||
|
call assert_equal(lines[0], term_getline(g:buf, 1))
|
||||||
|
|
||||||
|
" Get attr of normal(a0), incsearch(a1), hlsearch(a2) highlight
|
||||||
|
call term_sendkeys(g:buf, ":set incsearch hlsearch\<cr>")
|
||||||
|
call term_sendkeys(g:buf, '/b')
|
||||||
|
call term_wait(g:buf, 200)
|
||||||
|
let screen_line1 = term_scrape(g:buf, 1)
|
||||||
|
call assert_true(len(screen_line1) > 2)
|
||||||
|
" a0: attr_normal
|
||||||
|
let a0 = screen_line1[0].attr
|
||||||
|
" a1: attr_incsearch
|
||||||
|
let a1 = screen_line1[1].attr
|
||||||
|
" a2: attr_hlsearch
|
||||||
|
let a2 = screen_line1[2].attr
|
||||||
|
call assert_notequal(a0, a1)
|
||||||
|
call assert_notequal(a0, a2)
|
||||||
|
call assert_notequal(a1, a2)
|
||||||
|
call term_sendkeys(g:buf, "\<cr>gg0")
|
||||||
|
|
||||||
|
" Test incremental highlight search
|
||||||
|
call term_sendkeys(g:buf, "/vim")
|
||||||
|
call term_wait(g:buf, 200)
|
||||||
|
" Buffer:
|
||||||
|
" abb vim vim vi
|
||||||
|
" vimvivim
|
||||||
|
" Search: /vim
|
||||||
|
let attr_line1 = [a0,a0,a0,a0,a1,a1,a1,a0,a2,a2,a2,a0,a0,a0]
|
||||||
|
let attr_line2 = [a2,a2,a2,a0,a0,a2,a2,a2]
|
||||||
|
call assert_equal(attr_line1, map(term_scrape(g:buf, 1)[:len(attr_line1)-1], 'v:val.attr'))
|
||||||
|
call assert_equal(attr_line2, map(term_scrape(g:buf, 2)[:len(attr_line2)-1], 'v:val.attr'))
|
||||||
|
|
||||||
|
" Test <C-g>
|
||||||
|
call term_sendkeys(g:buf, "\<C-g>\<C-g>")
|
||||||
|
call term_wait(g:buf, 200)
|
||||||
|
let attr_line1 = [a0,a0,a0,a0,a2,a2,a2,a0,a2,a2,a2,a0,a0,a0]
|
||||||
|
let attr_line2 = [a1,a1,a1,a0,a0,a2,a2,a2]
|
||||||
|
call assert_equal(attr_line1, map(term_scrape(g:buf, 1)[:len(attr_line1)-1], 'v:val.attr'))
|
||||||
|
call assert_equal(attr_line2, map(term_scrape(g:buf, 2)[:len(attr_line2)-1], 'v:val.attr'))
|
||||||
|
|
||||||
|
" Test <C-t>
|
||||||
|
call term_sendkeys(g:buf, "\<C-t>")
|
||||||
|
call term_wait(g:buf, 200)
|
||||||
|
let attr_line1 = [a0,a0,a0,a0,a2,a2,a2,a0,a1,a1,a1,a0,a0,a0]
|
||||||
|
let attr_line2 = [a2,a2,a2,a0,a0,a2,a2,a2]
|
||||||
|
call assert_equal(attr_line1, map(term_scrape(g:buf, 1)[:len(attr_line1)-1], 'v:val.attr'))
|
||||||
|
call assert_equal(attr_line2, map(term_scrape(g:buf, 2)[:len(attr_line2)-1], 'v:val.attr'))
|
||||||
|
|
||||||
|
" Type Enter and a1(incsearch highlight) should become a2(hlsearch highlight)
|
||||||
|
call term_sendkeys(g:buf, "\<cr>")
|
||||||
|
call term_wait(g:buf, 200)
|
||||||
|
let attr_line1 = [a0,a0,a0,a0,a2,a2,a2,a0,a2,a2,a2,a0,a0,a0]
|
||||||
|
let attr_line2 = [a2,a2,a2,a0,a0,a2,a2,a2]
|
||||||
|
call assert_equal(attr_line1, map(term_scrape(g:buf, 1)[:len(attr_line1)-1], 'v:val.attr'))
|
||||||
|
call assert_equal(attr_line2, map(term_scrape(g:buf, 2)[:len(attr_line2)-1], 'v:val.attr'))
|
||||||
|
|
||||||
|
" Test nohlsearch. a2(hlsearch highlight) should become a0(normal highlight)
|
||||||
|
call term_sendkeys(g:buf, ":1\<cr>")
|
||||||
|
call term_sendkeys(g:buf, ":set nohlsearch\<cr>")
|
||||||
|
call term_sendkeys(g:buf, "/vim")
|
||||||
|
call term_wait(g:buf, 200)
|
||||||
|
let attr_line1 = [a0,a0,a0,a0,a1,a1,a1,a0,a0,a0,a0,a0,a0,a0]
|
||||||
|
let attr_line2 = [a0,a0,a0,a0,a0,a0,a0,a0]
|
||||||
|
call assert_equal(attr_line1, map(term_scrape(g:buf, 1)[:len(attr_line1)-1], 'v:val.attr'))
|
||||||
|
call assert_equal(attr_line2, map(term_scrape(g:buf, 2)[:len(attr_line2)-1], 'v:val.attr'))
|
||||||
|
|
||||||
|
bwipe!
|
||||||
|
endfunc
|
||||||
|
@@ -761,6 +761,8 @@ static char *(features[]) =
|
|||||||
|
|
||||||
static int included_patches[] =
|
static int included_patches[] =
|
||||||
{ /* Add new patch number below this line */
|
{ /* Add new patch number below this line */
|
||||||
|
/**/
|
||||||
|
1238,
|
||||||
/**/
|
/**/
|
||||||
1237,
|
1237,
|
||||||
/**/
|
/**/
|
||||||
|
Reference in New Issue
Block a user