0
0
mirror of https://github.com/vim/vim.git synced 2025-09-24 03:44:06 -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:
Bram Moolenaar
2017-10-29 16:40:30 +01:00
parent af2d20c628
commit 2e51d9a097
6 changed files with 185 additions and 7 deletions

View File

@@ -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

View File

@@ -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)

View File

@@ -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);

View File

@@ -100,11 +100,14 @@ 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; #endif
# ifdef FEAT_SEARCH_EXTRA # 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; static int saved_no_hlsearch = 0;
# endif # endif
#endif
static char_u *mr_pattern = NULL; /* pattern used by search_regcomp() */ static char_u *mr_pattern = NULL; /* pattern used by search_regcomp() */
#ifdef FEAT_RIGHTLEFT #ifdef FEAT_RIGHTLEFT
@@ -329,9 +332,9 @@ restore_search_patterns(void)
{ {
vim_free(spats[0].pat); vim_free(spats[0].pat);
spats[0] = saved_spats[0]; spats[0] = saved_spats[0];
#if defined(FEAT_EVAL) # if defined(FEAT_EVAL)
set_vv_searchforward(); set_vv_searchforward();
#endif # endif
vim_free(spats[1].pat); vim_free(spats[1].pat);
spats[1] = saved_spats[1]; spats[1] = saved_spats[1];
last_idx = saved_last_idx; last_idx = saved_last_idx;
@@ -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.

View File

@@ -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

View File

@@ -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,
/**/ /**/