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
|
||||
are typing the pattern.
|
||||
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
|
||||
to the command line. If 'ignorecase' and 'smartcase' are set and the
|
||||
command line has no uppercase characters, the added character is
|
||||
|
@@ -1715,8 +1715,9 @@ getcmdline(
|
||||
if (p_is && !cmd_silent && (firstc == '/' || firstc == '?'))
|
||||
{
|
||||
pos_T t;
|
||||
int search_flags = SEARCH_KEEP + SEARCH_NOOF;
|
||||
int search_flags = SEARCH_NOOF;
|
||||
|
||||
save_last_search_pattern();
|
||||
cursor_off();
|
||||
out_flush();
|
||||
if (c == Ctrl_G)
|
||||
@@ -1726,6 +1727,8 @@ getcmdline(
|
||||
}
|
||||
else
|
||||
t = match_start;
|
||||
if (!p_hls)
|
||||
search_flags += SEARCH_KEEP;
|
||||
++emsg_off;
|
||||
i = searchit(curwin, curbuf, &t,
|
||||
c == Ctrl_G ? FORWARD : BACKWARD,
|
||||
@@ -1777,6 +1780,7 @@ getcmdline(
|
||||
# endif
|
||||
old_botline = curwin->w_botline;
|
||||
update_screen(NOT_VALID);
|
||||
restore_last_search_pattern();
|
||||
redrawcmdline();
|
||||
}
|
||||
else
|
||||
@@ -1934,12 +1938,17 @@ cmdline_changed:
|
||||
}
|
||||
incsearch_postponed = FALSE;
|
||||
curwin->w_cursor = search_start; /* start at old position */
|
||||
save_last_search_pattern();
|
||||
|
||||
/* If there is no command line, don't do anything */
|
||||
if (ccline.cmdlen == 0)
|
||||
{
|
||||
i = 0;
|
||||
SET_NO_HLSEARCH(TRUE); /* turn off previous highlight */
|
||||
}
|
||||
else
|
||||
{
|
||||
int search_flags = SEARCH_OPT + SEARCH_NOOF + SEARCH_PEEK;
|
||||
cursor_off(); /* so the user knows we're busy */
|
||||
out_flush();
|
||||
++emsg_off; /* So it doesn't beep if bad expr */
|
||||
@@ -1947,8 +1956,10 @@ cmdline_changed:
|
||||
/* Set the time limit to half a second. */
|
||||
profile_setlimit(500L, &tm);
|
||||
#endif
|
||||
if (!p_hls)
|
||||
search_flags += SEARCH_KEEP;
|
||||
i = do_search(NULL, firstc, ccline.cmdbuff, count,
|
||||
SEARCH_KEEP + SEARCH_OPT + SEARCH_NOOF + SEARCH_PEEK,
|
||||
search_flags,
|
||||
#ifdef FEAT_RELTIME
|
||||
&tm, NULL
|
||||
#else
|
||||
@@ -2005,6 +2016,7 @@ cmdline_changed:
|
||||
save_cmdline(&save_ccline);
|
||||
update_screen(SOME_VALID);
|
||||
restore_cmdline(&save_ccline);
|
||||
restore_last_search_pattern();
|
||||
|
||||
/* Leave it at the end to make CTRL-R CTRL-W work. */
|
||||
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_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);
|
||||
int ignorecase(char_u *pat);
|
||||
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)
|
||||
/* copy of spats[], for keeping the search patterns while executing autocmds */
|
||||
static struct spat saved_spats[2];
|
||||
static int saved_last_idx = 0;
|
||||
# ifdef FEAT_SEARCH_EXTRA
|
||||
static int saved_no_hlsearch = 0;
|
||||
#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
|
||||
|
||||
static char_u *mr_pattern = NULL; /* pattern used by search_regcomp() */
|
||||
@@ -360,6 +363,38 @@ free_search_patterns(void)
|
||||
}
|
||||
#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".
|
||||
* Uses the 'ignorecase' and 'smartcase' options.
|
||||
|
@@ -1,5 +1,7 @@
|
||||
" Test for the search command
|
||||
|
||||
source shared.vim
|
||||
|
||||
func Test_search_cmdline()
|
||||
if !exists('+incsearch')
|
||||
return
|
||||
@@ -431,3 +433,118 @@ func Test_search_regexp()
|
||||
set undolevels&
|
||||
enew!
|
||||
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[] =
|
||||
{ /* Add new patch number below this line */
|
||||
/**/
|
||||
1238,
|
||||
/**/
|
||||
1237,
|
||||
/**/
|
||||
|
Reference in New Issue
Block a user