]> granicus.if.org Git - vim/commitdiff
patch 8.0.1238: incremental search only shows one match v8.0.1238
authorBram Moolenaar <Bram@vim.org>
Sun, 29 Oct 2017 15:40:30 +0000 (16:40 +0100)
committerBram Moolenaar <Bram@vim.org>
Sun, 29 Oct 2017 15:40:30 +0000 (16:40 +0100)
Problem:    Incremental search only shows one match.
Solution:   When 'incsearch' and and 'hlsearch' are both set highlight all
            matches. (haya14busa, closes #2198)

runtime/doc/options.txt
src/ex_getln.c
src/proto/search.pro
src/search.c
src/testdir/test_search.vim
src/version.c

index ebe9c9262097410c69c0dc4241f7e3d15230af0b..181aa94b2dbc3220873ff2070a4e52920eed3661 100644 (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
        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
index ba6a403597dd6f41a1f5b9da7cb4399f12b14ca3..717a0122486b24e765be5b416e02ff807562af08 100644 (file)
@@ -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)
index 63955adee0d3857f9e088eb14e0db031bdeac62d..41c200612f0443c3687b6e3765f22b034c08a913 100644 (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_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);
index c3c5503095e45b03d0f93bae91fe4bb98eeb0f6b..e56cb1b41c31b066eb3472a5986fc5feb32da9c1 100644 (file)
@@ -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];
-static int         saved_last_idx = 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
-#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.
+ *
+ * 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.
index 19e631e6998d525f0d3be403128d1a947b00f00d..eb781106a909c4c20bc15d34ce52b43ce54e1ddc 100644 (file)
@@ -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
index ff69454cf8c761e3549b09a70329d97cb3754b60..7d4ba569266583053b7eedd0819877e1c9d4d4a0 100644 (file)
@@ -761,6 +761,8 @@ static char *(features[]) =
 
 static int included_patches[] =
 {   /* Add new patch number below this line */
+/**/
+    1238,
 /**/
     1237,
 /**/