mirror of
https://github.com/neovim/neovim.git
synced 2025-02-25 18:55:25 -06:00
feat(extmarks): virtual text can be right-aligned, truncated #31921
Problem: Right aligned virtual text can cover up buffer text if virtual text is too long Solution: An additional option for `virt_text_pos` called `eol_right_align` has been added to truncate virtual text if it would have otherwise covered up buffer text. This ensures the virtual text extends no further left than EOL.
This commit is contained in:
parent
c6d2cbf8f5
commit
931ee5591f
@ -2609,6 +2609,13 @@ nvim_buf_set_extmark({buffer}, {ns_id}, {line}, {col}, {opts})
|
||||
last).
|
||||
• virt_text_pos : position of virtual text. Possible values:
|
||||
• "eol": right after eol character (default).
|
||||
• "eol_right_align": display right aligned in the window
|
||||
unless the virtual text is longer than the space
|
||||
available. If the virtual text is too long, it is
|
||||
truncated to fit in the window after the EOL character.
|
||||
If the line is wrapped, the virtual text is shown after
|
||||
the end of the line rather than the previous screen
|
||||
line.
|
||||
• "overlay": display over the specified column, without
|
||||
shifting the underlying text.
|
||||
• "right_align": display right aligned in the window.
|
||||
|
@ -626,8 +626,8 @@ Lua module: vim.diagnostic *diagnostic-api*
|
||||
• {hl_mode}? (`'replace'|'combine'|'blend'`) See
|
||||
|nvim_buf_set_extmark()|.
|
||||
• {virt_text}? (`[string,any][]`) See |nvim_buf_set_extmark()|.
|
||||
• {virt_text_pos}? (`'eol'|'overlay'|'right_align'|'inline'`) See
|
||||
|nvim_buf_set_extmark()|.
|
||||
• {virt_text_pos}? (`'eol'|'eol_right_align'|'inline'|'overlay'|'right_align'`)
|
||||
See |nvim_buf_set_extmark()|.
|
||||
• {virt_text_win_col}? (`integer`) See |nvim_buf_set_extmark()|.
|
||||
• {virt_text_hide}? (`boolean`) See |nvim_buf_set_extmark()|.
|
||||
|
||||
|
@ -195,6 +195,8 @@ API
|
||||
• |nvim_open_win()| `relative` field can be set to "laststatus" and "tabline".
|
||||
• |nvim_buf_set_extmark()| `hl_group` field can be an array of layered groups
|
||||
• |vim.hl.range()| now has a optional `timeout` field which allows for a timed highlight
|
||||
• |nvim_buf_set_extmark()| virt_text_pos accepts `eol_right_align` to
|
||||
allow for right aligned text that truncates before covering up buffer text.
|
||||
|
||||
DEFAULTS
|
||||
|
||||
|
9
runtime/lua/vim/_meta/api.lua
generated
9
runtime/lua/vim/_meta/api.lua
generated
@ -589,6 +589,15 @@ function vim.api.nvim_buf_line_count(buffer) end
|
||||
--- (highest priority last).
|
||||
--- - virt_text_pos : position of virtual text. Possible values:
|
||||
--- - "eol": right after eol character (default).
|
||||
--- - "eol_right_align": display right aligned in the window
|
||||
--- unless the virtual text is longer than
|
||||
--- the space available. If the virtual
|
||||
--- text is too long, it is truncated to
|
||||
--- fit in the window after the EOL
|
||||
--- character. If the line is wrapped, the
|
||||
--- virtual text is shown after the end of
|
||||
--- the line rather than the previous
|
||||
--- screen line.
|
||||
--- - "overlay": display over the specified column, without
|
||||
--- shifting the underlying text.
|
||||
--- - "right_align": display right aligned in the window.
|
||||
|
@ -220,7 +220,7 @@ end
|
||||
--- @field virt_text? [string,any][]
|
||||
---
|
||||
--- See |nvim_buf_set_extmark()|.
|
||||
--- @field virt_text_pos? 'eol'|'overlay'|'right_align'|'inline'
|
||||
--- @field virt_text_pos? 'eol'|'eol_right_align'|'inline'|'overlay'|'right_align'
|
||||
---
|
||||
--- See |nvim_buf_set_extmark()|.
|
||||
--- @field virt_text_win_col? integer
|
||||
|
@ -400,6 +400,15 @@ Array nvim_buf_get_extmarks(Buffer buffer, Integer ns_id, Object start, Object e
|
||||
/// (highest priority last).
|
||||
/// - virt_text_pos : position of virtual text. Possible values:
|
||||
/// - "eol": right after eol character (default).
|
||||
/// - "eol_right_align": display right aligned in the window
|
||||
/// unless the virtual text is longer than
|
||||
/// the space available. If the virtual
|
||||
/// text is too long, it is truncated to
|
||||
/// fit in the window after the EOL
|
||||
/// character. If the line is wrapped, the
|
||||
/// virtual text is shown after the end of
|
||||
/// the line rather than the previous
|
||||
/// screen line.
|
||||
/// - "overlay": display over the specified column, without
|
||||
/// shifting the underlying text.
|
||||
/// - "right_align": display right aligned in the window.
|
||||
@ -620,6 +629,8 @@ Integer nvim_buf_set_extmark(Buffer buffer, Integer ns_id, Integer line, Integer
|
||||
virt_text.pos = kVPosOverlay;
|
||||
} else if (strequal("right_align", str.data)) {
|
||||
virt_text.pos = kVPosRightAlign;
|
||||
} else if (strequal("eol_right_align", str.data)) {
|
||||
virt_text.pos = kVPosEndOfLineRightAlign;
|
||||
} else if (strequal("inline", str.data)) {
|
||||
virt_text.pos = kVPosInline;
|
||||
} else {
|
||||
|
@ -15,8 +15,8 @@
|
||||
// actual Decor* data is in decoration_defs.h
|
||||
|
||||
/// Keep in sync with VirtTextPos in decoration_defs.h
|
||||
EXTERN const char *const virt_text_pos_str[]
|
||||
INIT( = { "eol", "overlay", "win_col", "right_align", "inline" });
|
||||
EXTERN const char *const virt_text_pos_str[] INIT( = { "eol", "eol_right_align", "inline",
|
||||
"overlay", "right_align", "win_col" });
|
||||
|
||||
/// Keep in sync with HlMode in decoration_defs.h
|
||||
EXTERN const char *const hl_mode_str[] INIT( = { "", "replace", "combine", "blend" });
|
||||
|
@ -19,10 +19,11 @@ typedef kvec_t(VirtTextChunk) VirtText;
|
||||
/// Keep in sync with virt_text_pos_str[] in decoration.h
|
||||
typedef enum {
|
||||
kVPosEndOfLine,
|
||||
kVPosOverlay,
|
||||
kVPosWinCol,
|
||||
kVPosRightAlign,
|
||||
kVPosEndOfLineRightAlign,
|
||||
kVPosInline,
|
||||
kVPosOverlay,
|
||||
kVPosRightAlign,
|
||||
kVPosWinCol,
|
||||
} VirtTextPos;
|
||||
|
||||
typedef kvec_t(struct virt_line { VirtText line; bool left_col; }) VirtLines;
|
||||
|
@ -263,6 +263,9 @@ static void draw_virt_text(win_T *wp, buf_T *buf, int col_off, int *end_col, int
|
||||
int *const indices = state->ranges_i.items;
|
||||
DecorRangeSlot *const slots = state->slots.items;
|
||||
|
||||
/// Total width of all virtual text with "eol_right_align" alignment
|
||||
int totalWidthOfEolRightAlignedVirtText = 0;
|
||||
|
||||
for (int i = 0; i < end; i++) {
|
||||
DecorRange *item = &slots[indices[i]].range;
|
||||
if (!(item->start_row == state->row && decor_virt_pos(item))) {
|
||||
@ -277,7 +280,44 @@ static void draw_virt_text(win_T *wp, buf_T *buf, int col_off, int *end_col, int
|
||||
if (decor_virt_pos(item) && item->draw_col == -1) {
|
||||
bool updated = true;
|
||||
VirtTextPos pos = decor_virt_pos_kind(item);
|
||||
if (pos == kVPosRightAlign) {
|
||||
|
||||
if (do_eol && pos == kVPosEndOfLineRightAlign) {
|
||||
int eolOffset = 0;
|
||||
if (totalWidthOfEolRightAlignedVirtText == 0) {
|
||||
// Look ahead to the remaining decor items
|
||||
for (int j = i; j < end; j++) {
|
||||
/// A future decor to be handled in this function's call
|
||||
DecorRange *lookaheadItem = &slots[indices[j]].range;
|
||||
|
||||
if (lookaheadItem->start_row != state->row
|
||||
|| !decor_virt_pos(lookaheadItem)
|
||||
|| lookaheadItem->draw_col != -1) {
|
||||
continue;
|
||||
}
|
||||
|
||||
/// The Virtual Text of the decor item we're looking ahead to
|
||||
DecorVirtText *lookaheadVt = NULL;
|
||||
if (item->kind == kDecorKindVirtText) {
|
||||
assert(item->data.vt);
|
||||
lookaheadVt = item->data.vt;
|
||||
}
|
||||
|
||||
if (decor_virt_pos_kind(lookaheadItem) == kVPosEndOfLineRightAlign) {
|
||||
// An extra space is added for single character spacing in EOL alignment
|
||||
totalWidthOfEolRightAlignedVirtText += (lookaheadVt->width + 1);
|
||||
}
|
||||
}
|
||||
|
||||
// Remove one space from the total width since there's no single space after the last entry
|
||||
totalWidthOfEolRightAlignedVirtText--;
|
||||
|
||||
if (totalWidthOfEolRightAlignedVirtText <= (right_pos - state->eol_col)) {
|
||||
eolOffset = right_pos - totalWidthOfEolRightAlignedVirtText - state->eol_col;
|
||||
}
|
||||
}
|
||||
|
||||
item->draw_col = state->eol_col + eolOffset;
|
||||
} else if (pos == kVPosRightAlign) {
|
||||
right_pos -= vt->width;
|
||||
item->draw_col = right_pos;
|
||||
} else if (pos == kVPosEndOfLine && do_eol) {
|
||||
@ -304,7 +344,7 @@ static void draw_virt_text(win_T *wp, buf_T *buf, int col_off, int *end_col, int
|
||||
int vcol = item->draw_col - col_off;
|
||||
int col = draw_virt_text_item(buf, item->draw_col, vt->data.virt_text,
|
||||
vt->hl_mode, max_col, vcol);
|
||||
if (vt->pos == kVPosEndOfLine && do_eol) {
|
||||
if (do_eol && ((vt->pos == kVPosEndOfLine) || (vt->pos == kVPosEndOfLineRightAlign))) {
|
||||
state->eol_col = col + 1;
|
||||
}
|
||||
*end_col = MAX(*end_col, col);
|
||||
|
@ -509,6 +509,69 @@ describe('decorations providers', function()
|
||||
]]}
|
||||
end)
|
||||
|
||||
it('can have virtual text of the style: eol_right_align', function()
|
||||
insert(mulholland)
|
||||
setup_provider [[
|
||||
local hl = api.nvim_get_hl_id_by_name "ErrorMsg"
|
||||
local test_ns = api.nvim_create_namespace "mulholland"
|
||||
function on_do(event, ...)
|
||||
if event == "line" then
|
||||
local win, buf, line = ...
|
||||
api.nvim_buf_set_extmark(buf, test_ns, line, 0, {
|
||||
virt_text = {{'+'}, {'1234567890', 'ErrorMsg'}};
|
||||
virt_text_pos='eol_right_align';
|
||||
ephemeral = true;
|
||||
})
|
||||
end
|
||||
end
|
||||
]]
|
||||
|
||||
screen:expect{grid=[[
|
||||
// just to see if there was an accident |
|
||||
// on Mulholland Drive +{2:1234567890}|
|
||||
try_start(); +{2:1234567890}|
|
||||
bufref_T save_buf; +{2:1234567890}|
|
||||
switch_buffer(&save_buf, buf); +{2:12345678}|
|
||||
posp = getmark(mark, false); +{2:1234567890}|
|
||||
restore_buffer(&save_buf);^ +{2:1234567890}|
|
||||
|
|
||||
]]}
|
||||
end)
|
||||
|
||||
it('multiple eol_right_align', function()
|
||||
insert(mulholland)
|
||||
setup_provider [[
|
||||
local hl = api.nvim_get_hl_id_by_name "ErrorMsg"
|
||||
local test_ns = api.nvim_create_namespace "mulholland"
|
||||
function on_do(event, ...)
|
||||
if event == "line" then
|
||||
local win, buf, line = ...
|
||||
api.nvim_buf_set_extmark(buf, test_ns, line, 0, {
|
||||
virt_text = {{'11111'}};
|
||||
virt_text_pos='eol_right_align';
|
||||
ephemeral = true;
|
||||
})
|
||||
api.nvim_buf_set_extmark(0, test_ns, line, 0, {
|
||||
virt_text = {{'22222'}};
|
||||
virt_text_pos='eol_right_align';
|
||||
ephemeral = true;
|
||||
})
|
||||
end
|
||||
end
|
||||
]]
|
||||
|
||||
screen:expect{grid=[[
|
||||
// just to see if there was an accident |
|
||||
// on Mulholland Drive 11111 22222|
|
||||
try_start(); 11111 22222|
|
||||
bufref_T save_buf; 11111 22222|
|
||||
switch_buffer(&save_buf, buf); 11111 222|
|
||||
posp = getmark(mark, false); 11111 22222|
|
||||
restore_buffer(&save_buf);^ 11111 22222|
|
||||
|
|
||||
]]}
|
||||
end)
|
||||
|
||||
it('virtual text works with wrapped lines', function()
|
||||
insert(mulholland)
|
||||
feed('ggJj3JjJ')
|
||||
|
Loading…
Reference in New Issue
Block a user