From 091eb4c8c7208569379daf094503abd2eeec32c6 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Sun, 17 Mar 2024 17:54:18 +0800 Subject: [PATCH] fix(mouse): click after eol with conceal and virtual text (#27897) Problem: Wrong cursor position when clicking after end of line with 'virtualedit', conceal and virtual text. Solution: Always fill linebuf_vcol[] for the columns to clear. --- src/nvim/drawline.c | 16 ++++++--- test/functional/ui/mouse_spec.lua | 54 +++++++++++++++++++++++++++++++ 2 files changed, 66 insertions(+), 4 deletions(-) diff --git a/src/nvim/drawline.c b/src/nvim/drawline.c index a6f3f0c4b3..cbe586d103 100644 --- a/src/nvim/drawline.c +++ b/src/nvim/drawline.c @@ -300,7 +300,6 @@ static void draw_virt_text(win_T *wp, buf_T *buf, int col_off, int *end_col, int if (vt->pos == kVPosEndOfLine && do_eol) { state->eol_col = col + 1; } - // TODO(zeertzjq): set values in linebuf_vcol[] *end_col = MAX(*end_col, col); } if (!vt || !(vt->flags & kVTRepeatLinebreak)) { @@ -2571,6 +2570,10 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, int col_rows, s decor_redraw_eol(wp, &decor_state, &wlv.line_attr, wlv.col + eol_skip); } + for (int i = wlv.col; i < grid->cols; i++) { + linebuf_vcol[wlv.off + (i - wlv.col)] = wlv.vcol + (i - wlv.col); + } + if (((wp->w_p_cuc && wp->w_virtcol >= vcol_hlc(wlv) - eol_hl_off && wp->w_virtcol < grid->cols * (ptrdiff_t)(wlv.row - startrow + 1) + start_col @@ -2596,8 +2599,7 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, int col_rows, s while (wlv.col < grid->cols) { linebuf_char[wlv.off] = schar_from_ascii(' '); - linebuf_vcol[wlv.off] = wlv.vcol; - wlv.col++; + advance_color_col(&wlv, vcol_hlc(wlv)); int col_attr = base_attr; @@ -2616,7 +2618,9 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, int col_rows, s col_attr = hl_combine_attr(col_attr, wlv.line_attr); linebuf_attr[wlv.off] = col_attr; + // linebuf_vcol[] already filled by the for loop above wlv.off++; + wlv.col++; if (vcol_hlc(wlv) >= rightmost_vcol) { break; @@ -2857,13 +2861,17 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, int col_rows, s int draw_col = wlv.col - wlv.boguscols; + for (int i = draw_col; i < grid->cols; i++) { + linebuf_vcol[wlv.off + (i - draw_col)] = wlv.vcol - 1; + } + // Apply 'cursorline' highlight. if (wlv.boguscols != 0 && (wlv.line_attr_lowprio != 0 || wlv.line_attr != 0)) { int attr = hl_combine_attr(wlv.line_attr_lowprio, wlv.line_attr); while (draw_col < grid->cols) { linebuf_char[wlv.off] = schar_from_char(' '); linebuf_attr[wlv.off] = attr; - linebuf_vcol[wlv.off] = wlv.vcol - 1; + // linebuf_vcol[] already filled by the for loop above wlv.off++; draw_col++; } diff --git a/test/functional/ui/mouse_spec.lua b/test/functional/ui/mouse_spec.lua index 0f30bf4471..11fb0ffaca 100644 --- a/test/functional/ui/mouse_spec.lua +++ b/test/functional/ui/mouse_spec.lua @@ -34,6 +34,7 @@ describe('ui/mouse/input', function() [6] = { foreground = Screen.colors.Grey100, background = Screen.colors.Red }, [7] = { bold = true, foreground = Screen.colors.SeaGreen4 }, [8] = { foreground = Screen.colors.Brown }, + [9] = { background = Screen.colors.DarkGrey, foreground = Screen.colors.LightGrey }, }) command('set mousemodel=extend') feed('itestingmousesupport and selection') @@ -1638,6 +1639,59 @@ describe('ui/mouse/input', function() end) end) + it('virtual text does not change cursor placement on concealed line', function() + command('%delete') + insert('aaaaaaaaaa|hidden|bbbbbbbbbb|hidden|cccccccccc') + command('syntax match test /|hidden|/ conceal cchar=X') + command('set conceallevel=2 concealcursor=n virtualedit=all') + screen:expect([[ + aaaaaaaaaa{9:X}bbbbbbb | + bbb{9:X}ccccccccc^c | + {0:~ }|*2 + | + ]]) + api.nvim_input_mouse('left', 'press', '', 0, 0, 22) + screen:expect([[ + aaaaaaaaaa{9:X}bbbbbb^b | + bbb{9:X}cccccccccc | + {0:~ }|*2 + | + ]]) + api.nvim_input_mouse('left', 'press', '', 0, 1, 16) + screen:expect([[ + aaaaaaaaaa{9:X}bbbbbbb | + bbb{9:X}cccccccccc ^ | + {0:~ }|*2 + | + ]]) + + api.nvim_buf_set_extmark(0, api.nvim_create_namespace(''), 0, 0, { + virt_text = { { '?', 'ErrorMsg' } }, + virt_text_pos = 'right_align', + virt_text_repeat_linebreak = true, + }) + screen:expect([[ + aaaaaaaaaa{9:X}bbbbbbb {6:?}| + bbb{9:X}cccccccccc ^ {6:?}| + {0:~ }|*2 + | + ]]) + api.nvim_input_mouse('left', 'press', '', 0, 0, 22) + screen:expect([[ + aaaaaaaaaa{9:X}bbbbbb^b {6:?}| + bbb{9:X}cccccccccc {6:?}| + {0:~ }|*2 + | + ]]) + api.nvim_input_mouse('left', 'press', '', 0, 1, 16) + screen:expect([[ + aaaaaaaaaa{9:X}bbbbbbb {6:?}| + bbb{9:X}cccccccccc ^ {6:?}| + {0:~ }|*2 + | + ]]) + end) + it('getmousepos() works correctly', function() local winwidth = api.nvim_get_option_value('winwidth', {}) -- Set winwidth=1 so that window sizes don't change.