From c5bf838f8aa51709f8d7ee81cf2b2a6479c77ad7 Mon Sep 17 00:00:00 2001 From: Ibby <33922797+SleepySwords@users.noreply.github.com> Date: Mon, 27 Mar 2023 01:25:37 +1100 Subject: [PATCH] fix(ui): fix visual and search highlighting interfering with virtual text vim-patch:9.0.0193: search and match highlgith interfere with virtual text Problem: Search and match highlgith interfere with virtual text highlight. (Ben Jackson) Solution: Check for match highlight after text properties. Reset and restore search highlight when showing virtual text. (closes vim/vim#10892) https://github.com/vim/vim/commit/e38fc86180fd3f6b372648eea6adc3f623fea302 vim-patch:9.0.0452: Visual highlighting extends into virtual text prop Problem: Visual highlighting extends into virtual text prop. Solution: Do not highlight what isn't actually selected. Fix ordering of stored text props. https://github.com/vim/vim/commit/6eda17d881c9b2880ccb2a4d11951939a58f233d Co-authored-by: Bram Moolenaar --- src/nvim/drawline.c | 92 +++++++++++++++---------- test/functional/ui/decorations_spec.lua | 92 ++++++++++++++++++++++++- 2 files changed, 146 insertions(+), 38 deletions(-) diff --git a/src/nvim/drawline.c b/src/nvim/drawline.c index 725b047985..c789c42af4 100644 --- a/src/nvim/drawline.c +++ b/src/nvim/drawline.c @@ -978,7 +978,10 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool nochange, bool area_highlighting = false; // Visual or incsearch highlighting in this line int vi_attr = 0; // attributes for Visual and incsearch highlighting int area_attr = 0; // attributes desired by highlighting + int saved_area_attr = 0; // idem for area_attr int search_attr = 0; // attributes desired by 'hlsearch' + int saved_search_attr = 0; // search_attr to be used when n_extra + // goes to zero int vcol_save_attr = 0; // saved attr for 'cursorcolumn' int syntax_attr = 0; // attributes desired by syntax bool has_syntax = false; // this buffer has syntax highl. @@ -1729,6 +1732,50 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool nochange, area_active = false; } + if (has_decor && v >= 0) { + bool selected = (area_active || (area_highlighting && noinvcur + && wlv.vcol == wp->w_virtcol)); + extmark_attr = decor_redraw_col(wp, (colnr_T)v, wlv.off, + selected, &decor_state); + + // we could already be inside an existing virt_line with multiple chunks + if (!(virt_inline_i < kv_size(virt_inline))) { + DecorState *state = &decor_state; + for (size_t i = 0; i < kv_size(state->active); i++) { + DecorRange *item = &kv_A(state->active, i); + if (!(item->start_row == state->row + && kv_size(item->decor.virt_text) + && item->decor.virt_text_pos == kVTInline)) { + continue; + } + if (item->win_col >= -1 && item->start_col <= v) { + virt_inline = item->decor.virt_text; + virt_inline_i = 0; + item->win_col = -2; + break; + } + } + } + + if (wlv.n_extra <= 0 && virt_inline_i < kv_size(virt_inline)) { + VirtTextChunk vtc = kv_A(virt_inline, virt_inline_i); + wlv.p_extra = vtc.text; + wlv.n_extra = (int)strlen(wlv.p_extra); + wlv.c_extra = NUL; + wlv.c_final = NUL; + wlv.extra_attr = vtc.hl_id ? syn_id2attr(vtc.hl_id) : 0; + n_attr = mb_charlen(vtc.text); + // restore search_attr and area_attr when n_extra + // is down to zero + saved_search_attr = search_attr; + saved_area_attr = area_attr; + search_attr = 0; + area_attr = 0; + extmark_attr = 0; + virt_inline_i++; + } + } + if (!wlv.n_extra) { // Check for start/end of 'hlsearch' and other matches. // After end, check for start/end of next match. @@ -1792,43 +1839,6 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool nochange, wlv.char_attr = 0; } } - - if (has_decor && v >= 0) { - bool selected = (area_active || (area_highlighting && noinvcur - && wlv.vcol == wp->w_virtcol)); - extmark_attr = decor_redraw_col(wp, (colnr_T)v, wlv.off, selected, &decor_state); - - // we could already be inside an existing virt_line with multiple chunks - if (!(virt_inline_i < kv_size(virt_inline))) { - DecorState *state = &decor_state; - for (size_t i = 0; i < kv_size(state->active); i++) { - DecorRange *item = &kv_A(state->active, i); - if (!(item->start_row == state->row - && kv_size(item->decor.virt_text) - && item->decor.virt_text_pos == kVTInline)) { - continue; - } - if (item->win_col >= -1 && item->start_col <= v) { - virt_inline = item->decor.virt_text; - virt_inline_i = 0; - item->win_col = -2; - break; - } - } - } - - if (wlv.n_extra <= 0 && virt_inline_i < kv_size(virt_inline)) { - VirtTextChunk vtc = kv_A(virt_inline, virt_inline_i); - wlv.p_extra = vtc.text; - wlv.n_extra = (int)strlen(wlv.p_extra); - wlv.c_extra = NUL; - wlv.c_final = NUL; - wlv.extra_attr = vtc.hl_id ? syn_id2attr(vtc.hl_id) : 0; - n_attr = mb_charlen(vtc.text); - extmark_attr = 0; - virt_inline_i++; - } - } } // Get the next character to put on the screen. @@ -1890,6 +1900,14 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool nochange, wlv.p_extra++; } wlv.n_extra--; + if (wlv.n_extra <= 0) { + if (search_attr == 0) { + search_attr = saved_search_attr; + } + if (area_attr == 0 && *ptr != NUL) { + area_attr = saved_area_attr; + } + } } else if (foldinfo.fi_lines > 0) { // skip writing the buffer line itself c = NUL; diff --git a/test/functional/ui/decorations_spec.lua b/test/functional/ui/decorations_spec.lua index 4ed9d5a044..fa492dfcac 100644 --- a/test/functional/ui/decorations_spec.lua +++ b/test/functional/ui/decorations_spec.lua @@ -646,6 +646,8 @@ describe('extmark decorations', function() [26] = {background=Screen.colors.DarkGrey, foreground=Screen.colors.LightGrey}; [27] = {background = Screen.colors.Plum1}; [28] = {foreground = Screen.colors.SlateBlue}; + [29] = {background = Screen.colors.Yellow1}; + [30] = {reverse = true}; } ns = meths.create_namespace 'test' @@ -1582,7 +1584,7 @@ bbbbbbb]]) ]]} end) - it('has correct cursor position with virtual text on an empty line', function() + it('cursor position is correct with virtual text on an empty line', function() command('set linebreak') insert('one twoword') feed('0') @@ -1606,6 +1608,94 @@ bbbbbbb]]) | ]]} end) + + it('search highlight is correct with virtual text attatched to', function() + insert('foo foo foo foo') + feed('0') + meths.buf_set_extmark(0, ns, 0, 8, + { virt_text = { { 'virtual text', 'Special' } }, virt_text_pos = 'inline' }) + screen:expect { grid = [[ + ^foo foo {28:virtual text}foo foo | + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + | + ]]} + + feed('/foo') + screen:expect { grid = [[ + {29:foo} {30:foo} {28:virtual text}{29:foo} {29:foo} | + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + /foo^ | + ]]} + end) + + it('visual select highlight is correct with virtual text attatched to', function() + insert('foo foo foo foo') + feed('0') + meths.buf_set_extmark(0, ns, 0, 8, + { virt_text = { { 'virtual text', 'Special' } }, virt_text_pos = 'inline' }) + feed('8l') + screen:expect { grid = [[ + foo foo {28:virtual text}^foo foo | + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + | + ]]} + + feed('v') + feed('2h') + screen:expect { grid = [[ + foo fo^o{18: }{28:virtual text}{18:f}oo foo | + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {24:-- VISUAL --} | + ]]} + end) end) describe('decorations: virtual lines', function()