fix(marks): handle double-with inline virt_text with 'nowrap' (#32476)

This commit is contained in:
zeertzjq 2025-02-16 22:05:13 +08:00 committed by GitHub
parent efe92f9dff
commit 8452032554
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 106 additions and 30 deletions

View File

@ -909,25 +909,39 @@ static void handle_inline_virtual_text(win_T *wp, winlinevars_T *wlv, ptrdiff_t
// If the text didn't reach until the first window
// column we need to skip cells.
if (wlv->skip_cells > 0) {
// FIXME: this should use virt_text_width instead
int virt_text_len = wlv->n_attr;
if (virt_text_len > wlv->skip_cells) {
int len = mb_charlen2bytelen(wlv->p_extra, wlv->skip_cells);
wlv->n_extra -= len;
wlv->p_extra += len;
wlv->n_attr -= wlv->skip_cells;
int virt_text_width = (int)mb_string2cells(wlv->p_extra);
if (virt_text_width > wlv->skip_cells) {
int cells_to_skip = wlv->skip_cells;
// Skip cells in the text.
while (cells_to_skip > 0) {
int clen = utf_ptr2len(wlv->p_extra);
cells_to_skip -= utf_ptr2cells(wlv->p_extra);
wlv->p_extra += clen;
wlv->n_extra -= clen;
wlv->n_attr--;
}
// If a double-width char doesn't fit, pad with space.
if (cells_to_skip < 0) {
int pad_len = -cells_to_skip;
char *padded = get_extra_buf((size_t)(wlv->n_extra + pad_len) + 1);
memset(padded, ' ', (size_t)pad_len);
xmemcpyz(padded + pad_len, wlv->p_extra, (size_t)wlv->n_extra);
wlv->p_extra = padded;
wlv->n_extra += pad_len;
wlv->n_attr += pad_len;
}
// Skipped cells needed to be accounted for in vcol.
wlv->skipped_cells += wlv->skip_cells;
wlv->skip_cells = 0;
} else {
// the whole text is left of the window, drop
// it and advance to the next one
wlv->skip_cells -= virt_text_len;
// The whole text is left of the window, drop
// it and advance to the next one.
wlv->skip_cells -= virt_text_width;
// Skipped cells needed to be accounted for in vcol.
wlv->skipped_cells += virt_text_len;
wlv->skipped_cells += virt_text_width;
wlv->n_attr = 0;
wlv->n_extra = 0;
// go to the start so the next virtual text chunk can be selected.
// Go to the start so the next virtual text chunk can be selected.
continue;
}
}

View File

@ -2251,24 +2251,6 @@ int mb_charlen(const char *str)
return count;
}
int mb_charlen2bytelen(const char *str, int charlen)
{
const char *p = str;
int count = 0;
if (p == NULL) {
return 0;
}
for (int i = 0; *p != NUL && i < charlen; i++) {
int b = utfc_ptr2len(p);
p += b;
count += b;
}
return count;
}
/// Like mb_charlen() but for a string with specified length.
int mb_charlen_len(const char *str, int len)
{

View File

@ -3375,6 +3375,86 @@ describe('decorations: inline virtual text', function()
]]}
end)
it('draws correctly with no wrap and multibyte virtual text', function()
insert('12345678')
command('set nowrap')
api.nvim_buf_set_extmark(0, ns, 0, 2, {
virt_text = { { 'αβγ口=', 'Special' }, { '', 'Special' } },
virt_text_pos = 'inline',
})
screen:expect([[
12{10:αβγ=}34567^8 |
{1:~ }|
|
]])
feed('zl')
screen:expect([[
2{10:αβγ=}34567^8 |
{1:~ }|
|
]])
feed('zl')
screen:expect([[
{10:αβγ=}34567^8 |
{1:~ }|
|
]])
feed('zl')
screen:expect([[
{10:βγ=}34567^8 |
{1:~ }|
|
]])
feed('zl')
screen:expect([[
{10:γ=}34567^8 |
{1:~ }|
|
]])
feed('zl')
screen:expect([[
{10:=}34567^8 |
{1:~ }|
|
]])
feed('zl')
screen:expect([[
{10: =}34567^8 |
{1:~ }|
|
]])
feed('zl')
screen:expect([[
{10:=}34567^8 |
{1:~ }|
|
]])
feed('zl')
screen:expect([[
{10:}34567^8 |
{1:~ }|
|
]])
feed('zl')
screen:expect([[
{10: }34567^8 |
{1:~ }|
|
]])
feed('zl')
screen:expect([[
34567^8 |
{1:~ }|
|
]])
feed('zl')
screen:expect([[
4567^8 |
{1:~ }|
|
]])
end)
it('tabs are the correct length with no wrap following virtual text', function()
command('set nowrap')
feed('itest<TAB>a<ESC>')