From 35c3275b4896a65d67caf2a4355d7516b6ddec29 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Mon, 3 Jul 2023 22:57:45 +0800 Subject: [PATCH] fix(plines): handle inline virtual text after last char (#24241) Also remove dead code in win_lbr_chartabsize(). --- src/nvim/plines.c | 11 ++++---- src/nvim/plines.h | 14 +++++----- test/functional/ui/decorations_spec.lua | 36 ++++++++++++++++++++++++- 3 files changed, 47 insertions(+), 14 deletions(-) diff --git a/src/nvim/plines.c b/src/nvim/plines.c index 523b85fd32..eb1ae540a4 100644 --- a/src/nvim/plines.c +++ b/src/nvim/plines.c @@ -287,7 +287,7 @@ unsigned win_linetabsize(win_T *wp, linenr_T lnum, char *line, colnr_T len) /// Return the number of cells line "lnum" of window "wp" will take on the /// screen, taking into account the size of a tab and text properties. -unsigned linetabsize(win_T *wp, linenr_T lnum) +unsigned linetabsize(win_T *wp, linenr_T lnum) { return win_linetabsize(wp, lnum, ml_get_buf(wp->w_buffer, lnum, false), (colnr_T)MAXCOL); } @@ -298,9 +298,8 @@ void win_linetabsize_cts(chartabsize_T *cts, colnr_T len) MB_PTR_ADV(cts->cts_ptr)) { cts->cts_vcol += win_lbr_chartabsize(cts, NULL); } - // check for a virtual text on an empty line - if (cts->cts_has_virt_text && *cts->cts_ptr == NUL - && cts->cts_ptr == cts->cts_line) { + // check for a virtual text after the end of the line + if (len == MAXCOL && cts->cts_has_virt_text && *cts->cts_ptr == NUL) { (void)win_lbr_chartabsize(cts, NULL); cts->cts_vcol += cts->cts_cur_text_width_left + cts->cts_cur_text_width_right; } @@ -406,15 +405,15 @@ int win_lbr_chartabsize(chartabsize_T *cts, int *headp) // First get normal size, without 'linebreak' or virtual text int size = win_chartabsize(wp, s, vcol); + if (cts->cts_has_virt_text) { int tab_size = size; - int charlen = *s == NUL ? 1 : utf_ptr2len(s); int col = (int)(s - line); while (true) { mtkey_t mark = marktree_itr_current(cts->cts_iter); if (mark.pos.row != cts->cts_row || mark.pos.col > col) { break; - } else if (mark.pos.col >= col && mark.pos.col < col + charlen) { + } else if (mark.pos.col == col) { if (!mt_end(mark)) { Decoration decor = get_decor(mark); if (decor.virt_text_pos == kVTInline) { diff --git a/src/nvim/plines.h b/src/nvim/plines.h index 2ce7133705..d89dc7b6f6 100644 --- a/src/nvim/plines.h +++ b/src/nvim/plines.h @@ -6,19 +6,19 @@ #include "nvim/buffer_defs.h" #include "nvim/vim.h" -// Argument for lbr_chartabsize(). +/// Argument for lbr_chartabsize(). typedef struct { win_T *cts_win; - char *cts_line; // start of the line - char *cts_ptr; // current position in line + char *cts_line; ///< start of the line + char *cts_ptr; ///< current position in line int cts_row; - bool cts_has_virt_text; // true if if a property inserts text - int cts_cur_text_width_left; // width of virtual text left of cursor - int cts_cur_text_width_right; // width of virtual text right of cursor + bool cts_has_virt_text; ///< true if if there is inline virtual text + int cts_cur_text_width_left; ///< width of virtual text left of cursor + int cts_cur_text_width_right; ///< width of virtual text right of cursor MarkTreeIter cts_iter[1]; - int cts_vcol; // virtual column at current position + int cts_vcol; ///< virtual column at current position } chartabsize_T; #ifdef INCLUDE_GENERATED_DECLARATIONS diff --git a/test/functional/ui/decorations_spec.lua b/test/functional/ui/decorations_spec.lua index 4c04bad3a0..8070ac550d 100644 --- a/test/functional/ui/decorations_spec.lua +++ b/test/functional/ui/decorations_spec.lua @@ -1835,7 +1835,7 @@ describe('decorations: inline virtual text', function() ]]} end) - it('text is drawn correctly when inserting a wrapping virtual text on an empty line', function() + it('text is drawn correctly with a wrapping virtual text', function() feed('o') insert([[aaaaaaa @@ -1899,6 +1899,40 @@ bbbbbbb]]) {1:~ }| | ]]} + + feed('ggic') + screen:expect { grid = [[ + c{10:^XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX}| + {10:XX} | + aaaaaaa | + {10:XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX}| + bbbbbbb | + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {8:-- INSERT --} | + ]]} + end) + + it('regexp \\%V does not count trailing virtual text', function() + screen:try_resize(50, 4) + meths.buf_set_lines(0, 0, -1, true, {'foofoo', '', 'foofoo'}) + meths.buf_set_extmark(0, ns, 1, 0, { virt_text = {{'barbarbar', 'Special'}}, virt_text_pos = 'inline' }) + feed([[G5l/foo\n\%V]]) + screen:expect{grid=[[ + foo{12:^foo } | + {10:barbarbar} | + foofoo | + {16:search hit BOTTOM, continuing at TOP} | + ]]} + feed([[jIbaz/foo\nbaz\%V]]) + screen:expect{grid=[[ + foo{12:^foo } | + {12:baz}{10:barbarbar} | + foofoo | + {16:search hit BOTTOM, continuing at TOP} | + ]]} end) it('cursor position is correct with virtual text attached to hard tabs', function()