From dee3af2122d5072d351551ef023d2c177334b332 Mon Sep 17 00:00:00 2001 From: Ibby <33922797+SleepySwords@users.noreply.github.com> Date: Sun, 26 Mar 2023 16:09:09 +1100 Subject: [PATCH] vim-patch:9.0.0178: cursor position wrong with virtual text before Tab Problem: Cursor position wrong with virtual text before Tab. Solution: Use the byte length, not the cell with, to compare the column. Correct tab size after text prop. (closes vim/vim#10866) https://github.com/vim/vim/commit/e428fa04a758cc87ea580c856a796e58e407504b Co-authored-by: Bram Moolenaar --- src/nvim/charset.c | 8 +- src/nvim/plines.c | 7 ++ test/functional/ui/decorations_spec.lua | 105 ++++++++++++++++++++++++ 3 files changed, 116 insertions(+), 4 deletions(-) diff --git a/src/nvim/charset.c b/src/nvim/charset.c index 3b48392d49..24267ebd50 100644 --- a/src/nvim/charset.c +++ b/src/nvim/charset.c @@ -1084,10 +1084,6 @@ void getvcol(win_T *wp, pos_T *pos, colnr_T *start, colnr_T *cursor, colnr_T *en } if (cursor != NULL) { - if ((State & MODE_INSERT) == 0 && !on_NUL) { - // cursor is after inserted text, unless on the NUL - vcol += cts.cts_cur_text_width; - } if ((*ptr == TAB) && (State & MODE_NORMAL) && !wp->w_p_list @@ -1096,6 +1092,10 @@ void getvcol(win_T *wp, pos_T *pos, colnr_T *start, colnr_T *cursor, colnr_T *en // cursor at end *cursor = vcol + incr - 1; } else { + if ((State & MODE_INSERT) == 0 && !on_NUL) { + // cursor is after inserted text, unless on the NUL + vcol += cts.cts_cur_text_width; + } // cursor at start *cursor = vcol + head; } diff --git a/src/nvim/plines.c b/src/nvim/plines.c index 59c45d3615..2df9c23902 100644 --- a/src/nvim/plines.c +++ b/src/nvim/plines.c @@ -411,6 +411,7 @@ 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) { @@ -425,6 +426,12 @@ int win_lbr_chartabsize(chartabsize_T *cts, int *headp) if (decor.virt_text_pos == kVTInline) { cts->cts_cur_text_width += decor.virt_text_width; size += decor.virt_text_width; + if (*s == TAB) { + // tab size changes because of the inserted text + size -= tab_size; + tab_size = win_chartabsize(wp, s, vcol + size); + size += tab_size; + } } } } diff --git a/test/functional/ui/decorations_spec.lua b/test/functional/ui/decorations_spec.lua index 635666c941..91284e3a2f 100644 --- a/test/functional/ui/decorations_spec.lua +++ b/test/functional/ui/decorations_spec.lua @@ -1476,6 +1476,111 @@ bbbbbbb]]) | ]]} end) + + it('cursor position is correct with virtual text attatched to hard tabs', function() + command('set noexpandtab') + feed('i') + feed('') + feed('') + feed('test') + feed('') + meths.buf_set_extmark(0, ns, 0, 1, + { virt_text = { { 'virtual text', 'Special' } }, virt_text_pos = 'inline' }) + feed('0') + screen:expect { grid = [[ + ^ {28:virtual text} test | + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + | + ]]} + + feed('l') + screen:expect { grid = [[ + {28:virtual text} ^ test | + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + | + ]]} + + feed('l') + screen:expect { grid = [[ + {28:virtual text} ^test | + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + | + ]]} + + feed('l') + screen:expect { grid = [[ + {28:virtual text} t^est | + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + | + ]]} + + feed('l') + screen:expect { grid = [[ + {28:virtual text} te^st | + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + | + ]]} + end) end) describe('decorations: virtual lines', function()