mirror of
https://github.com/neovim/neovim
synced 2025-07-18 10:11:50 +00:00
fix(extmarks): make right_align and win_col work on wrapped line (#23759)
This commit is contained in:
@ -81,7 +81,7 @@ void decor_redraw(buf_T *buf, int row1, int row2, Decoration *decor)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (decor && decor_virt_pos(*decor)) {
|
if (decor && decor_virt_pos(decor)) {
|
||||||
redraw_buf_line_later(buf, row1 + 1, false);
|
redraw_buf_line_later(buf, row1 + 1, false);
|
||||||
if (decor->virt_text_pos == kVTInline) {
|
if (decor->virt_text_pos == kVTInline) {
|
||||||
changed_line_display_buf(buf);
|
changed_line_display_buf(buf);
|
||||||
@ -202,9 +202,9 @@ Decoration get_decor(mtkey_t mark)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// @return true if decor has a virtual position (virtual text or ui_watched)
|
/// @return true if decor has a virtual position (virtual text or ui_watched)
|
||||||
static bool decor_virt_pos(Decoration decor)
|
bool decor_virt_pos(const Decoration *const decor)
|
||||||
{
|
{
|
||||||
return kv_size(decor.virt_text) || decor.ui_watched;
|
return kv_size(decor->virt_text) || decor->ui_watched;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool decor_redraw_start(win_T *wp, int top_row, DecorState *state)
|
bool decor_redraw_start(win_T *wp, int top_row, DecorState *state)
|
||||||
@ -232,7 +232,7 @@ bool decor_redraw_start(win_T *wp, int top_row, DecorState *state)
|
|||||||
|
|
||||||
// Exclude start marks if the end mark position is above the top row
|
// Exclude start marks if the end mark position is above the top row
|
||||||
// Exclude end marks if we have already added the start mark
|
// Exclude end marks if we have already added the start mark
|
||||||
if ((mt_start(mark) && altpos.row < top_row && !decor_virt_pos(decor))
|
if ((mt_start(mark) && altpos.row < top_row && !decor_virt_pos(&decor))
|
||||||
|| (mt_end(mark) && altpos.row >= top_row)) {
|
|| (mt_end(mark) && altpos.row >= top_row)) {
|
||||||
goto next_mark;
|
goto next_mark;
|
||||||
}
|
}
|
||||||
@ -342,7 +342,7 @@ next_mark:
|
|||||||
bool active = false, keep = true;
|
bool active = false, keep = true;
|
||||||
if (item.end_row < state->row
|
if (item.end_row < state->row
|
||||||
|| (item.end_row == state->row && item.end_col <= col)) {
|
|| (item.end_row == state->row && item.end_col <= col)) {
|
||||||
if (!(item.start_row >= state->row && decor_virt_pos(item.decor))) {
|
if (!(item.start_row >= state->row && decor_virt_pos(&item.decor))) {
|
||||||
keep = false;
|
keep = false;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@ -372,10 +372,19 @@ next_mark:
|
|||||||
if (active && item.decor.spell != kNone) {
|
if (active && item.decor.spell != kNone) {
|
||||||
spell = item.decor.spell;
|
spell = item.decor.spell;
|
||||||
}
|
}
|
||||||
if ((item.start_row == state->row && item.start_col <= col)
|
if (item.start_row == state->row && decor_virt_pos(&item.decor)
|
||||||
&& decor_virt_pos(item.decor)
|
&& item.draw_col != INT_MIN) {
|
||||||
&& item.decor.virt_text_pos == kVTOverlay && item.win_col == -1) {
|
if (item.start_col <= col) {
|
||||||
item.win_col = (item.decor.virt_text_hide && hidden) ? -2 : win_col;
|
if (item.decor.virt_text_pos == kVTOverlay && item.draw_col == -1) {
|
||||||
|
item.draw_col = (item.decor.virt_text_hide && hidden) ? INT_MIN : win_col;
|
||||||
|
} else if (item.draw_col == -3) {
|
||||||
|
item.draw_col = -1;
|
||||||
|
}
|
||||||
|
} else if (wp->w_p_wrap
|
||||||
|
&& (item.decor.virt_text_pos == kVTRightAlign
|
||||||
|
|| item.decor.virt_text_pos == kVTWinCol)) {
|
||||||
|
item.draw_col = -3;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (keep) {
|
if (keep) {
|
||||||
kv_A(state->active, j++) = item;
|
kv_A(state->active, j++) = item;
|
||||||
@ -550,7 +559,7 @@ bool decor_redraw_eol(win_T *wp, DecorState *state, int *eol_attr, int eol_col)
|
|||||||
bool has_virttext = false;
|
bool has_virttext = false;
|
||||||
for (size_t i = 0; i < kv_size(state->active); i++) {
|
for (size_t i = 0; i < kv_size(state->active); i++) {
|
||||||
DecorRange item = kv_A(state->active, i);
|
DecorRange item = kv_A(state->active, i);
|
||||||
if (item.start_row == state->row && decor_virt_pos(item.decor)) {
|
if (item.start_row == state->row && decor_virt_pos(&item.decor)) {
|
||||||
has_virttext = true;
|
has_virttext = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -82,7 +82,11 @@ typedef struct {
|
|||||||
Decoration decor;
|
Decoration decor;
|
||||||
int attr_id; // cached lookup of decor.hl_id
|
int attr_id; // cached lookup of decor.hl_id
|
||||||
bool virt_text_owned;
|
bool virt_text_owned;
|
||||||
int win_col;
|
/// Screen column to draw the virtual text.
|
||||||
|
/// When -1, the virtual text may be drawn after deciding where.
|
||||||
|
/// When -3, the virtual text should be drawn on a later screen line.
|
||||||
|
/// When INT_MIN, the virtual text should no longer be drawn.
|
||||||
|
int draw_col;
|
||||||
uint64_t ns_id;
|
uint64_t ns_id;
|
||||||
uint64_t mark_id;
|
uint64_t mark_id;
|
||||||
} DecorRange;
|
} DecorRange;
|
||||||
|
@ -277,35 +277,34 @@ static void draw_virt_text(win_T *wp, buf_T *buf, int col_off, int *end_col, int
|
|||||||
bool do_eol = state->eol_col > -1;
|
bool do_eol = state->eol_col > -1;
|
||||||
for (size_t i = 0; i < kv_size(state->active); i++) {
|
for (size_t i = 0; i < kv_size(state->active); i++) {
|
||||||
DecorRange *item = &kv_A(state->active, i);
|
DecorRange *item = &kv_A(state->active, i);
|
||||||
if (!(item->start_row == state->row
|
if (!(item->start_row == state->row && decor_virt_pos(&item->decor))) {
|
||||||
&& (kv_size(item->decor.virt_text) || item->decor.ui_watched))) {
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (item->win_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;
|
right_pos -= item->decor.virt_text_width;
|
||||||
item->win_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->win_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->win_col = MAX(item->decor.col + col_off, 0);
|
item->draw_col = MAX(item->decor.col + col_off, 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (item->win_col < 0) {
|
if (item->draw_col < 0) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
int col = 0;
|
int col = 0;
|
||||||
if (item->decor.ui_watched) {
|
if (item->decor.ui_watched) {
|
||||||
// send mark position to UI
|
// send mark position to UI
|
||||||
col = item->win_col;
|
col = item->draw_col;
|
||||||
WinExtmark m = { (NS)item->ns_id, item->mark_id, win_row, col };
|
WinExtmark m = { (NS)item->ns_id, item->mark_id, win_row, col };
|
||||||
kv_push(win_extmark_arr, m);
|
kv_push(win_extmark_arr, m);
|
||||||
}
|
}
|
||||||
if (kv_size(item->decor.virt_text)) {
|
if (kv_size(item->decor.virt_text)) {
|
||||||
col = draw_virt_text_item(buf, item->win_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->win_col - col_off);
|
item->decor.hl_mode, max_col, item->draw_col - col_off);
|
||||||
}
|
}
|
||||||
item->win_col = -2; // 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;
|
state->eol_col = col + 1;
|
||||||
}
|
}
|
||||||
@ -876,10 +875,10 @@ static void handle_inline_virtual_text(win_T *wp, winlinevars_T *wlv, ptrdiff_t
|
|||||||
|| item->decor.virt_text_pos != kVTInline) {
|
|| item->decor.virt_text_pos != kVTInline) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (item->win_col >= -1 && item->start_col == v) {
|
if (item->draw_col >= -1 && item->start_col == v) {
|
||||||
wlv->virt_inline = item->decor.virt_text;
|
wlv->virt_inline = item->decor.virt_text;
|
||||||
wlv->virt_inline_i = 0;
|
wlv->virt_inline_i = 0;
|
||||||
item->win_col = -2;
|
item->draw_col = INT_MIN;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -940,25 +940,30 @@ describe('extmark decorations', function()
|
|||||||
]]}
|
]]}
|
||||||
end)
|
end)
|
||||||
|
|
||||||
it('can have virtual text of fixed win_col position', function()
|
it('can have virtual text of right_align and fixed win_col position', function()
|
||||||
insert(example_text)
|
insert(example_text)
|
||||||
feed 'gg'
|
feed 'gg'
|
||||||
meths.buf_set_extmark(0, ns, 1, 0, { virt_text={{'Very', 'ErrorMsg'}}, virt_text_win_col=31, hl_mode='blend'})
|
meths.buf_set_extmark(0, ns, 1, 0, { virt_text={{'Very', 'ErrorMsg'}}, virt_text_win_col=31, hl_mode='blend'})
|
||||||
|
meths.buf_set_extmark(0, ns, 1, 0, { virt_text={{'VERY', 'ErrorMsg'}}, virt_text_pos='right_align', hl_mode='blend'})
|
||||||
meths.buf_set_extmark(0, ns, 2, 10, { virt_text={{'Much', 'ErrorMsg'}}, virt_text_win_col=31, hl_mode='blend'})
|
meths.buf_set_extmark(0, ns, 2, 10, { virt_text={{'Much', 'ErrorMsg'}}, virt_text_win_col=31, hl_mode='blend'})
|
||||||
|
meths.buf_set_extmark(0, ns, 2, 10, { virt_text={{'MUCH', 'ErrorMsg'}}, virt_text_pos='right_align', hl_mode='blend'})
|
||||||
meths.buf_set_extmark(0, ns, 3, 15, { virt_text={{'Error', 'ErrorMsg'}}, virt_text_win_col=31, hl_mode='blend'})
|
meths.buf_set_extmark(0, ns, 3, 15, { virt_text={{'Error', 'ErrorMsg'}}, virt_text_win_col=31, hl_mode='blend'})
|
||||||
|
meths.buf_set_extmark(0, ns, 3, 15, { virt_text={{'ERROR', 'ErrorMsg'}}, virt_text_pos='right_align', hl_mode='blend'})
|
||||||
meths.buf_set_extmark(0, ns, 7, 21, { virt_text={{'-', 'NonText'}}, virt_text_win_col=4, hl_mode='blend'})
|
meths.buf_set_extmark(0, ns, 7, 21, { virt_text={{'-', 'NonText'}}, virt_text_win_col=4, hl_mode='blend'})
|
||||||
|
meths.buf_set_extmark(0, ns, 7, 21, { virt_text={{'-', 'NonText'}}, virt_text_pos='right_align', hl_mode='blend'})
|
||||||
-- empty virt_text should not change anything
|
-- empty virt_text should not change anything
|
||||||
meths.buf_set_extmark(0, ns, 8, 0, { virt_text={{''}}, virt_text_win_col=14, hl_mode='blend'})
|
meths.buf_set_extmark(0, ns, 8, 0, { virt_text={{''}}, virt_text_win_col=14, hl_mode='blend'})
|
||||||
|
meths.buf_set_extmark(0, ns, 8, 0, { virt_text={{''}}, virt_text_pos='right_align', hl_mode='blend'})
|
||||||
|
|
||||||
screen:expect{grid=[[
|
screen:expect{grid=[[
|
||||||
^for _,item in ipairs(items) do |
|
^for _,item in ipairs(items) do |
|
||||||
local text, hl_id_cell, cou{4:Very} unpack(item) |
|
local text, hl_id_cell, cou{4:Very} unpack(ite{4:VERY}|
|
||||||
if hl_id_cell ~= nil then {4:Much} |
|
if hl_id_cell ~= nil then {4:Much} {4:MUCH}|
|
||||||
hl_id = hl_id_cell {4:Error} |
|
hl_id = hl_id_cell {4:Error} {4:ERROR}|
|
||||||
end |
|
end |
|
||||||
for _ = 1, (count or 1) do |
|
for _ = 1, (count or 1) do |
|
||||||
local cell = line[colpos] |
|
local cell = line[colpos] |
|
||||||
{1:-} cell.text = text |
|
{1:-} cell.text = text {1:-}|
|
||||||
cell.hl_id = hl_id |
|
cell.hl_id = hl_id |
|
||||||
colpos = colpos+1 |
|
colpos = colpos+1 |
|
||||||
end |
|
end |
|
||||||
@ -971,14 +976,14 @@ describe('extmark decorations', function()
|
|||||||
feed '3G12|i<cr><esc>'
|
feed '3G12|i<cr><esc>'
|
||||||
screen:expect{grid=[[
|
screen:expect{grid=[[
|
||||||
for _,item in ipairs(items) do |
|
for _,item in ipairs(items) do |
|
||||||
local text, hl_id_cell, cou{4:Very} unpack(item) |
|
local text, hl_id_cell, cou{4:Very} unpack(ite{4:VERY}|
|
||||||
if hl_i {4:Much} |
|
if hl_i {4:Much} {4:MUCH}|
|
||||||
^d_cell ~= nil then |
|
^d_cell ~= nil then |
|
||||||
hl_id = hl_id_cell {4:Error} |
|
hl_id = hl_id_cell {4:Error} {4:ERROR}|
|
||||||
end |
|
end |
|
||||||
for _ = 1, (count or 1) do |
|
for _ = 1, (count or 1) do |
|
||||||
local cell = line[colpos] |
|
local cell = line[colpos] |
|
||||||
{1:-} cell.text = text |
|
{1:-} cell.text = text {1:-}|
|
||||||
cell.hl_id = hl_id |
|
cell.hl_id = hl_id |
|
||||||
colpos = colpos+1 |
|
colpos = colpos+1 |
|
||||||
end |
|
end |
|
||||||
@ -990,13 +995,13 @@ describe('extmark decorations', function()
|
|||||||
feed 'u:<cr>'
|
feed 'u:<cr>'
|
||||||
screen:expect{grid=[[
|
screen:expect{grid=[[
|
||||||
for _,item in ipairs(items) do |
|
for _,item in ipairs(items) do |
|
||||||
local text, hl_id_cell, cou{4:Very} unpack(item) |
|
local text, hl_id_cell, cou{4:Very} unpack(ite{4:VERY}|
|
||||||
if hl_i^d_cell ~= nil then {4:Much} |
|
if hl_i^d_cell ~= nil then {4:Much} {4:MUCH}|
|
||||||
hl_id = hl_id_cell {4:Error} |
|
hl_id = hl_id_cell {4:Error} {4:ERROR}|
|
||||||
end |
|
end |
|
||||||
for _ = 1, (count or 1) do |
|
for _ = 1, (count or 1) do |
|
||||||
local cell = line[colpos] |
|
local cell = line[colpos] |
|
||||||
{1:-} cell.text = text |
|
{1:-} cell.text = text {1:-}|
|
||||||
cell.hl_id = hl_id |
|
cell.hl_id = hl_id |
|
||||||
colpos = colpos+1 |
|
colpos = colpos+1 |
|
||||||
end |
|
end |
|
||||||
@ -1009,14 +1014,14 @@ describe('extmark decorations', function()
|
|||||||
feed '8|i<cr><esc>'
|
feed '8|i<cr><esc>'
|
||||||
screen:expect{grid=[[
|
screen:expect{grid=[[
|
||||||
for _,item in ipairs(items) do |
|
for _,item in ipairs(items) do |
|
||||||
local text, hl_id_cell, cou{4:Very} unpack(item) |
|
local text, hl_id_cell, cou{4:Very} unpack(ite{4:VERY}|
|
||||||
if |
|
if |
|
||||||
^hl_id_cell ~= nil then {4:Much} |
|
^hl_id_cell ~= nil then {4:Much} {4:MUCH}|
|
||||||
hl_id = hl_id_cell {4:Error} |
|
hl_id = hl_id_cell {4:Error} {4:ERROR}|
|
||||||
end |
|
end |
|
||||||
for _ = 1, (count or 1) do |
|
for _ = 1, (count or 1) do |
|
||||||
local cell = line[colpos] |
|
local cell = line[colpos] |
|
||||||
{1:-} cell.text = text |
|
{1:-} cell.text = text {1:-}|
|
||||||
cell.hl_id = hl_id |
|
cell.hl_id = hl_id |
|
||||||
colpos = colpos+1 |
|
colpos = colpos+1 |
|
||||||
end |
|
end |
|
||||||
@ -1024,6 +1029,82 @@ describe('extmark decorations', function()
|
|||||||
{1:~ }|
|
{1:~ }|
|
||||||
|
|
|
|
||||||
]]}
|
]]}
|
||||||
|
|
||||||
|
feed 'jI-- <esc>..........'
|
||||||
|
screen:expect{grid=[[
|
||||||
|
for _,item in ipairs(items) do |
|
||||||
|
local text, hl_id_cell, cou{4:Very} unpack(ite{4:VERY}|
|
||||||
|
if |
|
||||||
|
hl_id_cell ~= nil then {4:Much} {4:MUCH}|
|
||||||
|
--^ -- -- -- -- -- -- --{4:Error}- -- hl_i{4:ERROR}|
|
||||||
|
l_id_cell |
|
||||||
|
end |
|
||||||
|
for _ = 1, (count or 1) do |
|
||||||
|
local cell = line[colpos] |
|
||||||
|
{1:-} cell.text = text {1:-}|
|
||||||
|
cell.hl_id = hl_id |
|
||||||
|
colpos = colpos+1 |
|
||||||
|
end |
|
||||||
|
end |
|
||||||
|
|
|
||||||
|
]]}
|
||||||
|
|
||||||
|
feed '.'
|
||||||
|
screen:expect{grid=[[
|
||||||
|
for _,item in ipairs(items) do |
|
||||||
|
local text, hl_id_cell, cou{4:Very} unpack(ite{4:VERY}|
|
||||||
|
if |
|
||||||
|
hl_id_cell ~= nil then {4:Much} {4:MUCH}|
|
||||||
|
--^ -- -- -- -- -- -- -- -- -- -- -- hl_id |
|
||||||
|
= hl_id_cell {4:Error} {4:ERROR}|
|
||||||
|
end |
|
||||||
|
for _ = 1, (count or 1) do |
|
||||||
|
local cell = line[colpos] |
|
||||||
|
{1:-} cell.text = text {1:-}|
|
||||||
|
cell.hl_id = hl_id |
|
||||||
|
colpos = colpos+1 |
|
||||||
|
end |
|
||||||
|
end |
|
||||||
|
|
|
||||||
|
]]}
|
||||||
|
|
||||||
|
command 'set nowrap'
|
||||||
|
screen:expect{grid=[[
|
||||||
|
for _,item in ipairs(items) do |
|
||||||
|
local text, hl_id_cell, cou{4:Very} unpack(ite{4:VERY}|
|
||||||
|
if |
|
||||||
|
hl_id_cell ~= nil then {4:Much} {4:MUCH}|
|
||||||
|
--^ -- -- -- -- -- -- --{4:Error}- -- -- h{4:ERROR}|
|
||||||
|
end |
|
||||||
|
for _ = 1, (count or 1) do |
|
||||||
|
local cell = line[colpos] |
|
||||||
|
{1:-} cell.text = text {1:-}|
|
||||||
|
cell.hl_id = hl_id |
|
||||||
|
colpos = colpos+1 |
|
||||||
|
end |
|
||||||
|
end |
|
||||||
|
{1:~ }|
|
||||||
|
|
|
||||||
|
]]}
|
||||||
|
|
||||||
|
feed('8zl')
|
||||||
|
screen:expect{grid=[[
|
||||||
|
em in ipairs(items) do |
|
||||||
|
l text, hl_id_cell, count = unp{4:Very}item) {4:VERY}|
|
||||||
|
|
|
||||||
|
ll ~= nil then {4:Much} {4:MUCH}|
|
||||||
|
--^ -- -- -- -- -- -- -- -- -- -{4:Error}hl_id = h{4:ERROR}|
|
||||||
|
|
|
||||||
|
_ = 1, (count or 1) do |
|
||||||
|
local cell = line[colpos] |
|
||||||
|
cell{1:-}text = text {1:-}|
|
||||||
|
cell.hl_id = hl_id |
|
||||||
|
colpos = colpos+1 |
|
||||||
|
|
|
||||||
|
|
|
||||||
|
{1:~ }|
|
||||||
|
|
|
||||||
|
]]}
|
||||||
end)
|
end)
|
||||||
|
|
||||||
it('can have virtual text which combines foreground and background groups', function()
|
it('can have virtual text which combines foreground and background groups', function()
|
||||||
|
Reference in New Issue
Block a user