Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
Vim inchlsearch
diff --git a/runtime/doc/options.txt b/runtime/doc/options.txt
index 56697d51d..b52f16bf3 100644
--- a/runtime/doc/options.txt
+++ b/runtime/doc/options.txt
@@ -4175,7 +4175,7 @@ A jump table for the options with a short description can be found at |Q_op|.
'highlight' option. This uses the "Search" highlight group by
default. Note that only the matching text is highlighted, any offsets
are not applied.
- See also: 'incsearch' and |:match|.
+ See also: 'incsearch', 'inchlsearch' and |:match|.
When you get bored looking at the highlighted matches, you can turn it
off with |:nohlsearch|. This does not change the option value, as
soon as you use a search command, the highlighting comes back.
@@ -4386,6 +4386,17 @@ A jump table for the options with a short description can be found at |Q_op|.
default now. This should work fine for most people, however if you
have any problem with it, try using on-the-spot style.
+ *'inchlsearch'* *'ihls'* *'noinchlsearch'* *'noihls'*
+'inchlsearch' 'ihls' boolean (default off)
+ global
+ {not in Vi}
+ {not available when compiled without the
+ |+extra_search| features}
+ While typing a search command, all matched strings are highlighted.
+ It works only when both 'incsearch' and 'hlsearch' are on. The type of
+ highlighting is same as highlight of 'hlsearch' and same as highlight
+ of 'incsearch' for the current match.
+
*'include'* *'inc'*
'include' 'inc' string (default "^\s*#\s*include")
global or local to buffer |global-local|
@@ -4447,7 +4458,7 @@ 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'.
+ See also: 'hlsearch' and 'inchlsearch'.
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
diff --git a/runtime/doc/quickref.txt b/runtime/doc/quickref.txt
index c4d67907e..3a3da90d3 100644
--- a/runtime/doc/quickref.txt
+++ b/runtime/doc/quickref.txt
@@ -750,6 +750,7 @@ Short explanation of each option: *option-list*
'imsearch' 'ims' use :lmap or IM when typing a search pattern
'imstatusfunc' 'imsf' function to obtain X input method status
'imstyle' 'imst' specifies the input style of the input method
+'inchlsearch' 'ihls' highlight all matches while typing search pattern
'include' 'inc' pattern to be used to find an include file
'includeexpr' 'inex' expression used to process an include line
'incsearch' 'is' highlight match while typing search pattern
diff --git a/runtime/optwin.vim b/runtime/optwin.vim
index ac7000630..3f622348d 100644
--- a/runtime/optwin.vim
+++ b/runtime/optwin.vim
@@ -409,6 +409,8 @@ call append("$", "highlight\twhich highlighting to use for various occasions")
call <SID>OptionG("hl", &hl)
call append("$", "hlsearch\thighlight all matches for the last used search pattern")
call <SID>BinOptionG("hls", &hls)
+call append("$", "inchlsearch\thighlight all matches while typing search pattern")
+call <SID>BinOptionG("ihls", &ihls)
if has("termguicolors")
call append("$", "termguicolors\tuse GUI colors for the terminal")
call <SID>BinOptionG("tgc", &tgc)
diff --git a/src/ex_getln.c b/src/ex_getln.c
index 9f7dad99a..578a7c5fd 100644
--- a/src/ex_getln.c
+++ b/src/ex_getln.c
@@ -1680,11 +1680,11 @@ getcmdline(
if (p_is && !cmd_silent && (firstc == '/' || firstc == '?'))
{
pos_T t;
- int search_flags = SEARCH_KEEP + SEARCH_NOOF
- + SEARCH_PEEK;
+ int search_flags = SEARCH_NOOF + SEARCH_PEEK;
if (char_avail())
continue;
+ save_last_search_pattern();
cursor_off();
out_flush();
if (c == Ctrl_G)
@@ -1694,6 +1694,8 @@ getcmdline(
}
else
t = match_start;
+ if (!p_ihls)
+ search_flags += SEARCH_KEEP;
++emsg_off;
i = searchit(curwin, curbuf, &t,
c == Ctrl_G ? FORWARD : BACKWARD,
@@ -1745,6 +1747,7 @@ getcmdline(
# endif
old_botline = curwin->w_botline;
update_screen(NOT_VALID);
+ restore_last_search_pattern();
redrawcmdline();
}
else
@@ -1902,12 +1905,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 */
@@ -1915,8 +1923,10 @@ cmdline_changed:
/* Set the time limit to half a second. */
profile_setlimit(500L, &tm);
#endif
+ if (!p_ihls)
+ 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
@@ -1973,6 +1983,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)
diff --git a/src/option.c b/src/option.c
index 4e2b92969..c99bc9670 100644
--- a/src/option.c
+++ b/src/option.c
@@ -1611,6 +1611,9 @@ static struct vimoption options[] =
{"incsearch", "is", P_BOOL|P_VI_DEF|P_VIM,
(char_u *)&p_is, PV_NONE,
{(char_u *)FALSE, (char_u *)0L} SCRIPTID_INIT},
+ {"inchlsearch", "ihls", P_BOOL|P_VI_DEF|P_VIM,
+ (char_u *)&p_ihls, PV_NONE,
+ {(char_u *)FALSE, (char_u *)0L} SCRIPTID_INIT},
{"indentexpr", "inde", P_STRING|P_ALLOCED|P_VI_DEF|P_VIM,
#if defined(FEAT_CINDENT) && defined(FEAT_EVAL)
(char_u *)&p_inde, PV_INDE,
diff --git a/src/option.h b/src/option.h
index ecd70dced..fee4e5dce 100644
--- a/src/option.h
+++ b/src/option.h
@@ -586,6 +586,7 @@ EXTERN int p_imcmdline; /* 'imcmdline' */
EXTERN int p_imdisable; /* 'imdisable' */
#endif
EXTERN int p_is; /* 'incsearch' */
+EXTERN int p_ihls; /* 'inchlsearch' */
EXTERN int p_im; /* 'insertmode' */
EXTERN char_u *p_isf; /* 'isfname' */
EXTERN char_u *p_isi; /* 'isident' */
diff --git a/src/proto/search.pro b/src/proto/search.pro
index 63955adee..41c200612 100644
--- a/src/proto/search.pro
+++ b/src/proto/search.pro
@@ -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);
diff --git a/src/search.c b/src/search.c
index c3c550309..5d4d6e2b8 100644
--- a/src/search.c
+++ b/src/search.c
@@ -100,11 +100,14 @@ 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];
+#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;
-# ifdef FEAT_SEARCH_EXTRA
static int saved_no_hlsearch = 0;
# endif
-#endif
static char_u *mr_pattern = NULL; /* pattern used by search_regcomp() */
#ifdef FEAT_RIGHTLEFT
@@ -329,9 +332,9 @@ restore_search_patterns(void)
{
vim_free(spats[0].pat);
spats[0] = saved_spats[0];
-#if defined(FEAT_EVAL)
+# if defined(FEAT_EVAL)
set_vv_searchforward();
-#endif
+# endif
vim_free(spats[1].pat);
spats[1] = saved_spats[1];
last_idx = saved_last_idx;
@@ -360,6 +363,38 @@ free_search_patterns(void)
}
#endif
+#ifdef FEAT_SEARCH_EXTRA
+/*
+ * Save and restore the search pattern for incremental highlight search
+ * feature ('inchlsearch').
+ *
+ * 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.
diff --git a/src/testdir/test_search.vim b/src/testdir/test_search.vim
index 5ae101f1e..433567dfe 100644
--- a/src/testdir/test_search.vim
+++ b/src/testdir/test_search.vim
@@ -412,3 +412,36 @@ func Test_search_regexp()
set undolevels&
enew!
endfunc
+
+func Test_search_cmdline_inchlsearch()
+ if !exists('+inchlsearch')
+ return
+ endif
+ set incsearch hlsearch inchlsearch
+ " 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 noinchlsearch
+ bw!
+endfunc
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.