mirror of
https://github.com/neovim/neovim
synced 2025-07-16 17:21:49 +00:00
fix(extmarks): account for rightleft when drawing virt text (#25262)
Co-authored-by: zeertzjq <zeertzjq@outlook.com>
This commit is contained in:
@ -223,7 +223,7 @@ static int line_putchar(buf_T *buf, LineState *s, schar_T *dest, int maxcells, b
|
|||||||
if (*p == TAB) {
|
if (*p == TAB) {
|
||||||
cells = MIN(tabstop_padding(vcol, buf->b_p_ts, buf->b_p_vts_array), maxcells);
|
cells = MIN(tabstop_padding(vcol, buf->b_p_ts, buf->b_p_vts_array), maxcells);
|
||||||
for (int c = 0; c < cells; c++) {
|
for (int c = 0; c < cells; c++) {
|
||||||
dest[c] = schar_from_ascii(' ');
|
dest[rl ? -c : c] = schar_from_ascii(' ');
|
||||||
}
|
}
|
||||||
goto done;
|
goto done;
|
||||||
} else if ((uint8_t)(*p) < 0x80 && u8cc[0] == 0) {
|
} else if ((uint8_t)(*p) < 0x80 && u8cc[0] == 0) {
|
||||||
@ -257,7 +257,7 @@ static int line_putchar(buf_T *buf, LineState *s, schar_T *dest, int maxcells, b
|
|||||||
dest[0] = schar_from_cc(u8c, u8cc);
|
dest[0] = schar_from_cc(u8c, u8cc);
|
||||||
}
|
}
|
||||||
if (cells > 1) {
|
if (cells > 1) {
|
||||||
dest[1] = 0;
|
dest[rl ? -1 : 1] = 0;
|
||||||
}
|
}
|
||||||
done:
|
done:
|
||||||
s->p += c_len;
|
s->p += c_len;
|
||||||
@ -277,12 +277,20 @@ static void draw_virt_text(win_T *wp, buf_T *buf, int col_off, int *end_col, int
|
|||||||
}
|
}
|
||||||
if (item->draw_col == -1) {
|
if (item->draw_col == -1) {
|
||||||
if (item->decor.virt_text_pos == kVTRightAlign) {
|
if (item->decor.virt_text_pos == kVTRightAlign) {
|
||||||
right_pos -= item->decor.virt_text_width;
|
if (wp->w_p_rl) {
|
||||||
|
right_pos += item->decor.virt_text_width;
|
||||||
|
} else {
|
||||||
|
right_pos -= item->decor.virt_text_width;
|
||||||
|
}
|
||||||
item->draw_col = right_pos;
|
item->draw_col = right_pos;
|
||||||
} else if (item->decor.virt_text_pos == kVTEndOfLine && do_eol) {
|
} else if (item->decor.virt_text_pos == kVTEndOfLine && do_eol) {
|
||||||
item->draw_col = state->eol_col;
|
item->draw_col = state->eol_col;
|
||||||
} else if (item->decor.virt_text_pos == kVTWinCol) {
|
} else if (item->decor.virt_text_pos == kVTWinCol) {
|
||||||
item->draw_col = MAX(item->decor.col + col_off, 0);
|
if (wp->w_p_rl) {
|
||||||
|
item->draw_col = MIN(col_off - item->decor.col, wp->w_grid.cols - 1);
|
||||||
|
} else {
|
||||||
|
item->draw_col = MAX(col_off + item->decor.col, 0);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (item->draw_col < 0) {
|
if (item->draw_col < 0) {
|
||||||
@ -297,25 +305,33 @@ static void draw_virt_text(win_T *wp, buf_T *buf, int col_off, int *end_col, int
|
|||||||
}
|
}
|
||||||
if (kv_size(item->decor.virt_text)) {
|
if (kv_size(item->decor.virt_text)) {
|
||||||
col = draw_virt_text_item(buf, item->draw_col, item->decor.virt_text,
|
col = draw_virt_text_item(buf, item->draw_col, item->decor.virt_text,
|
||||||
item->decor.hl_mode, max_col, item->draw_col - col_off);
|
item->decor.hl_mode, max_col, item->draw_col - col_off, wp->w_p_rl);
|
||||||
}
|
}
|
||||||
item->draw_col = INT_MIN; // deactivate
|
item->draw_col = INT_MIN; // deactivate
|
||||||
if (item->decor.virt_text_pos == kVTEndOfLine && do_eol) {
|
if (item->decor.virt_text_pos == kVTEndOfLine && do_eol) {
|
||||||
state->eol_col = col + 1;
|
if (wp->w_p_rl) {
|
||||||
|
state->eol_col = col - 1;
|
||||||
|
} else {
|
||||||
|
state->eol_col = col + 1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
*end_col = MAX(*end_col, col);
|
if (wp->w_p_rl) {
|
||||||
|
*end_col = MIN(*end_col, col);
|
||||||
|
} else {
|
||||||
|
*end_col = MAX(*end_col, col);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static int draw_virt_text_item(buf_T *buf, int col, VirtText vt, HlMode hl_mode, int max_col,
|
static int draw_virt_text_item(buf_T *buf, int col, VirtText vt, HlMode hl_mode, int max_col,
|
||||||
int vcol)
|
int vcol, bool rl)
|
||||||
{
|
{
|
||||||
LineState s = LINE_STATE("");
|
LineState s = LINE_STATE("");
|
||||||
int virt_attr = 0;
|
int virt_attr = 0;
|
||||||
size_t virt_pos = 0;
|
size_t virt_pos = 0;
|
||||||
|
|
||||||
while (col < max_col) {
|
while (rl ? col > max_col : col < max_col) {
|
||||||
if (!*s.p) {
|
if (!*s.p) {
|
||||||
if (virt_pos >= kv_size(vt)) {
|
if (virt_pos >= kv_size(vt)) {
|
||||||
break;
|
break;
|
||||||
@ -346,20 +362,27 @@ static int draw_virt_text_item(buf_T *buf, int col, VirtText vt, HlMode hl_mode,
|
|||||||
attr = virt_attr;
|
attr = virt_attr;
|
||||||
}
|
}
|
||||||
schar_T dummy[2];
|
schar_T dummy[2];
|
||||||
|
bool rl_overwrote_double_width = linebuf_char[col] == 0;
|
||||||
int cells = line_putchar(buf, &s, through ? dummy : &linebuf_char[col],
|
int cells = line_putchar(buf, &s, through ? dummy : &linebuf_char[col],
|
||||||
max_col - col, false, vcol);
|
rl ? col - max_col : max_col - col, rl, vcol);
|
||||||
// If we failed to emit a char, we still need to put a space and advance.
|
// If we failed to emit a char, we still need to put a space and advance.
|
||||||
if (cells < 1) {
|
if (cells < 1) {
|
||||||
linebuf_char[col] = schar_from_ascii(' ');
|
linebuf_char[col] = schar_from_ascii(' ');
|
||||||
cells = 1;
|
cells = 1;
|
||||||
}
|
}
|
||||||
for (int c = 0; c < cells; c++) {
|
for (int c = 0; c < cells; c++) {
|
||||||
linebuf_attr[col++] = attr;
|
linebuf_attr[col] = attr;
|
||||||
|
if (rl) {
|
||||||
|
col--;
|
||||||
|
} else {
|
||||||
|
col++;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (col < max_col && linebuf_char[col] == 0) {
|
// If one half of a double-width char is overwritten,
|
||||||
// If the left half of a double-width char is overwritten,
|
// change the other half to a space so that grid redraws properly,
|
||||||
// change the right half to a space so that grid redraws properly,
|
// but don't advance the current column.
|
||||||
// but don't advance the current column.
|
if ((rl && col > max_col && rl_overwrote_double_width)
|
||||||
|
|| (!rl && col < max_col && linebuf_char[col] == 0)) {
|
||||||
linebuf_char[col] = schar_from_ascii(' ');
|
linebuf_char[col] = schar_from_ascii(' ');
|
||||||
}
|
}
|
||||||
vcol += cells;
|
vcol += cells;
|
||||||
@ -1675,13 +1698,16 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool number_onl
|
|||||||
virt_line_offset = kv_A(virt_lines, virt_line_index).left_col ? 0 : win_col_off(wp);
|
virt_line_offset = kv_A(virt_lines, virt_line_index).left_col ? 0 : win_col_off(wp);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!virt_line_offset) {
|
if (virt_line_offset == 0) {
|
||||||
// Skip the column states if there is a "virt_left_col" line.
|
// Skip the column states if there is a "virt_left_col" line.
|
||||||
wlv.draw_state = WL_BRI - 1;
|
wlv.draw_state = WL_BRI - 1;
|
||||||
} else if (statuscol.draw) {
|
} else if (statuscol.draw) {
|
||||||
// Skip fold, sign and number states if 'statuscolumn' is set.
|
// Skip fold, sign and number states if 'statuscolumn' is set.
|
||||||
wlv.draw_state = WL_STC - 1;
|
wlv.draw_state = WL_STC - 1;
|
||||||
}
|
}
|
||||||
|
if (virt_line_offset >= 0 && wp->w_p_rl) {
|
||||||
|
virt_line_offset = wp->w_grid.cols - 1 - virt_line_offset;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (wlv.draw_state == WL_FOLD - 1 && wlv.n_extra == 0) {
|
if (wlv.draw_state == WL_FOLD - 1 && wlv.n_extra == 0) {
|
||||||
@ -1769,7 +1795,7 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool number_onl
|
|||||||
&& wlv.vcol >= wp->w_virtcol)
|
&& wlv.vcol >= wp->w_virtcol)
|
||||||
|| (number_only && wlv.draw_state > WL_STC))
|
|| (number_only && wlv.draw_state > WL_STC))
|
||||||
&& wlv.filler_todo <= 0) {
|
&& wlv.filler_todo <= 0) {
|
||||||
draw_virt_text(wp, buf, win_col_offset, &wlv.col, grid->cols, wlv.row);
|
draw_virt_text(wp, buf, win_col_offset, &wlv.col, wp->w_p_rl ? -1 : grid->cols, wlv.row);
|
||||||
grid_put_linebuf(grid, wlv.row, 0, wlv.col, -grid->cols, wp->w_p_rl, wp, bg_attr, false);
|
grid_put_linebuf(grid, wlv.row, 0, wlv.col, -grid->cols, wp->w_p_rl, wp, bg_attr, false);
|
||||||
// Pretend we have finished updating the window. Except when
|
// Pretend we have finished updating the window. Except when
|
||||||
// 'cursorcolumn' is set.
|
// 'cursorcolumn' is set.
|
||||||
@ -2805,7 +2831,8 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool number_onl
|
|||||||
? 1 : 0);
|
? 1 : 0);
|
||||||
|
|
||||||
if (has_decor) {
|
if (has_decor) {
|
||||||
has_virttext = decor_redraw_eol(wp, &decor_state, &wlv.line_attr, wlv.col + eol_skip);
|
has_virttext = decor_redraw_eol(wp, &decor_state, &wlv.line_attr,
|
||||||
|
wlv.col + (wp->w_p_rl ? -eol_skip : eol_skip));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (((wp->w_p_cuc
|
if (((wp->w_p_cuc
|
||||||
@ -2893,9 +2920,10 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool number_onl
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (kv_size(fold_vt) > 0) {
|
if (kv_size(fold_vt) > 0) {
|
||||||
draw_virt_text_item(buf, win_col_offset, fold_vt, kHlModeCombine, grid->cols, 0);
|
draw_virt_text_item(buf, win_col_offset, fold_vt, kHlModeCombine,
|
||||||
|
wp->w_p_rl ? -1 : grid->cols, 0, wp->w_p_rl);
|
||||||
}
|
}
|
||||||
draw_virt_text(wp, buf, win_col_offset, &wlv.col, grid->cols, wlv.row);
|
draw_virt_text(wp, buf, win_col_offset, &wlv.col, wp->w_p_rl ? -1 : grid->cols, wlv.row);
|
||||||
grid_put_linebuf(grid, wlv.row, 0, wlv.col, grid->cols, wp->w_p_rl, wp, bg_attr, false);
|
grid_put_linebuf(grid, wlv.row, 0, wlv.col, grid->cols, wp->w_p_rl, wp, bg_attr, false);
|
||||||
wlv.row++;
|
wlv.row++;
|
||||||
|
|
||||||
@ -3159,9 +3187,9 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool number_onl
|
|||||||
int draw_col = wlv.col - wlv.boguscols;
|
int draw_col = wlv.col - wlv.boguscols;
|
||||||
if (virt_line_offset >= 0) {
|
if (virt_line_offset >= 0) {
|
||||||
draw_virt_text_item(buf, virt_line_offset, kv_A(virt_lines, virt_line_index).line,
|
draw_virt_text_item(buf, virt_line_offset, kv_A(virt_lines, virt_line_index).line,
|
||||||
kHlModeReplace, grid->cols, 0);
|
kHlModeReplace, wp->w_p_rl ? -1 : grid->cols, 0, wp->w_p_rl);
|
||||||
} else if (wlv.filler_todo <= 0) {
|
} else if (wlv.filler_todo <= 0) {
|
||||||
draw_virt_text(wp, buf, win_col_offset, &draw_col, grid->cols, wlv.row);
|
draw_virt_text(wp, buf, win_col_offset, &draw_col, wp->w_p_rl ? -1 : grid->cols, wlv.row);
|
||||||
}
|
}
|
||||||
|
|
||||||
grid_put_linebuf(grid, wlv.row, 0, draw_col, grid->cols, wp->w_p_rl, wp, bg_attr, wrap);
|
grid_put_linebuf(grid, wlv.row, 0, draw_col, grid->cols, wp->w_p_rl, wp, bg_attr, wrap);
|
||||||
|
@ -1910,6 +1910,84 @@ describe('extmark decorations', function()
|
|||||||
|
|
|
|
||||||
]]}
|
]]}
|
||||||
end)
|
end)
|
||||||
|
|
||||||
|
it('virtual text works with rightleft', function()
|
||||||
|
screen:try_resize(50, 3)
|
||||||
|
insert('abcdefghijklmn')
|
||||||
|
feed('0')
|
||||||
|
command('set rightleft')
|
||||||
|
meths.buf_set_extmark(0, ns, 0, 0, { virt_text = {{'EOL', 'Underlined'}}})
|
||||||
|
meths.buf_set_extmark(0, ns, 0, 0, { virt_text = {{'right_align', 'Underlined'}}, virt_text_pos = 'right_align' })
|
||||||
|
meths.buf_set_extmark(0, ns, 0, 0, { virt_text = {{'win_col', 'Underlined'}}, virt_text_win_col = 20 })
|
||||||
|
meths.buf_set_extmark(0, ns, 0, 2, { virt_text = {{'overlayed', 'Underlined'}}, virt_text_pos = 'overlay' })
|
||||||
|
screen:expect{grid=[[
|
||||||
|
{28:ngila_thgir} {28:loc_niw} {28:LOE} nml{28:deyalrevo}b^a|
|
||||||
|
{1: ~}|
|
||||||
|
|
|
||||||
|
]]}
|
||||||
|
|
||||||
|
insert(('#'):rep(32))
|
||||||
|
feed('0')
|
||||||
|
screen:expect{grid=[[
|
||||||
|
{28:ngila_tdeyalrevo}ba#####{28:loc_niw}###################^#|
|
||||||
|
{1: ~}|
|
||||||
|
|
|
||||||
|
]]}
|
||||||
|
|
||||||
|
insert(('#'):rep(16))
|
||||||
|
feed('0')
|
||||||
|
screen:expect{grid=[[
|
||||||
|
{28:ngila_thgir}############{28:loc_niw}###################^#|
|
||||||
|
{28:LOE} nml{28:deyalrevo}|
|
||||||
|
|
|
||||||
|
]]}
|
||||||
|
|
||||||
|
insert('###')
|
||||||
|
feed('0')
|
||||||
|
screen:expect{grid=[[
|
||||||
|
#################################################^#|
|
||||||
|
{28:ngila_thgir} {28:loc_niw} {28:LOE} nml{28:deyalrevo}ba#|
|
||||||
|
|
|
||||||
|
]]}
|
||||||
|
|
||||||
|
command('set number')
|
||||||
|
screen:expect{grid=[[
|
||||||
|
#############################################^#{2: 1 }|
|
||||||
|
{28:ngila_thgir} {28:loc_niw} nml{28:deyalrevo}ba#####{2: }|
|
||||||
|
|
|
||||||
|
]]}
|
||||||
|
|
||||||
|
command('set cpoptions+=n')
|
||||||
|
screen:expect{grid=[[
|
||||||
|
#############################################^#{2: 1 }|
|
||||||
|
{28:ngila_thgir} {28:loc_niw} nml{28:deyalrevo}ba#####|
|
||||||
|
|
|
||||||
|
]]}
|
||||||
|
end)
|
||||||
|
|
||||||
|
it('works with double width char and rightleft', function()
|
||||||
|
screen:try_resize(50, 3)
|
||||||
|
insert('abcdefghij口klmnop')
|
||||||
|
feed('0')
|
||||||
|
command('set rightleft')
|
||||||
|
screen:expect{grid=[[
|
||||||
|
ponmlk口jihgfedcb^a|
|
||||||
|
{1: ~}|
|
||||||
|
|
|
||||||
|
]]}
|
||||||
|
meths.buf_set_extmark(0, ns, 0, 2, { virt_text = {{'overlayed', 'Underlined'}}, virt_text_pos = 'overlay' })
|
||||||
|
screen:expect{grid=[[
|
||||||
|
ponmlk {28:deyalrevo}b^a|
|
||||||
|
{1: ~}|
|
||||||
|
|
|
||||||
|
]]}
|
||||||
|
meths.buf_set_extmark(0, ns, 0, 15, { virt_text = {{'古', 'Underlined'}}, virt_text_pos = 'overlay' })
|
||||||
|
screen:expect{grid=[[
|
||||||
|
po{28:古}lk {28:deyalrevo}b^a|
|
||||||
|
{1: ~}|
|
||||||
|
|
|
||||||
|
]]}
|
||||||
|
end)
|
||||||
end)
|
end)
|
||||||
|
|
||||||
describe('decorations: inline virtual text', function()
|
describe('decorations: inline virtual text', function()
|
||||||
@ -4245,6 +4323,7 @@ if (h->n_buckets < new_n_buckets) { // expand
|
|||||||
end)
|
end)
|
||||||
|
|
||||||
it('does not show twice if end_row or end_col is specified #18622', function()
|
it('does not show twice if end_row or end_col is specified #18622', function()
|
||||||
|
screen:try_resize(50, 8)
|
||||||
insert([[
|
insert([[
|
||||||
aaa
|
aaa
|
||||||
bbb
|
bbb
|
||||||
@ -4260,10 +4339,28 @@ if (h->n_buckets < new_n_buckets) { // expand
|
|||||||
dd^d |
|
dd^d |
|
||||||
{1:VIRT LINE 2} |
|
{1:VIRT LINE 2} |
|
||||||
{1:~ }|
|
{1:~ }|
|
||||||
{1:~ }|
|
|
|
||||||
{1:~ }|
|
]]}
|
||||||
{1:~ }|
|
end)
|
||||||
{1:~ }|
|
|
||||||
|
it('works with rightleft', function()
|
||||||
|
screen:try_resize(50, 8)
|
||||||
|
insert([[
|
||||||
|
aaa
|
||||||
|
bbb
|
||||||
|
ccc
|
||||||
|
ddd]])
|
||||||
|
command('set number rightleft')
|
||||||
|
meths.buf_set_extmark(0, ns, 0, 0, {virt_lines = {{{'VIRT LINE 1', 'NonText'}}}, virt_lines_leftcol = true})
|
||||||
|
meths.buf_set_extmark(0, ns, 3, 0, {virt_lines = {{{'VIRT LINE 2', 'NonText'}}}})
|
||||||
|
screen:expect{grid=[[
|
||||||
|
aaa{9: 1 }|
|
||||||
|
{1:1 ENIL TRIV}|
|
||||||
|
bbb{9: 2 }|
|
||||||
|
ccc{9: 3 }|
|
||||||
|
^ddd{9: 4 }|
|
||||||
|
{1:2 ENIL TRIV}{9: }|
|
||||||
|
{1: ~}|
|
||||||
|
|
|
|
||||||
]]}
|
]]}
|
||||||
end)
|
end)
|
||||||
|
@ -3047,6 +3047,39 @@ describe("folded lines", function()
|
|||||||
{11:-- VISUAL LINE --} |
|
{11:-- VISUAL LINE --} |
|
||||||
]])
|
]])
|
||||||
end
|
end
|
||||||
|
|
||||||
|
meths.set_option_value('rightleft', true, {})
|
||||||
|
if multigrid then
|
||||||
|
screen:expect([[
|
||||||
|
## grid 1
|
||||||
|
[2:------------------------------]|
|
||||||
|
[2:------------------------------]|
|
||||||
|
[2:------------------------------]|
|
||||||
|
[2:------------------------------]|
|
||||||
|
[2:------------------------------]|
|
||||||
|
[2:------------------------------]|
|
||||||
|
[3:------------------------------]|
|
||||||
|
## grid 2
|
||||||
|
a si sihT{7: }|
|
||||||
|
{14:hsilgnE dila}^v{7: -}|
|
||||||
|
{20: desopmoc ecnetnes}{19: }{15:--}{7: +│}|
|
||||||
|
{15:······}{20:.evac sih ni}{19: }{15:--}{7: +│}|
|
||||||
|
{1: ~}|
|
||||||
|
{1: ~}|
|
||||||
|
## grid 3
|
||||||
|
{11:-- VISUAL LINE --} |
|
||||||
|
]])
|
||||||
|
else
|
||||||
|
screen:expect([[
|
||||||
|
a si sihT{7: }|
|
||||||
|
{14:hsilgnE dila}^v{7: -}|
|
||||||
|
{20: desopmoc ecnetnes}{19: }{15:--}{7: +│}|
|
||||||
|
{15:······}{20:.evac sih ni}{19: }{15:--}{7: +│}|
|
||||||
|
{1: ~}|
|
||||||
|
{1: ~}|
|
||||||
|
{11:-- VISUAL LINE --} |
|
||||||
|
]])
|
||||||
|
end
|
||||||
end)
|
end)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user