aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/nvim/drawline.c119
-rw-r--r--test/functional/ui/decorations_spec.lua51
2 files changed, 124 insertions, 46 deletions
diff --git a/src/nvim/drawline.c b/src/nvim/drawline.c
index 679f92c3b8..884abb6b88 100644
--- a/src/nvim/drawline.c
+++ b/src/nvim/drawline.c
@@ -930,28 +930,22 @@ static void handle_inline_virtual_text(win_T *wp, winlinevars_T *wlv, ptrdiff_t
if (wlv->skip_cells > 0) {
int virt_text_width = (int)mb_string2cells(wlv->p_extra);
if (virt_text_width > wlv->skip_cells) {
- int cells_to_skip = wlv->skip_cells;
+ int skip_cells_remaining = wlv->skip_cells;
// Skip cells in the text.
- while (cells_to_skip > 0) {
+ while (skip_cells_remaining > 0) {
+ int cells = utf_ptr2cells(wlv->p_extra);
+ if (cells > skip_cells_remaining) {
+ break;
+ }
int c_len = utfc_ptr2len(wlv->p_extra);
- cells_to_skip -= utf_ptr2cells(wlv->p_extra);
+ skip_cells_remaining -= cells;
wlv->p_extra += c_len;
wlv->n_extra -= c_len;
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;
+ wlv->skipped_cells += wlv->skip_cells - skip_cells_remaining;
+ wlv->skip_cells = skip_cells_remaining;
} else {
// The whole text is left of the window, drop
// it and advance to the next one.
@@ -1076,6 +1070,9 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, int col_rows, s
bool in_multispace = false; // in multiple consecutive spaces
int multispace_pos = 0; // position in lcs-multispace string
+ int n_extra_next = 0; // n_extra to use after current extra chars
+ int extra_attr_next = -1; // extra_attr to use after current extra chars
+
bool search_attr_from_match = false; // if search_attr is from :match
bool has_decor = false; // this buffer has decoration
@@ -1950,7 +1947,6 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, int col_rows, s
if (wlv.col >= grid->cols - 1 && schar_cells(mb_schar) == 2) {
mb_c = '>';
mb_l = 1;
- (void)mb_l;
mb_schar = schar_from_ascii(mb_c);
multi_attr = win_hl_attr(wp, HLF_AT);
@@ -1963,30 +1959,58 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, int col_rows, s
wlv.n_extra -= mb_l;
wlv.p_extra += mb_l;
}
- }
- // Only restore search_attr and area_attr after "n_extra" in
- // the next screen line is also done.
- if (wlv.n_extra <= 0) {
- if (search_attr == 0) {
- search_attr = saved_search_attr;
- saved_search_attr = 0;
- }
- if (area_attr == 0 && *ptr != NUL) {
- area_attr = saved_area_attr;
- saved_area_attr = 0;
- }
- if (decor_attr == 0) {
- decor_attr = saved_decor_attr;
- saved_decor_attr = 0;
+ // If a double-width char doesn't fit at the left side display a '<'.
+ if (wlv.filler_todo <= 0 && wlv.skip_cells > 0 && mb_l > 1) {
+ if (wlv.n_extra > 0) {
+ n_extra_next = wlv.n_extra;
+ extra_attr_next = wlv.extra_attr;
+ }
+ wlv.n_extra = 1;
+ wlv.sc_extra = schar_from_ascii(MB_FILLER_CHAR);
+ wlv.sc_final = NUL;
+ mb_schar = schar_from_ascii(' ');
+ mb_c = ' ';
+ mb_l = 1;
+ (void)mb_l;
+ wlv.n_attr++;
+ wlv.extra_attr = win_hl_attr(wp, HLF_AT);
}
+ }
- if (wlv.extra_for_extmark) {
- // wlv.extra_attr should be used at this position but not
- // any further.
+ if (wlv.n_extra <= 0) {
+ // Only restore search_attr and area_attr when there is no "n_extra" to show.
+ if (n_extra_next <= 0) {
+ if (search_attr == 0) {
+ search_attr = saved_search_attr;
+ saved_search_attr = 0;
+ }
+ if (area_attr == 0 && *ptr != NUL) {
+ area_attr = saved_area_attr;
+ saved_area_attr = 0;
+ }
+ if (decor_attr == 0) {
+ decor_attr = saved_decor_attr;
+ saved_decor_attr = 0;
+ }
+ if (wlv.extra_for_extmark) {
+ // wlv.extra_attr should be used at this position but not any further.
+ wlv.reset_extra_attr = true;
+ extra_attr_next = -1;
+ }
+ wlv.extra_for_extmark = false;
+ } else {
+ assert(wlv.sc_extra != NUL || wlv.sc_final != NUL);
+ assert(wlv.p_extra != NULL);
+ wlv.sc_extra = NUL;
+ wlv.sc_final = NUL;
+ wlv.n_extra = n_extra_next;
+ n_extra_next = 0;
+ // wlv.extra_attr should be used at this position, but extra_attr_next
+ // should be used after that.
wlv.reset_extra_attr = true;
+ assert(extra_attr_next >= 0);
}
- wlv.extra_for_extmark = false;
}
} else if (wlv.filler_todo > 0) {
// Wait with reading text until filler lines are done. Still need to
@@ -2563,14 +2587,19 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, int col_rows, s
wp->w_valid |= VALID_WCOL|VALID_WROW|VALID_VIRTCOL;
}
- // Don't override visual selection highlighting.
+ // Use "wlv.extra_attr", but don't override visual selection highlighting.
if (wlv.n_attr > 0 && !search_attr_from_match) {
wlv.char_attr = hl_combine_attr(wlv.char_attr, wlv.extra_attr);
if (wlv.reset_extra_attr) {
wlv.reset_extra_attr = false;
- wlv.extra_attr = 0;
- // search_attr_from_match can be restored now that the extra_attr has been applied
- search_attr_from_match = saved_search_attr_from_match;
+ if (extra_attr_next >= 0) {
+ wlv.extra_attr = extra_attr_next;
+ extra_attr_next = -1;
+ } else {
+ wlv.extra_attr = 0;
+ // search_attr_from_match can be restored now that the extra_attr has been applied
+ search_attr_from_match = saved_search_attr_from_match;
+ }
}
}
@@ -2584,14 +2613,20 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, int col_rows, s
&& wlv.skip_cells <= 0
&& mb_schar != NUL) {
lcs_prec_todo = NUL;
- // TODO(zeertzjq): handle the n_extra > 0 case
- if (schar_cells(mb_schar) > 1 && wlv.n_extra == 0) {
+ if (schar_cells(mb_schar) > 1) {
// Double-width character being overwritten by the "precedes"
// character, need to fill up half the character.
wlv.sc_extra = schar_from_ascii(MB_FILLER_CHAR);
wlv.sc_final = NUL;
+ if (wlv.n_extra > 0) {
+ assert(wlv.p_extra != NULL);
+ n_extra_next = wlv.n_extra;
+ extra_attr_next = wlv.extra_attr;
+ wlv.n_attr = MAX(wlv.n_attr + 1, 2);
+ } else {
+ wlv.n_attr = 2;
+ }
wlv.n_extra = 1;
- wlv.n_attr = 2;
wlv.extra_attr = win_hl_attr(wp, HLF_AT);
}
mb_schar = wp->w_p_lcs_chars.prec;
diff --git a/test/functional/ui/decorations_spec.lua b/test/functional/ui/decorations_spec.lua
index 971d126fa7..99e6b5f78f 100644
--- a/test/functional/ui/decorations_spec.lua
+++ b/test/functional/ui/decorations_spec.lua
@@ -3368,17 +3368,24 @@ describe('decorations: inline virtual text', function()
command("set nowrap")
api.nvim_buf_set_extmark(0, ns, 0, 2, { virt_text = { { string.rep('X', 55), 'Special' } }, virt_text_pos = 'inline' })
feed('$')
- screen:expect{grid=[[
+ screen:expect([[
{10:XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX}cdefgh^i|
{1:~ }|
|
- ]]}
+ ]])
+ command('set list listchars+=precedes:!')
+ screen:expect([[
+ {1:!}{10:XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX}cdefgh^i|
+ {1:~ }|
+ |
+ ]])
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, {
+ hl_mode = 'replace',
virt_text = { { 'α口β̳γ̲=', 'Special' }, { '❤️', 'Special' } },
virt_text_pos = 'inline',
})
@@ -3405,9 +3412,33 @@ describe('decorations: inline virtual text', function()
{1:~ }|
|
]])
+ feed('V')
+ screen:expect([[
+ {10:口β̳γ̲=❤️}{7:34567}^8 |
+ {1:~ }|
+ {8:-- VISUAL LINE --} |
+ ]])
+ command('set list listchars+=precedes:!')
+ screen:expect([[
+ {1:!<}{10:β̳γ̲=❤️}{7:34567}^8 |
+ {1:~ }|
+ {8:-- VISUAL LINE --} |
+ ]])
feed('zl')
screen:expect([[
- {10: β̳γ̲=❤️}34567^8 |
+ {1:!}{10:β̳γ̲=❤️}{7:34567}^8 |
+ {1:~ }|
+ {8:-- VISUAL LINE --} |
+ ]])
+ command('set nolist')
+ screen:expect([[
+ {1:<}{10:β̳γ̲=❤️}{7:34567}^8 |
+ {1:~ }|
+ {8:-- VISUAL LINE --} |
+ ]])
+ feed('<Esc>')
+ screen:expect([[
+ {1:<}{10:β̳γ̲=❤️}34567^8 |
{1:~ }|
|
]])
@@ -3435,9 +3466,21 @@ describe('decorations: inline virtual text', function()
{1:~ }|
|
]])
+ command('set list')
+ screen:expect([[
+ {1:!<}34567^8 |
+ {1:~ }|
+ |
+ ]])
feed('zl')
screen:expect([[
- {10: }34567^8 |
+ {1:!}34567^8 |
+ {1:~ }|
+ |
+ ]])
+ command('set nolist')
+ screen:expect([[
+ {1:<}34567^8 |
{1:~ }|
|
]])