mirror of
https://github.com/neovim/neovim.git
synced 2024-12-19 18:55:14 -07:00
fix(extmarks): priority order of inline and non-inline virt_text (#27532)
This commit is contained in:
parent
69bdcc6823
commit
a0790558c3
@ -2754,9 +2754,10 @@ nvim_buf_set_extmark({buffer}, {ns_id}, {line}, {col}, {*opts})
|
|||||||
hidden marks, an "invalid" key is added to the "details"
|
hidden marks, an "invalid" key is added to the "details"
|
||||||
array of |nvim_buf_get_extmarks()| and family. If
|
array of |nvim_buf_get_extmarks()| and family. If
|
||||||
"undo_restore" is false, the extmark is deleted instead.
|
"undo_restore" is false, the extmark is deleted instead.
|
||||||
• priority: a priority value for the highlight group or sign
|
• priority: a priority value for the highlight group, sign
|
||||||
attribute. For example treesitter highlighting uses a
|
attribute or virtual text. For virtual text, item with
|
||||||
value of 100.
|
highest priority is drawn last. For example treesitter
|
||||||
|
highlighting uses a value of 100.
|
||||||
• strict: boolean that indicates extmark should not be
|
• strict: boolean that indicates extmark should not be
|
||||||
placed if the line or column value is past the end of the
|
placed if the line or column value is past the end of the
|
||||||
buffer or end of the line respectively. Defaults to true.
|
buffer or end of the line respectively. Defaults to true.
|
||||||
|
7
runtime/lua/vim/_meta/api.lua
generated
7
runtime/lua/vim/_meta/api.lua
generated
@ -576,9 +576,10 @@ function vim.api.nvim_buf_line_count(buffer) end
|
|||||||
--- hidden marks, an "invalid" key is added to the "details"
|
--- hidden marks, an "invalid" key is added to the "details"
|
||||||
--- array of `nvim_buf_get_extmarks()` and family. If
|
--- array of `nvim_buf_get_extmarks()` and family. If
|
||||||
--- "undo_restore" is false, the extmark is deleted instead.
|
--- "undo_restore" is false, the extmark is deleted instead.
|
||||||
--- • priority: a priority value for the highlight group or sign
|
--- • priority: a priority value for the highlight group, sign
|
||||||
--- attribute. For example treesitter highlighting uses a
|
--- attribute or virtual text. For virtual text, item with
|
||||||
--- value of 100.
|
--- highest priority is drawn last. For example treesitter
|
||||||
|
--- highlighting uses a value of 100.
|
||||||
--- • strict: boolean that indicates extmark should not be
|
--- • strict: boolean that indicates extmark should not be
|
||||||
--- placed if the line or column value is past the end of the
|
--- placed if the line or column value is past the end of the
|
||||||
--- buffer or end of the line respectively. Defaults to true.
|
--- buffer or end of the line respectively. Defaults to true.
|
||||||
|
@ -452,9 +452,10 @@ Array nvim_buf_get_extmarks(Buffer buffer, Integer ns_id, Object start, Object e
|
|||||||
/// hidden marks, an "invalid" key is added to the "details"
|
/// hidden marks, an "invalid" key is added to the "details"
|
||||||
/// array of |nvim_buf_get_extmarks()| and family. If
|
/// array of |nvim_buf_get_extmarks()| and family. If
|
||||||
/// "undo_restore" is false, the extmark is deleted instead.
|
/// "undo_restore" is false, the extmark is deleted instead.
|
||||||
/// - priority: a priority value for the highlight group or sign
|
/// - priority: a priority value for the highlight group, sign
|
||||||
/// attribute. For example treesitter highlighting uses a
|
/// attribute or virtual text. For virtual text, item with
|
||||||
/// value of 100.
|
/// highest priority is drawn last. For example treesitter
|
||||||
|
/// highlighting uses a value of 100.
|
||||||
/// - strict: boolean that indicates extmark should not be placed
|
/// - strict: boolean that indicates extmark should not be placed
|
||||||
/// if the line or column value is past the end of the
|
/// if the line or column value is past the end of the
|
||||||
/// buffer or end of the line respectively. Defaults to true.
|
/// buffer or end of the line respectively. Defaults to true.
|
||||||
|
@ -541,7 +541,7 @@ void decor_range_add_sh(DecorState *state, int start_row, int start_col, int end
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Initialize the draw_col of a newly-added virtual text item.
|
/// Initialize the draw_col of a newly-added virtual text item.
|
||||||
static void decor_init_draw_col(int win_col, bool hidden, DecorRange *item)
|
void decor_init_draw_col(int win_col, bool hidden, DecorRange *item)
|
||||||
{
|
{
|
||||||
DecorVirtText *vt = item->kind == kDecorKindVirtText ? item->data.vt : NULL;
|
DecorVirtText *vt = item->kind == kDecorKindVirtText ? item->data.vt : NULL;
|
||||||
VirtTextPos pos = decor_virt_pos_kind(item);
|
VirtTextPos pos = decor_virt_pos_kind(item);
|
||||||
|
@ -52,10 +52,10 @@ typedef struct {
|
|||||||
///< Reflects the order of patterns/captures in the query file.
|
///< Reflects the order of patterns/captures in the query file.
|
||||||
DecorRangeKind kind;
|
DecorRangeKind kind;
|
||||||
/// Screen column to draw the virtual text.
|
/// Screen column to draw the virtual text.
|
||||||
/// When -1, the virtual text may be drawn after deciding where.
|
/// When -1, it should be drawn on the current screen line after deciding where.
|
||||||
/// When -3, the virtual text should be drawn on the next screen line.
|
/// When -3, it may be drawn at a position yet to be assigned.
|
||||||
/// When -10, the virtual text has just been added.
|
/// When -10, it has just been added.
|
||||||
/// When INT_MIN, the virtual text should no longer be drawn.
|
/// When INT_MIN, it should no longer be drawn.
|
||||||
int draw_col;
|
int draw_col;
|
||||||
} DecorRange;
|
} DecorRange;
|
||||||
|
|
||||||
|
@ -769,7 +769,7 @@ static bool has_more_inline_virt(winlinevars_T *wlv, ptrdiff_t v)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void handle_inline_virtual_text(win_T *wp, winlinevars_T *wlv, ptrdiff_t v)
|
static void handle_inline_virtual_text(win_T *wp, winlinevars_T *wlv, ptrdiff_t v, bool selected)
|
||||||
{
|
{
|
||||||
while (wlv->n_extra == 0) {
|
while (wlv->n_extra == 0) {
|
||||||
if (wlv->virt_inline_i >= kv_size(wlv->virt_inline)) {
|
if (wlv->virt_inline_i >= kv_size(wlv->virt_inline)) {
|
||||||
@ -779,6 +779,11 @@ static void handle_inline_virtual_text(win_T *wp, winlinevars_T *wlv, ptrdiff_t
|
|||||||
DecorState *state = &decor_state;
|
DecorState *state = &decor_state;
|
||||||
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->draw_col == -3) {
|
||||||
|
// No more inline virtual text before this non-inline virtual text item,
|
||||||
|
// so its position can be decided now.
|
||||||
|
decor_init_draw_col(wlv->off, selected, item);
|
||||||
|
}
|
||||||
if (item->start_row != state->row
|
if (item->start_row != state->row
|
||||||
|| item->kind != kDecorKindVirtText
|
|| item->kind != kDecorKindVirtText
|
||||||
|| item->data.vt->pos != kVPosInline
|
|| item->data.vt->pos != kVPosInline
|
||||||
@ -1493,6 +1498,8 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, int col_rows, s
|
|||||||
extra_check = true;
|
extra_check = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const bool may_have_inline_virt
|
||||||
|
= !has_foldtext && buf_meta_total(wp->w_buffer, kMTMetaInline) > 0;
|
||||||
int virt_line_index;
|
int virt_line_index;
|
||||||
int virt_line_offset = -1;
|
int virt_line_offset = -1;
|
||||||
// Repeat for the whole displayed line.
|
// Repeat for the whole displayed line.
|
||||||
@ -1656,17 +1663,21 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, int col_rows, s
|
|||||||
|
|
||||||
bool selected = (area_active || (area_highlighting && noinvcur
|
bool selected = (area_active || (area_highlighting && noinvcur
|
||||||
&& wlv.vcol == wp->w_virtcol));
|
&& wlv.vcol == wp->w_virtcol));
|
||||||
|
// When there may be inline virtual text, position of non-inline virtual text
|
||||||
|
// can only be decided after drawing inline virtual text with lower priority.
|
||||||
if (decor_need_recheck) {
|
if (decor_need_recheck) {
|
||||||
decor_recheck_draw_col(wlv.off, selected, &decor_state);
|
if (!may_have_inline_virt) {
|
||||||
|
decor_recheck_draw_col(wlv.off, selected, &decor_state);
|
||||||
|
}
|
||||||
decor_need_recheck = false;
|
decor_need_recheck = false;
|
||||||
}
|
}
|
||||||
if (wlv.filler_todo <= 0) {
|
if (wlv.filler_todo <= 0) {
|
||||||
extmark_attr = decor_redraw_col(wp, (colnr_T)(ptr - line), wlv.off, selected,
|
extmark_attr = decor_redraw_col(wp, (colnr_T)(ptr - line),
|
||||||
&decor_state);
|
may_have_inline_virt ? -3 : wlv.off,
|
||||||
|
selected, &decor_state);
|
||||||
}
|
}
|
||||||
|
if (may_have_inline_virt) {
|
||||||
if (!has_foldtext && buf_meta_total(wp->w_buffer, kMTMetaInline) > 0) {
|
handle_inline_virtual_text(wp, &wlv, ptr - line, selected);
|
||||||
handle_inline_virtual_text(wp, &wlv, ptr - line);
|
|
||||||
if (wlv.n_extra > 0 && wlv.virt_inline_hl_mode <= kHlModeReplace) {
|
if (wlv.n_extra > 0 && wlv.virt_inline_hl_mode <= kHlModeReplace) {
|
||||||
// restore search_attr and area_attr when n_extra is down to zero
|
// restore search_attr and area_attr when n_extra is down to zero
|
||||||
// TODO(bfredl): this is ugly as fuck. look if we can do this some other way.
|
// TODO(bfredl): this is ugly as fuck. look if we can do this some other way.
|
||||||
@ -2665,12 +2676,12 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, int col_rows, s
|
|||||||
&& !has_foldtext) {
|
&& !has_foldtext) {
|
||||||
if (has_decor && *ptr == NUL && lcs_eol == 0 && lcs_eol_todo) {
|
if (has_decor && *ptr == NUL && lcs_eol == 0 && lcs_eol_todo) {
|
||||||
// Tricky: there might be a virtual text just _after_ the last char
|
// Tricky: there might be a virtual text just _after_ the last char
|
||||||
decor_redraw_col(wp, (colnr_T)(ptr - line), wlv.off, false, &decor_state);
|
decor_redraw_col(wp, (colnr_T)(ptr - line), -1, false, &decor_state);
|
||||||
}
|
}
|
||||||
if (*ptr != NUL
|
if (*ptr != NUL
|
||||||
|| (lcs_eol > 0 && lcs_eol_todo)
|
|| (lcs_eol > 0 && lcs_eol_todo)
|
||||||
|| (wlv.n_extra > 0 && (wlv.sc_extra != NUL || *wlv.p_extra != NUL))
|
|| (wlv.n_extra > 0 && (wlv.sc_extra != NUL || *wlv.p_extra != NUL))
|
||||||
|| has_more_inline_virt(&wlv, ptr - line)) {
|
|| (may_have_inline_virt && has_more_inline_virt(&wlv, ptr - line))) {
|
||||||
mb_schar = wp->w_p_lcs_chars.ext;
|
mb_schar = wp->w_p_lcs_chars.ext;
|
||||||
wlv.char_attr = win_hl_attr(wp, HLF_AT);
|
wlv.char_attr = win_hl_attr(wp, HLF_AT);
|
||||||
mb_c = schar_get_first_codepoint(mb_schar);
|
mb_c = schar_get_first_codepoint(mb_schar);
|
||||||
@ -2819,6 +2830,7 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, int col_rows, s
|
|||||||
} else if (!is_wrapped) {
|
} else if (!is_wrapped) {
|
||||||
// Without wrapping, we might need to display right_align and win_col
|
// Without wrapping, we might need to display right_align and win_col
|
||||||
// virt_text for the entire text line.
|
// virt_text for the entire text line.
|
||||||
|
decor_recheck_draw_col(-1, true, &decor_state);
|
||||||
decor_redraw_col(wp, MAXCOL, -1, true, &decor_state);
|
decor_redraw_col(wp, MAXCOL, -1, true, &decor_state);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -2831,7 +2843,7 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, int col_rows, s
|
|||||||
|| (wp->w_p_list && wp->w_p_lcs_chars.eol != NUL
|
|| (wp->w_p_list && wp->w_p_lcs_chars.eol != NUL
|
||||||
&& wlv.p_extra != at_end_str)
|
&& wlv.p_extra != at_end_str)
|
||||||
|| (wlv.n_extra != 0 && (wlv.sc_extra != NUL || *wlv.p_extra != NUL))
|
|| (wlv.n_extra != 0 && (wlv.sc_extra != NUL || *wlv.p_extra != NUL))
|
||||||
|| has_more_inline_virt(&wlv, ptr - line))) {
|
|| (may_have_inline_virt && has_more_inline_virt(&wlv, ptr - line)))) {
|
||||||
const bool wrap = is_wrapped // Wrapping enabled (not a folded line).
|
const bool wrap = is_wrapped // Wrapping enabled (not a folded line).
|
||||||
&& wlv.filler_todo <= 0 // Not drawing diff filler lines.
|
&& wlv.filler_todo <= 0 // Not drawing diff filler lines.
|
||||||
&& lcs_eol_todo // Haven't printed the lcs_eol character.
|
&& lcs_eol_todo // Haven't printed the lcs_eol character.
|
||||||
|
@ -2401,6 +2401,93 @@ describe('extmark decorations', function()
|
|||||||
|
|
||||||
helpers.assert_alive()
|
helpers.assert_alive()
|
||||||
end)
|
end)
|
||||||
|
|
||||||
|
it('priority ordering of overlay or win_col virtual text at same position', function()
|
||||||
|
api.nvim_buf_set_extmark(0, ns, 0, 0, { virt_text = {{'A'}}, virt_text_pos = 'overlay', priority = 100 })
|
||||||
|
api.nvim_buf_set_extmark(0, ns, 0, 0, { virt_text = {{'A'}}, virt_text_win_col = 30, priority = 100 })
|
||||||
|
api.nvim_buf_set_extmark(0, ns, 0, 0, { virt_text = {{'BB'}}, virt_text_pos = 'overlay', priority = 90 })
|
||||||
|
api.nvim_buf_set_extmark(0, ns, 0, 0, { virt_text = {{'BB'}}, virt_text_win_col = 30, priority = 90 })
|
||||||
|
api.nvim_buf_set_extmark(0, ns, 0, 0, { virt_text = {{'CCC'}}, virt_text_pos = 'overlay', priority = 80 })
|
||||||
|
api.nvim_buf_set_extmark(0, ns, 0, 0, { virt_text = {{'CCC'}}, virt_text_win_col = 30, priority = 80 })
|
||||||
|
screen:expect([[
|
||||||
|
^ABC ABC |
|
||||||
|
{1:~ }|*13
|
||||||
|
|
|
||||||
|
]])
|
||||||
|
end)
|
||||||
|
|
||||||
|
it('priority ordering of inline and non-inline virtual text at same char', function()
|
||||||
|
insert(('?'):rep(40) .. ('!'):rep(30))
|
||||||
|
api.nvim_buf_set_extmark(0, ns, 0, 40, { virt_text = {{'A'}}, virt_text_pos = 'overlay', priority = 10 })
|
||||||
|
api.nvim_buf_set_extmark(0, ns, 0, 40, { virt_text = {{'a'}}, virt_text_win_col = 15, priority = 10 })
|
||||||
|
api.nvim_buf_set_extmark(0, ns, 0, 40, { virt_text = {{'BBBB'}}, virt_text_pos = 'inline', priority = 15 })
|
||||||
|
api.nvim_buf_set_extmark(0, ns, 0, 40, { virt_text = {{'C'}}, virt_text_pos = 'overlay', priority = 20 })
|
||||||
|
api.nvim_buf_set_extmark(0, ns, 0, 40, { virt_text = {{'c'}}, virt_text_win_col = 17, priority = 20 })
|
||||||
|
api.nvim_buf_set_extmark(0, ns, 0, 40, { virt_text = {{'DDDD'}}, virt_text_pos = 'inline', priority = 25 })
|
||||||
|
api.nvim_buf_set_extmark(0, ns, 0, 40, { virt_text = {{'E'}}, virt_text_pos = 'overlay', priority = 30 })
|
||||||
|
api.nvim_buf_set_extmark(0, ns, 0, 40, { virt_text = {{'e'}}, virt_text_win_col = 19, priority = 30 })
|
||||||
|
api.nvim_buf_set_extmark(0, ns, 0, 40, { virt_text = {{'FFFF'}}, virt_text_pos = 'inline', priority = 35 })
|
||||||
|
api.nvim_buf_set_extmark(0, ns, 0, 40, { virt_text = {{'G'}}, virt_text_pos = 'overlay', priority = 40 })
|
||||||
|
api.nvim_buf_set_extmark(0, ns, 0, 40, { virt_text = {{'g'}}, virt_text_win_col = 21, priority = 40 })
|
||||||
|
api.nvim_buf_set_extmark(0, ns, 0, 40, { virt_text = {{'HHHH'}}, virt_text_pos = 'inline', priority = 45 })
|
||||||
|
api.nvim_buf_set_extmark(0, ns, 0, 40, { virt_text = {{'I'}}, virt_text_pos = 'overlay', priority = 50 })
|
||||||
|
api.nvim_buf_set_extmark(0, ns, 0, 40, { virt_text = {{'i'}}, virt_text_win_col = 23, priority = 50 })
|
||||||
|
api.nvim_buf_set_extmark(0, ns, 0, 40, { virt_text = {{'JJJJ'}}, virt_text_pos = 'inline', priority = 55 })
|
||||||
|
api.nvim_buf_set_extmark(0, ns, 0, 40, { virt_text = {{'K'}}, virt_text_pos = 'overlay', priority = 60 })
|
||||||
|
api.nvim_buf_set_extmark(0, ns, 0, 40, { virt_text = {{'k'}}, virt_text_win_col = 25, priority = 60 })
|
||||||
|
screen:expect([[
|
||||||
|
???????????????a?c?e????????????????????ABBBCDDDEF|
|
||||||
|
FFGHHHIJJJK!!!!!!!!!!g!i!k!!!!!!!!!!!!!^! |
|
||||||
|
{1:~ }|*12
|
||||||
|
|
|
||||||
|
]])
|
||||||
|
feed('02x$')
|
||||||
|
screen:expect([[
|
||||||
|
???????????????a?c?e??????????????????ABBBCDDDEFFF|
|
||||||
|
GHHHIJJJK!!!!!!!!!!!!g!i!k!!!!!!!!!!!^! |
|
||||||
|
{1:~ }|*12
|
||||||
|
|
|
||||||
|
]])
|
||||||
|
feed('02x$')
|
||||||
|
screen:expect([[
|
||||||
|
???????????????a?c?e?g??????????????ABBBCDDDEFFFGH|
|
||||||
|
HHIJJJK!!!!!!!!!!!!!!!!i!k!!!!!!!!!^! |
|
||||||
|
{1:~ }|*12
|
||||||
|
|
|
||||||
|
]])
|
||||||
|
feed('02x$')
|
||||||
|
screen:expect([[
|
||||||
|
???????????????a?c?e?g????????????ABBBCDDDEFFFGHHH|
|
||||||
|
IJJJK!!!!!!!!!!!!!!!!!!i!k!!!!!!!^! |
|
||||||
|
{1:~ }|*12
|
||||||
|
|
|
||||||
|
]])
|
||||||
|
command('set nowrap')
|
||||||
|
feed('0')
|
||||||
|
screen:expect([[
|
||||||
|
^???????????????a?c?e?g?i?k????????ABBBCDDDEFFFGHHH|
|
||||||
|
{1:~ }|*13
|
||||||
|
|
|
||||||
|
]])
|
||||||
|
feed('2x')
|
||||||
|
screen:expect([[
|
||||||
|
^???????????????a?c?e?g?i?k??????ABBBCDDDEFFFGHHHIJ|
|
||||||
|
{1:~ }|*13
|
||||||
|
|
|
||||||
|
]])
|
||||||
|
feed('2x')
|
||||||
|
screen:expect([[
|
||||||
|
^???????????????a?c?e?g?i?k????ABBBCDDDEFFFGHHHIJJJ|
|
||||||
|
{1:~ }|*13
|
||||||
|
|
|
||||||
|
]])
|
||||||
|
feed('2x')
|
||||||
|
screen:expect([[
|
||||||
|
^???????????????a?c?e?g?i?k??ABBBCDDDEFFFGHHHIJJJK!|
|
||||||
|
{1:~ }|*13
|
||||||
|
|
|
||||||
|
]])
|
||||||
|
end)
|
||||||
end)
|
end)
|
||||||
|
|
||||||
describe('decorations: inline virtual text', function()
|
describe('decorations: inline virtual text', function()
|
||||||
|
Loading…
Reference in New Issue
Block a user