From a05bbc60eaf2d18cb117345becd9d2d13fa4ce4c Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Thu, 15 Jun 2023 09:03:39 +0800 Subject: [PATCH] fix(extmarks): don't position overlay virt_text halfway a char (#24027) --- src/nvim/drawline.c | 87 +++++++++++-------------- test/functional/ui/decorations_spec.lua | 21 ++++++ 2 files changed, 60 insertions(+), 48 deletions(-) diff --git a/src/nvim/drawline.c b/src/nvim/drawline.c index eb5de14f32..7da8bfae14 100644 --- a/src/nvim/drawline.c +++ b/src/nvim/drawline.c @@ -871,10 +871,6 @@ static void apply_cursorline_highlight(win_T *wp, winlinevars_T *wlv) static void handle_inline_virtual_text(win_T *wp, winlinevars_T *wlv, ptrdiff_t v, bool *do_save) { - if (wlv->n_extra == 0 || !wlv->extra_for_extmark) { - wlv->reset_extra_attr = false; - } - while (wlv->n_extra == 0) { if (wlv->virt_inline_i >= kv_size(wlv->virt_inline)) { // need to find inline virtual text @@ -1763,50 +1759,10 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool number_onl break; } - if (wlv.draw_state == WL_LINE - && has_fold - && wlv.col == win_col_offset - && wlv.n_extra == 0 - && wlv.row == startrow + wlv.filler_lines) { + const bool draw_folded = wlv.draw_state == WL_LINE && has_fold + && wlv.row == startrow + wlv.filler_lines; + if (draw_folded && wlv.n_extra == 0) { wlv.char_attr = folded_attr = win_hl_attr(wp, HLF_FL); - - linenr_T lnume = lnum + foldinfo.fi_lines - 1; - memset(buf_fold, ' ', FOLD_TEXT_LEN); - wlv.p_extra = get_foldtext(wp, lnum, lnume, foldinfo, buf_fold); - wlv.n_extra = (int)strlen(wlv.p_extra); - - if (wlv.p_extra != buf_fold) { - xfree(wlv.p_extra_free); - wlv.p_extra_free = wlv.p_extra; - } - wlv.c_extra = NUL; - wlv.c_final = NUL; - wlv.p_extra[wlv.n_extra] = NUL; - - // Get the line again as evaluating 'foldtext' may free it. - line = ml_get_buf(wp->w_buffer, lnum, false); - ptr = line + v; - } - - if (wlv.draw_state == WL_LINE - && has_fold - && wlv.col < grid->cols - && wlv.n_extra == 0 - && wlv.row == startrow + wlv.filler_lines) { - // fill rest of line with 'fold' - wlv.c_extra = wp->w_p_fcs_chars.fold; - wlv.c_final = NUL; - - wlv.n_extra = wp->w_p_rl ? (wlv.col + 1) : (grid->cols - wlv.col); - } - - if (wlv.draw_state == WL_LINE - && has_fold - && wlv.col >= grid->cols - && wlv.n_extra != 0 - && wlv.row == startrow + wlv.filler_lines) { - // Truncate the folding. - wlv.n_extra = 0; } int extmark_attr = 0; @@ -1829,7 +1785,11 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool number_onl area_active = false; } - if (has_decor && v >= 0) { + if (wlv.n_extra == 0 || !wlv.extra_for_extmark) { + wlv.reset_extra_attr = false; + } + + if (has_decor && v >= 0 && wlv.n_extra == 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); @@ -1919,6 +1879,37 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool number_onl } } + if (draw_folded && wlv.n_extra == 0 && wlv.col == win_col_offset) { + linenr_T lnume = lnum + foldinfo.fi_lines - 1; + memset(buf_fold, ' ', FOLD_TEXT_LEN); + wlv.p_extra = get_foldtext(wp, lnum, lnume, foldinfo, buf_fold); + wlv.n_extra = (int)strlen(wlv.p_extra); + + if (wlv.p_extra != buf_fold) { + xfree(wlv.p_extra_free); + wlv.p_extra_free = wlv.p_extra; + } + wlv.c_extra = NUL; + wlv.c_final = NUL; + wlv.p_extra[wlv.n_extra] = NUL; + + // Get the line again as evaluating 'foldtext' may free it. + line = ml_get_buf(wp->w_buffer, lnum, false); + ptr = line + v; + } + + if (draw_folded && wlv.n_extra == 0 && wlv.col < grid->cols) { + // Fill rest of line with 'fold'. + wlv.c_extra = wp->w_p_fcs_chars.fold; + wlv.c_final = NUL; + wlv.n_extra = wp->w_p_rl ? (wlv.col + 1) : (grid->cols - wlv.col); + } + + if (draw_folded && wlv.n_extra != 0 && wlv.col >= grid->cols) { + // Truncate the folding. + wlv.n_extra = 0; + } + // Get the next character to put on the screen. // // The "p_extra" points to the extra stuff that is inserted to diff --git a/test/functional/ui/decorations_spec.lua b/test/functional/ui/decorations_spec.lua index 36c414e58f..940974e0b0 100644 --- a/test/functional/ui/decorations_spec.lua +++ b/test/functional/ui/decorations_spec.lua @@ -667,6 +667,8 @@ describe('extmark decorations', function() [31] = {underline = true, foreground = Screen.colors.DarkCyan}; [32] = {underline = true}; [33] = {foreground = Screen.colors.DarkBlue, background = Screen.colors.LightGray}; + [34] = {background = Screen.colors.Yellow}; + [35] = {background = Screen.colors.Yellow, bold = true, foreground = Screen.colors.Blue}; } ns = meths.create_namespace 'test' @@ -890,6 +892,25 @@ describe('extmark decorations', function() ]]} end) + it('overlay virtual text works on and after a TAB #24022', function() + screen:try_resize(40, 3) + meths.buf_set_lines(0, 0, -1, true, {'\t\tline 1'}) + meths.buf_set_extmark(0, ns, 0, 0, { virt_text = {{'AA', 'Search'}}, virt_text_pos = 'overlay', hl_mode = 'combine' }) + meths.buf_set_extmark(0, ns, 0, 1, { virt_text = {{'BB', 'Search'}}, virt_text_pos = 'overlay', hl_mode = 'combine' }) + meths.buf_set_extmark(0, ns, 0, 2, { virt_text = {{'CC', 'Search'}}, virt_text_pos = 'overlay', hl_mode = 'combine' }) + screen:expect{grid=[[ + {34:AA} ^ {34:BB} {34:CC}ne 1 | + {1:~ }| + | + ]]} + command('setlocal list listchars=tab:<->') + screen:expect{grid=[[ + {35:^AA}{1:----->}{35:BB}{1:----->}{34:CC}ne 1 | + {1:~ }| + | + ]]} + end) + it('can have virtual text of overlay position and styling', function() insert(example_text) feed 'gg'