mirror of
https://github.com/neovim/neovim.git
synced 2025-09-27 13:38:34 +00:00
Merge #7463 'incsearch + hlsearch highlight all'
This commit is contained in:
@@ -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
|
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.
|
avoid that Vim hangs while you are typing the pattern.
|
||||||
The |hl-IncSearch| highlight group determines the highlighting.
|
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
|
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
|
||||||
|
@@ -426,7 +426,7 @@ static uint8_t *command_line_enter(int firstc, long count, int indent)
|
|||||||
curwin->w_botline = s->old_botline;
|
curwin->w_botline = s->old_botline;
|
||||||
highlight_match = false;
|
highlight_match = false;
|
||||||
validate_cursor(); // needed for TAB
|
validate_cursor(); // needed for TAB
|
||||||
redraw_later(SOME_VALID);
|
redraw_all_later(SOME_VALID);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ccline.cmdbuff != NULL) {
|
if (ccline.cmdbuff != NULL) {
|
||||||
@@ -1019,17 +1019,36 @@ static void command_line_next_incsearch(CommandLineState *s, bool next_match)
|
|||||||
ui_flush();
|
ui_flush();
|
||||||
|
|
||||||
pos_T t;
|
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) {
|
if (next_match) {
|
||||||
t = s->match_end;
|
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;
|
search_flags += SEARCH_COL;
|
||||||
} else {
|
} else {
|
||||||
t = s->match_start;
|
t = s->match_start;
|
||||||
}
|
}
|
||||||
|
if (!p_hls) {
|
||||||
|
search_flags += SEARCH_KEEP;
|
||||||
|
}
|
||||||
emsg_off++;
|
emsg_off++;
|
||||||
s->i = searchit(curwin, curbuf, &t,
|
s->i = searchit(curwin, curbuf, &t,
|
||||||
next_match ? FORWARD : BACKWARD,
|
next_match ? FORWARD : BACKWARD,
|
||||||
ccline.cmdbuff, s->count, search_flags,
|
pat, s->count, search_flags,
|
||||||
RE_SEARCH, 0, NULL);
|
RE_SEARCH, 0, NULL);
|
||||||
emsg_off--;
|
emsg_off--;
|
||||||
ui_busy_stop();
|
ui_busy_stop();
|
||||||
@@ -1070,6 +1089,7 @@ static void command_line_next_incsearch(CommandLineState *s, bool next_match)
|
|||||||
} else {
|
} else {
|
||||||
vim_beep(BO_ERROR);
|
vim_beep(BO_ERROR);
|
||||||
}
|
}
|
||||||
|
restore_last_search_pattern();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1656,7 +1676,9 @@ static int command_line_handle_key(CommandLineState *s)
|
|||||||
if (char_avail()) {
|
if (char_avail()) {
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
if (ccline.cmdlen != 0) {
|
||||||
command_line_next_incsearch(s, s->c == Ctrl_G);
|
command_line_next_incsearch(s, s->c == Ctrl_G);
|
||||||
|
}
|
||||||
return command_line_not_changed(s);
|
return command_line_not_changed(s);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@@ -1759,6 +1781,20 @@ static int command_line_not_changed(CommandLineState *s)
|
|||||||
return command_line_changed(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)
|
static int command_line_changed(CommandLineState *s)
|
||||||
{
|
{
|
||||||
// 'incsearch' highlighting.
|
// 'incsearch' highlighting.
|
||||||
@@ -1773,20 +1809,27 @@ static int command_line_changed(CommandLineState *s)
|
|||||||
}
|
}
|
||||||
s->incsearch_postponed = false;
|
s->incsearch_postponed = false;
|
||||||
curwin->w_cursor = s->search_start; // start at old position
|
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 there is no command line, don't do anything
|
||||||
if (ccline.cmdlen == 0) {
|
if (ccline.cmdlen == 0) {
|
||||||
s->i = 0;
|
s->i = 0;
|
||||||
|
SET_NO_HLSEARCH(true); // turn off previous highlight
|
||||||
|
redraw_all_later(SOME_VALID);
|
||||||
} else {
|
} else {
|
||||||
|
int search_flags = SEARCH_OPT + SEARCH_NOOF + SEARCH_PEEK;
|
||||||
ui_busy_start();
|
ui_busy_start();
|
||||||
ui_flush();
|
ui_flush();
|
||||||
++emsg_off; // So it doesn't beep if bad expr
|
++emsg_off; // So it doesn't beep if bad expr
|
||||||
// Set the time limit to half a second.
|
// Set the time limit to half a second.
|
||||||
tm = profile_setlimit(500L);
|
tm = profile_setlimit(500L);
|
||||||
|
if (!p_hls) {
|
||||||
|
search_flags += SEARCH_KEEP;
|
||||||
|
}
|
||||||
s->i = do_search(NULL, s->firstc, ccline.cmdbuff, s->count,
|
s->i = do_search(NULL, s->firstc, ccline.cmdbuff, s->count,
|
||||||
SEARCH_KEEP + SEARCH_OPT + SEARCH_NOOF + SEARCH_PEEK,
|
search_flags,
|
||||||
&tm);
|
&tm);
|
||||||
--emsg_off;
|
emsg_off--;
|
||||||
// if interrupted while searching, behave like it failed
|
// if interrupted while searching, behave like it failed
|
||||||
if (got_int) {
|
if (got_int) {
|
||||||
(void)vpeekc(); // remove <C-C> from input stream
|
(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
|
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();
|
validate_cursor();
|
||||||
// May redraw the status line to show the cursor position.
|
// May redraw the status line to show the cursor position.
|
||||||
if (p_ru && curwin->w_status_height > 0) {
|
if (p_ru && curwin->w_status_height > 0) {
|
||||||
@@ -1836,6 +1885,7 @@ static int command_line_changed(CommandLineState *s)
|
|||||||
save_cmdline(&s->save_ccline);
|
save_cmdline(&s->save_ccline);
|
||||||
update_screen(SOME_VALID);
|
update_screen(SOME_VALID);
|
||||||
restore_cmdline(&s->save_ccline);
|
restore_cmdline(&s->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 (s->i != 0) {
|
if (s->i != 0) {
|
||||||
|
@@ -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 */
|
/* copy of spats[], for keeping the search patterns while executing autocmds */
|
||||||
static struct spat saved_spats[2];
|
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_last_idx = 0;
|
||||||
static int saved_no_hlsearch = 0;
|
static int saved_no_hlsearch = 0;
|
||||||
|
|
||||||
@@ -305,6 +308,36 @@ void free_search_patterns(void)
|
|||||||
|
|
||||||
#endif
|
#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".
|
* Return TRUE when case should be ignored for search pattern "pat".
|
||||||
* Uses the 'ignorecase' and 'smartcase' options.
|
* Uses the 'ignorecase' and 'smartcase' options.
|
||||||
|
@@ -101,10 +101,10 @@ static const int included_patches[] = {
|
|||||||
// 1399,
|
// 1399,
|
||||||
// 1398,
|
// 1398,
|
||||||
// 1397,
|
// 1397,
|
||||||
// 1396,
|
1396,
|
||||||
// 1395,
|
// 1395,
|
||||||
// 1394,
|
// 1394,
|
||||||
// 1393,
|
1393,
|
||||||
// 1392,
|
// 1392,
|
||||||
// 1391,
|
// 1391,
|
||||||
// 1390,
|
// 1390,
|
||||||
@@ -193,7 +193,7 @@ static const int included_patches[] = {
|
|||||||
// 1307,
|
// 1307,
|
||||||
// 1306,
|
// 1306,
|
||||||
// 1305,
|
// 1305,
|
||||||
// 1304,
|
1304,
|
||||||
// 1303,
|
// 1303,
|
||||||
// 1302,
|
// 1302,
|
||||||
// 1301,
|
// 1301,
|
||||||
@@ -247,7 +247,7 @@ static const int included_patches[] = {
|
|||||||
// 1253,
|
// 1253,
|
||||||
// 1252,
|
// 1252,
|
||||||
// 1251,
|
// 1251,
|
||||||
// 1250,
|
1250,
|
||||||
// 1249,
|
// 1249,
|
||||||
// 1248,
|
// 1248,
|
||||||
// 1247,
|
// 1247,
|
||||||
@@ -259,7 +259,7 @@ static const int included_patches[] = {
|
|||||||
// 1241,
|
// 1241,
|
||||||
// 1240,
|
// 1240,
|
||||||
// 1239,
|
// 1239,
|
||||||
// 1238,
|
1238,
|
||||||
// 1237,
|
// 1237,
|
||||||
// 1236,
|
// 1236,
|
||||||
// 1235,
|
// 1235,
|
||||||
|
@@ -2,6 +2,8 @@ local helpers = require('test.functional.helpers')(after_each)
|
|||||||
local Screen = require('test.functional.ui.screen')
|
local Screen = require('test.functional.ui.screen')
|
||||||
local clear, feed, insert = helpers.clear, helpers.feed, helpers.insert
|
local clear, feed, insert = helpers.clear, helpers.feed, helpers.insert
|
||||||
local feed_command = helpers.feed_command
|
local feed_command = helpers.feed_command
|
||||||
|
local eq = helpers.eq
|
||||||
|
local eval = helpers.eval
|
||||||
|
|
||||||
describe('search highlighting', function()
|
describe('search highlighting', function()
|
||||||
local screen
|
local screen
|
||||||
@@ -99,7 +101,30 @@ describe('search highlighting', function()
|
|||||||
feed("gg/li")
|
feed("gg/li")
|
||||||
screen:expect([[
|
screen:expect([[
|
||||||
the first {3:li}ne |
|
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:~ }|
|
||||||
{1:~ }|
|
{1:~ }|
|
||||||
@@ -132,7 +157,7 @@ describe('search highlighting', function()
|
|||||||
feed("/fir")
|
feed("/fir")
|
||||||
screen:expect([[
|
screen:expect([[
|
||||||
the {3:fir}st line |
|
the {3:fir}st line |
|
||||||
in a {2:lit}tle file |
|
in a little file |
|
||||||
|
|
|
|
||||||
{1:~ }|
|
{1:~ }|
|
||||||
{1:~ }|
|
{1:~ }|
|
||||||
@@ -144,13 +169,107 @@ describe('search highlighting', function()
|
|||||||
feed("<esc>/ttle")
|
feed("<esc>/ttle")
|
||||||
screen:expect([[
|
screen:expect([[
|
||||||
the first line |
|
the first line |
|
||||||
in a {2:li}{3:ttle} file |
|
in a li{3:ttle} file |
|
||||||
|
|
|
|
||||||
{1:~ }|
|
{1:~ }|
|
||||||
{1:~ }|
|
{1:~ }|
|
||||||
{1:~ }|
|
{1:~ }|
|
||||||
/ttle^ |
|
/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)
|
end)
|
||||||
|
|
||||||
it('works with incsearch and offset', function()
|
it('works with incsearch and offset', function()
|
||||||
@@ -163,7 +282,7 @@ describe('search highlighting', function()
|
|||||||
feed("gg/mat/e")
|
feed("gg/mat/e")
|
||||||
screen:expect([[
|
screen:expect([[
|
||||||
not the {3:mat}ch you're looking for |
|
not the {3:mat}ch you're looking for |
|
||||||
the match is here |
|
the {2:mat}ch is here |
|
||||||
{1:~ }|
|
{1:~ }|
|
||||||
{1:~ }|
|
{1:~ }|
|
||||||
{1:~ }|
|
{1:~ }|
|
||||||
@@ -174,7 +293,7 @@ describe('search highlighting', function()
|
|||||||
-- Search with count and /e offset fixed in Vim patch 7.4.532.
|
-- Search with count and /e offset fixed in Vim patch 7.4.532.
|
||||||
feed("<esc>2/mat/e")
|
feed("<esc>2/mat/e")
|
||||||
screen:expect([[
|
screen:expect([[
|
||||||
not the match you're looking for |
|
not the {2:mat}ch you're looking for |
|
||||||
the {3:mat}ch is here |
|
the {3:mat}ch is here |
|
||||||
{1:~ }|
|
{1:~ }|
|
||||||
{1:~ }|
|
{1:~ }|
|
||||||
|
Reference in New Issue
Block a user