diff options
author | Justin M. Keyes <justinkz@gmail.com> | 2018-02-01 23:25:55 +0100 |
---|---|---|
committer | Justin M. Keyes <justinkz@gmail.com> | 2018-02-01 23:25:55 +0100 |
commit | 709a87d194971f187442caa2e551c781aba38d50 (patch) | |
tree | c7fc053abd52b0d4de1e93577557546555c1a488 | |
parent | 6710164c2c44335a916a728cc8eb329c69d155f4 (diff) | |
parent | 87e03c2b85cef0b31eee5aab5078cd6457dd3c9b (diff) | |
download | rneovim-709a87d194971f187442caa2e551c781aba38d50.tar.gz rneovim-709a87d194971f187442caa2e551c781aba38d50.tar.bz2 rneovim-709a87d194971f187442caa2e551c781aba38d50.zip |
Merge #7463 'incsearch + hlsearch highlight all'
-rw-r--r-- | runtime/doc/options.txt | 12 | ||||
-rw-r--r-- | src/nvim/ex_getln.c | 64 | ||||
-rw-r--r-- | src/nvim/search.c | 33 | ||||
-rw-r--r-- | src/nvim/version.c | 10 | ||||
-rw-r--r-- | test/functional/ui/searchhl_spec.lua | 129 |
5 files changed, 230 insertions, 18 deletions
diff --git a/runtime/doc/options.txt b/runtime/doc/options.txt index ded9f7667a..6a36202177 100644 --- a/runtime/doc/options.txt +++ b/runtime/doc/options.txt @@ -3299,7 +3299,17 @@ A jump table for the options with a short description can be found at |Q_op|. pattern and/or a lot of text the match may not be found. This is to avoid that Vim hangs while you are typing the pattern. The |hl-IncSearch| highlight group determines the highlighting. - 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 diff --git a/src/nvim/ex_getln.c b/src/nvim/ex_getln.c index c4e0827dad..ba51f18518 100644 --- a/src/nvim/ex_getln.c +++ b/src/nvim/ex_getln.c @@ -426,7 +426,7 @@ static uint8_t *command_line_enter(int firstc, long count, int indent) curwin->w_botline = s->old_botline; highlight_match = false; validate_cursor(); // needed for TAB - redraw_later(SOME_VALID); + redraw_all_later(SOME_VALID); } if (ccline.cmdbuff != NULL) { @@ -1019,17 +1019,36 @@ static void command_line_next_incsearch(CommandLineState *s, bool next_match) ui_flush(); pos_T t; - int search_flags = SEARCH_KEEP + SEARCH_NOOF + SEARCH_PEEK; + char_u *pat; + int search_flags = SEARCH_NOOF; + + + if (s->firstc == ccline.cmdbuff[0]) { + pat = last_search_pattern(); + } else { + pat = ccline.cmdbuff; + } + + save_last_search_pattern(); + if (next_match) { t = s->match_end; + if (lt(s->match_start, s->match_end)) { + // start searching at the end of the match + // not at the beginning of the next column + (void)decl(&t); + } search_flags += SEARCH_COL; } else { t = s->match_start; } + if (!p_hls) { + search_flags += SEARCH_KEEP; + } emsg_off++; s->i = searchit(curwin, curbuf, &t, next_match ? FORWARD : BACKWARD, - ccline.cmdbuff, s->count, search_flags, + pat, s->count, search_flags, RE_SEARCH, 0, NULL); emsg_off--; ui_busy_stop(); @@ -1070,6 +1089,7 @@ static void command_line_next_incsearch(CommandLineState *s, bool next_match) } else { vim_beep(BO_ERROR); } + restore_last_search_pattern(); return; } @@ -1656,7 +1676,9 @@ static int command_line_handle_key(CommandLineState *s) if (char_avail()) { return 1; } - command_line_next_incsearch(s, s->c == Ctrl_G); + if (ccline.cmdlen != 0) { + command_line_next_incsearch(s, s->c == Ctrl_G); + } return command_line_not_changed(s); } break; @@ -1759,6 +1781,20 @@ static int command_line_not_changed(CommandLineState *s) return command_line_changed(s); } +/// Guess that the pattern matches everything. Only finds specific cases, such +/// as a trailing \|, which can happen while typing a pattern. +static int empty_pattern(char_u *p) +{ + int n = STRLEN(p); + + // remove trailing \v and the like + while (n >= 2 && p[n - 2] == '\\' + && vim_strchr((char_u *)"mMvVcCZ", p[n - 1]) != NULL) { + n -= 2; + } + return n == 0 || (n >= 2 && p[n - 2] == '\\' && p[n - 1] == '|'); +} + static int command_line_changed(CommandLineState *s) { // 'incsearch' highlighting. @@ -1773,20 +1809,27 @@ static int command_line_changed(CommandLineState *s) } s->incsearch_postponed = false; curwin->w_cursor = s->search_start; // start at old position + save_last_search_pattern(); // If there is no command line, don't do anything if (ccline.cmdlen == 0) { s->i = 0; + SET_NO_HLSEARCH(true); // turn off previous highlight + redraw_all_later(SOME_VALID); } else { + int search_flags = SEARCH_OPT + SEARCH_NOOF + SEARCH_PEEK; ui_busy_start(); ui_flush(); ++emsg_off; // So it doesn't beep if bad expr // Set the time limit to half a second. tm = profile_setlimit(500L); + if (!p_hls) { + search_flags += SEARCH_KEEP; + } s->i = do_search(NULL, s->firstc, ccline.cmdbuff, s->count, - SEARCH_KEEP + SEARCH_OPT + SEARCH_NOOF + SEARCH_PEEK, - &tm); - --emsg_off; + search_flags, + &tm); + emsg_off--; // if interrupted while searching, behave like it failed if (got_int) { (void)vpeekc(); // remove <C-C> from input stream @@ -1827,6 +1870,12 @@ static int command_line_changed(CommandLineState *s) end_pos = curwin->w_cursor; // shutup gcc 4 } + // Disable 'hlsearch' highlighting if the pattern matches + // everything. Avoids a flash when typing "foo\|". + if (empty_pattern(ccline.cmdbuff)) { + SET_NO_HLSEARCH(true); + } + validate_cursor(); // May redraw the status line to show the cursor position. if (p_ru && curwin->w_status_height > 0) { @@ -1836,6 +1885,7 @@ static int command_line_changed(CommandLineState *s) save_cmdline(&s->save_ccline); update_screen(SOME_VALID); restore_cmdline(&s->save_ccline); + restore_last_search_pattern(); // Leave it at the end to make CTRL-R CTRL-W work. if (s->i != 0) { diff --git a/src/nvim/search.c b/src/nvim/search.c index 6e56f5f25d..bbcac45369 100644 --- a/src/nvim/search.c +++ b/src/nvim/search.c @@ -96,6 +96,9 @@ static int lastc_bytelen = 1; /* >1 for multi-byte char */ /* copy of spats[], for keeping the search patterns while executing autocmds */ static struct spat saved_spats[2]; +// 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; @@ -305,6 +308,36 @@ void free_search_patterns(void) #endif +/// Save and restore the search pattern for incremental highlight search +/// feature. +/// +/// It's similar but different from save_search_patterns() and +/// restore_search_patterns(), because the search pattern must be restored when +/// cancelling 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) +{ + xfree(spats[RE_SEARCH].pat); + spats[RE_SEARCH] = saved_last_search_spat; + set_vv_searchforward(); + last_idx = saved_last_idx; + SET_NO_HLSEARCH(saved_no_hlsearch); +} + +char_u *last_search_pattern(void) +{ + return spats[RE_SEARCH].pat; +} + /* * Return TRUE when case should be ignored for search pattern "pat". * Uses the 'ignorecase' and 'smartcase' options. diff --git a/src/nvim/version.c b/src/nvim/version.c index da08a029b4..c95be072cf 100644 --- a/src/nvim/version.c +++ b/src/nvim/version.c @@ -101,10 +101,10 @@ static const int included_patches[] = { // 1399, // 1398, // 1397, - // 1396, + 1396, // 1395, // 1394, - // 1393, + 1393, // 1392, // 1391, // 1390, @@ -193,7 +193,7 @@ static const int included_patches[] = { // 1307, // 1306, // 1305, - // 1304, + 1304, // 1303, // 1302, // 1301, @@ -247,7 +247,7 @@ static const int included_patches[] = { // 1253, // 1252, // 1251, - // 1250, + 1250, // 1249, // 1248, // 1247, @@ -259,7 +259,7 @@ static const int included_patches[] = { // 1241, // 1240, // 1239, - // 1238, + 1238, // 1237, // 1236, // 1235, diff --git a/test/functional/ui/searchhl_spec.lua b/test/functional/ui/searchhl_spec.lua index 5af8b83a36..9f273e8dc9 100644 --- a/test/functional/ui/searchhl_spec.lua +++ b/test/functional/ui/searchhl_spec.lua @@ -2,6 +2,8 @@ local helpers = require('test.functional.helpers')(after_each) local Screen = require('test.functional.ui.screen') local clear, feed, insert = helpers.clear, helpers.feed, helpers.insert local feed_command = helpers.feed_command +local eq = helpers.eq +local eval = helpers.eval describe('search highlighting', function() local screen @@ -99,7 +101,30 @@ describe('search highlighting', function() feed("gg/li") screen:expect([[ the first {3:li}ne | - in a little file | + in a {2:li}ttle file | + | + {1:~ }| + {1:~ }| + {1:~ }| + /li^ | + ]]) + + -- check that consecutive matches are caught by C-g/C-t + feed("<C-g>") + screen:expect([[ + the first {2:li}ne | + in a {3:li}ttle file | + | + {1:~ }| + {1:~ }| + {1:~ }| + /li^ | + ]]) + + feed("<C-t>") + screen:expect([[ + the first {3:li}ne | + in a {2:li}ttle file | | {1:~ }| {1:~ }| @@ -132,7 +157,7 @@ describe('search highlighting', function() feed("/fir") screen:expect([[ the {3:fir}st line | - in a {2:lit}tle file | + in a little file | | {1:~ }| {1:~ }| @@ -144,13 +169,107 @@ describe('search highlighting', function() feed("<esc>/ttle") screen:expect([[ the first line | - in a {2:li}{3:ttle} file | + in a li{3:ttle} file | | {1:~ }| {1:~ }| {1:~ }| /ttle^ | ]]) + + -- cancelling search resets to the old search term + feed('<esc>') + screen:expect([[ + the first line | + in a {2:^lit}tle file | + | + {1:~ }| + {1:~ }| + {1:~ }| + | + ]]) + eq('lit', eval('@/')) + + -- cancelling inc search restores the hl state + feed(':noh<cr>') + screen:expect([[ + the first line | + in a ^little file | + | + {1:~ }| + {1:~ }| + {1:~ }| + :noh | + ]]) + + feed('/first') + screen:expect([[ + the {3:first} line | + in a little file | + | + {1:~ }| + {1:~ }| + {1:~ }| + /first^ | + ]]) + feed('<esc>') + screen:expect([[ + the first line | + in a ^little file | + | + {1:~ }| + {1:~ }| + {1:~ }| + | + ]]) + + -- test that pressing C-g in an empty command line does not move the cursor + feed('/<C-g>') + screen:expect([[ + the first line | + in a little file | + | + {1:~ }| + {1:~ }| + {1:~ }| + /^ | + ]]) + + -- same, for C-t + feed('<ESC>/<C-t>') + screen:expect([[ + the first line | + in a little file | + | + {1:~ }| + {1:~ }| + {1:~ }| + /^ | + ]]) + + -- 8.0.1304, test that C-g and C-t works with incsearch and empty pattern + feed('<esc>/fi<CR>') + feed('//') + screen:expect([[ + the {3:fi}rst line | + in a little {2:fi}le | + | + {1:~ }| + {1:~ }| + {1:~ }| + //^ | + ]]) + + feed('<C-g>') + screen:expect([[ + the {2:fi}rst line | + in a little {3:fi}le | + | + {1:~ }| + {1:~ }| + {1:~ }| + //^ | + ]]) end) it('works with incsearch and offset', function() @@ -163,7 +282,7 @@ describe('search highlighting', function() feed("gg/mat/e") screen:expect([[ not the {3:mat}ch you're looking for | - the match is here | + the {2:mat}ch is here | {1:~ }| {1:~ }| {1:~ }| @@ -174,7 +293,7 @@ describe('search highlighting', function() -- Search with count and /e offset fixed in Vim patch 7.4.532. feed("<esc>2/mat/e") screen:expect([[ - not the match you're looking for | + not the {2:mat}ch you're looking for | the {3:mat}ch is here | {1:~ }| {1:~ }| |