feat(highlight): implement CurSearch highlight

Adds a `CurSearch` highlight group to highlight the current search result under the cursor.
This commit is contained in:
Famiu Haque 2022-04-11 22:20:24 +06:00
parent 3f2e9298bd
commit b16afe4d55
9 changed files with 87 additions and 12 deletions

View File

@ -3176,8 +3176,12 @@ A jump table for the options with a short description can be found at |Q_op|.
'hlsearch' 'hls' boolean (default on) 'hlsearch' 'hls' boolean (default on)
global global
When there is a previous search pattern, highlight all its matches. When there is a previous search pattern, highlight all its matches.
The |hl-Search| highlight group determines the highlighting. Note that The |hl-Search| highlight group determines the highlighting for all
only the matching text is highlighted, any offsets are not applied. matches not under the cursor while the |hl-CurSearch| highlight group
(if defined) determines the highlighting for the match under the
cursor. If |hl-CurSearch| is not defined, then |hl-Search| is used for
both. Note that only the matching text is highlighted, any offsets
are not applied.
See also: 'incsearch' and |:match|. See also: 'incsearch' and |:match|.
When you get bored looking at the highlighted matches, you can turn it When you get bored looking at the highlighted matches, you can turn it
off with |:nohlsearch|. This does not change the option value, as off with |:nohlsearch|. This does not change the option value, as

View File

@ -5090,6 +5090,9 @@ ColorColumn used for the columns set with 'colorcolumn'
*hl-Conceal* *hl-Conceal*
Conceal placeholder characters substituted for concealed Conceal placeholder characters substituted for concealed
text (see 'conceallevel') text (see 'conceallevel')
*hl-CurSearch*
CurSearch used for highlighting a search pattern under the cursor
(see 'hlsearch')
*hl-Cursor* *hl-Cursor*
Cursor character under the cursor Cursor character under the cursor
lCursor the character under the cursor when |language-mapping| lCursor the character under the cursor when |language-mapping|

View File

@ -351,6 +351,8 @@ Functions:
Highlight groups: Highlight groups:
|hl-ColorColumn|, |hl-CursorColumn| are lower priority than most other |hl-ColorColumn|, |hl-CursorColumn| are lower priority than most other
groups groups
|hl-CurSearch| highlights match under cursor instead of last match found
using |n| or |N|
|hl-CursorLine| is low-priority unless foreground color is set |hl-CursorLine| is low-priority unless foreground color is set
*hl-VertSplit* superseded by |hl-WinSeparator| *hl-VertSplit* superseded by |hl-WinSeparator|

View File

@ -63,6 +63,7 @@ typedef enum {
HLF_E, // error messages HLF_E, // error messages
HLF_I, // incremental search HLF_I, // incremental search
HLF_L, // last search string HLF_L, // last search string
HLF_LC, // current search match
HLF_M, // "--More--" message HLF_M, // "--More--" message
HLF_CM, // Mode (e.g., "-- INSERT --") HLF_CM, // Mode (e.g., "-- INSERT --")
HLF_N, // line number for ":number" and ":#" commands HLF_N, // line number for ":number" and ":#" commands
@ -123,6 +124,7 @@ EXTERN const char *hlf_names[] INIT(= {
[HLF_E] = "ErrorMsg", [HLF_E] = "ErrorMsg",
[HLF_I] = "IncSearch", [HLF_I] = "IncSearch",
[HLF_L] = "Search", [HLF_L] = "Search",
[HLF_LC] = "CurSearch",
[HLF_M] = "MoreMsg", [HLF_M] = "MoreMsg",
[HLF_CM] = "ModeMsg", [HLF_CM] = "ModeMsg",
[HLF_N] = "LineNr", [HLF_N] = "LineNr",

View File

@ -1927,7 +1927,7 @@ void highlight_changed(void)
} }
highlight_attr[hlf] = hl_get_ui_attr(hlf, final_id, highlight_attr[hlf] = hl_get_ui_attr(hlf, final_id,
hlf == HLF_INACTIVE); (hlf == HLF_INACTIVE || hlf == HLF_LC));
if (highlight_attr[hlf] != highlight_attr_last[hlf]) { if (highlight_attr[hlf] != highlight_attr_last[hlf]) {
if (hlf == HLF_MSG) { if (hlf == HLF_MSG) {

View File

@ -4,6 +4,7 @@
// match.c: functions for highlighting matches // match.c: functions for highlighting matches
#include <stdbool.h> #include <stdbool.h>
#include "nvim/buffer_defs.h"
#include "nvim/charset.h" #include "nvim/charset.h"
#include "nvim/fold.h" #include "nvim/fold.h"
#include "nvim/highlight_group.h" #include "nvim/highlight_group.h"
@ -667,7 +668,16 @@ int update_search_hl(win_T *wp, linenr_T lnum, colnr_T col, char_u **line, match
if (shl->endcol < next_col) { if (shl->endcol < next_col) {
shl->endcol = next_col; shl->endcol = next_col;
} }
shl->attr_cur = shl->attr; // Use "CurSearch" highlight for current search match
if (shl == search_hl
&& (HL_ATTR(HLF_LC) || wp->w_hl_ids[HLF_LC])
&& wp->w_cursor.lnum == lnum
&& wp->w_cursor.col >= shl->startcol
&& wp->w_cursor.col < shl->endcol) {
shl->attr_cur = win_hl_attr(wp, HLF_LC) ? win_hl_attr(wp, HLF_LC) : HL_ATTR(HLF_LC);
} else {
shl->attr_cur = shl->attr;
}
// Match with the "Conceal" group results in hiding // Match with the "Conceal" group results in hiding
// the match. // the match.
if (cur != NULL if (cur != NULL

View File

@ -95,27 +95,31 @@ static void comp_botline(win_T *wp)
win_check_anchored_floats(wp); win_check_anchored_floats(wp);
} }
/// Redraw when w_cline_row changes and 'relativenumber' or 'cursorline' is set. /// Redraw when w_cline_row changes and 'relativenumber' or 'cursorline' is set
/// or if the 'CurSearch' highlight is defined.
/// Also when concealing is on and 'concealcursor' is not active. /// Also when concealing is on and 'concealcursor' is not active.
void redraw_for_cursorline(win_T *wp) void redraw_for_cursorline(win_T *wp)
FUNC_ATTR_NONNULL_ALL FUNC_ATTR_NONNULL_ALL
{ {
if ((wp->w_valid & VALID_CROW) == 0 && !pum_visible() if ((wp->w_valid & VALID_CROW) == 0 && !pum_visible()
&& (wp->w_p_rnu || win_cursorline_standout(wp))) { && (wp->w_p_rnu || win_cursorline_standout(wp)
// win_line() will redraw the number column and cursorline only. || HL_ATTR(HLF_LC) || wp->w_hl_ids[HLF_LC])) {
// win_line() will redraw the number column and cursorline only
// and also update the CurSearch highlight (if needed).
redraw_later(wp, VALID); redraw_later(wp, VALID);
} }
} }
/// Redraw when w_virtcol changes and 'cursorcolumn' is set or 'cursorlineopt' /// Redraw when w_virtcol changes and 'cursorcolumn' is set or 'cursorlineopt'
/// contains "screenline". /// contains "screenline" or when the 'CurSearch' highlight is defined.
/// Also when concealing is on and 'concealcursor' is active. /// Also when concealing is on and 'concealcursor' is active.
static void redraw_for_cursorcolumn(win_T *wp) static void redraw_for_cursorcolumn(win_T *wp)
FUNC_ATTR_NONNULL_ALL FUNC_ATTR_NONNULL_ALL
{ {
if ((wp->w_valid & VALID_VIRTCOL) == 0 && !pum_visible()) { if ((wp->w_valid & VALID_VIRTCOL) == 0 && !pum_visible()) {
if (wp->w_p_cuc) { if (wp->w_p_cuc || HL_ATTR(HLF_LC) || wp->w_hl_ids[HLF_LC]) {
// When 'cursorcolumn' is set need to redraw with SOME_VALID. // When 'cursorcolumn' is set or 'CurSearch' is defined
// need to redraw with SOME_VALID.
redraw_later(wp, SOME_VALID); redraw_later(wp, SOME_VALID);
} else if (wp->w_p_cul && (wp->w_p_culopt_flags & CULOPT_SCRLINE)) { } else if (wp->w_p_cul && (wp->w_p_culopt_flags & CULOPT_SCRLINE)) {
// When 'cursorlineopt' contains "screenline" need to redraw with VALID. // When 'cursorlineopt' contains "screenline" need to redraw with VALID.

View File

@ -212,10 +212,10 @@ describe('ui/cursor', function()
if m.blinkwait then m.blinkwait = 700 end if m.blinkwait then m.blinkwait = 700 end
end end
if m.hl_id then if m.hl_id then
m.hl_id = 61 m.hl_id = 62
m.attr = {background = Screen.colors.DarkGray} m.attr = {background = Screen.colors.DarkGray}
end end
if m.id_lm then m.id_lm = 62 end if m.id_lm then m.id_lm = 63 end
end end
-- Assert the new expectation. -- Assert the new expectation.

View File

@ -109,6 +109,56 @@ describe('search highlighting', function()
]]) ]])
end) end)
it('works for match under cursor', function()
screen:set_default_attr_ids({
[1] = {background = Screen.colors.Yellow},
[2] = {foreground = Screen.colors.Gray100, background = Screen.colors.Gray0},
[3] = {foreground = Screen.colors.Red},
})
command('highlight CurSearch guibg=Black guifg=White')
insert([[
There is no way that a bee should be
able to fly. Its wings are too small
to get its fat little body off the
ground. The bee, of course, flies
anyway because bees don't care what
humans think is impossible.]])
feed('/bee<CR>')
screen:expect{grid=[[
There is no way that a {2:^bee} should be |
able to fly. Its wings are too small |
to get its fat little body off the |
ground. The {1:bee}, of course, flies |
anyway because {1:bee}s don't care what |
humans think is impossible. |
{3:search hit BOTTOM, continuing at TOP} |
]]}
feed('nn')
screen:expect{grid=[[
There is no way that a {1:bee} should be |
able to fly. Its wings are too small |
to get its fat little body off the |
ground. The {1:bee}, of course, flies |
anyway because {2:^bee}s don't care what |
humans think is impossible. |
/bee |
]]}
feed('N')
screen:expect{grid=[[
There is no way that a {1:bee} should be |
able to fly. Its wings are too small |
to get its fat little body off the |
ground. The {2:^bee}, of course, flies |
anyway because {1:bee}s don't care what |
humans think is impossible. |
?bee |
]]}
end)
it('highlights after EOL', function() it('highlights after EOL', function()
insert("\n\n\n\n\n\n") insert("\n\n\n\n\n\n")