mirror of
https://github.com/neovim/neovim.git
synced 2024-12-19 10:45:16 -07:00
feat(ui): inline virtual text
vim-patch:9.0.0067: cannot show virtual text Problem: Cannot show virtual text. Solution: Initial changes for virtual text support, using text properties.7f9969c559
vim-patch:9.0.0116: virtual text not displayed if 'signcolumn' is "yes" Problem: Virtual text not displayed if 'signcolumn' is "yes". Solution: Set c_extra and c_final to NUL.711483cd13
Co-authored-by: bfredl <bjorn.linse@gmail.com>
This commit is contained in:
parent
b11a8c1b5d
commit
efa9b299a7
@ -477,6 +477,8 @@ Array nvim_buf_get_extmarks(Buffer buffer, Integer ns_id, Object start, Object e
|
|||||||
/// - "overlay": display over the specified column, without
|
/// - "overlay": display over the specified column, without
|
||||||
/// shifting the underlying text.
|
/// shifting the underlying text.
|
||||||
/// - "right_align": display right aligned in the window.
|
/// - "right_align": display right aligned in the window.
|
||||||
|
/// - "inline": display at the specified column, and
|
||||||
|
/// shift the buffer text to the right as needed
|
||||||
/// - virt_text_win_col : position the virtual text at a fixed
|
/// - virt_text_win_col : position the virtual text at a fixed
|
||||||
/// window column (starting from the first
|
/// window column (starting from the first
|
||||||
/// text column)
|
/// text column)
|
||||||
@ -695,6 +697,8 @@ Integer nvim_buf_set_extmark(Buffer buffer, Integer ns_id, Integer line, Integer
|
|||||||
decor.virt_text_pos = kVTOverlay;
|
decor.virt_text_pos = kVTOverlay;
|
||||||
} else if (strequal("right_align", str.data)) {
|
} else if (strequal("right_align", str.data)) {
|
||||||
decor.virt_text_pos = kVTRightAlign;
|
decor.virt_text_pos = kVTRightAlign;
|
||||||
|
} else if (strequal("inline", str.data)) {
|
||||||
|
decor.virt_text_pos = kVTInline;
|
||||||
} else {
|
} else {
|
||||||
VALIDATE_S(false, "virt_text_pos", "", {
|
VALIDATE_S(false, "virt_text_pos", "", {
|
||||||
goto error;
|
goto error;
|
||||||
|
@ -23,9 +23,11 @@ typedef enum {
|
|||||||
kVTOverlay,
|
kVTOverlay,
|
||||||
kVTWinCol,
|
kVTWinCol,
|
||||||
kVTRightAlign,
|
kVTRightAlign,
|
||||||
|
kVTInline,
|
||||||
} VirtTextPos;
|
} VirtTextPos;
|
||||||
|
|
||||||
EXTERN const char *const virt_text_pos_str[] INIT(= { "eol", "overlay", "win_col", "right_align" });
|
EXTERN const char *const virt_text_pos_str[] INIT(= { "eol", "overlay", "win_col", "right_align",
|
||||||
|
"inline" });
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
kHlModeUnknown,
|
kHlModeUnknown,
|
||||||
|
@ -1030,6 +1030,9 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool nochange,
|
|||||||
int left_curline_col = 0;
|
int left_curline_col = 0;
|
||||||
int right_curline_col = 0;
|
int right_curline_col = 0;
|
||||||
|
|
||||||
|
VirtText virt_inline = KV_INITIAL_VALUE;
|
||||||
|
size_t virt_inline_i = 0;
|
||||||
|
|
||||||
int match_conc = 0; ///< cchar for match functions
|
int match_conc = 0; ///< cchar for match functions
|
||||||
bool on_last_col = false;
|
bool on_last_col = false;
|
||||||
int syntax_flags = 0;
|
int syntax_flags = 0;
|
||||||
@ -1706,7 +1709,9 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool nochange,
|
|||||||
wlv.n_extra = 0;
|
wlv.n_extra = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (wlv.draw_state == WL_LINE && (area_highlighting || has_spell)) {
|
int extmark_attr = 0;
|
||||||
|
if (wlv.draw_state == WL_LINE
|
||||||
|
&& (area_highlighting || has_spell || (extra_check && !has_fold))) {
|
||||||
// handle Visual or match highlighting in this line
|
// handle Visual or match highlighting in this line
|
||||||
if (wlv.vcol == wlv.fromcol
|
if (wlv.vcol == wlv.fromcol
|
||||||
|| (wlv.vcol + 1 == wlv.fromcol && wlv.n_extra == 0
|
|| (wlv.vcol + 1 == wlv.fromcol && wlv.n_extra == 0
|
||||||
@ -1787,6 +1792,44 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool nochange,
|
|||||||
wlv.char_attr = 0;
|
wlv.char_attr = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (has_decor && v >= 0) {
|
||||||
|
bool selected = (area_active || (area_highlighting && noinvcur
|
||||||
|
&& wlv.vcol == wp->w_virtcol));
|
||||||
|
extmark_attr = decor_redraw_col(wp, (colnr_T)v, wlv.off,
|
||||||
|
selected, &decor_state);
|
||||||
|
|
||||||
|
// we could already be inside an existing virt_line with multiple chunks
|
||||||
|
if (!(virt_inline_i < kv_size(virt_inline))) {
|
||||||
|
DecorState *state = &decor_state;
|
||||||
|
for (size_t i = 0; i < kv_size(state->active); i++) {
|
||||||
|
DecorRange *item = &kv_A(state->active, i);
|
||||||
|
if (!(item->start_row == state->row
|
||||||
|
&& kv_size(item->decor.virt_text)
|
||||||
|
&& item->decor.virt_text_pos == kVTInline)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (item->win_col >= -1 && item->start_col <= v) {
|
||||||
|
virt_inline = item->decor.virt_text;
|
||||||
|
virt_inline_i = 0;
|
||||||
|
item->win_col = -2;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (wlv.n_extra <= 0 && virt_inline_i < kv_size(virt_inline)) {
|
||||||
|
VirtTextChunk vtc = kv_A(virt_inline, virt_inline_i);
|
||||||
|
wlv.p_extra = vtc.text;
|
||||||
|
wlv.n_extra = (int)strlen(wlv.p_extra);
|
||||||
|
wlv.c_extra = NUL;
|
||||||
|
wlv.c_final = NUL;
|
||||||
|
wlv.extra_attr = vtc.hl_id ? syn_id2attr(vtc.hl_id) : 0;
|
||||||
|
n_attr = wlv.n_extra;
|
||||||
|
extmark_attr = 0;
|
||||||
|
virt_inline_i++;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get the next character to put on the screen.
|
// Get the next character to put on the screen.
|
||||||
@ -2019,10 +2062,6 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool nochange,
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (has_decor && v > 0) {
|
if (has_decor && v > 0) {
|
||||||
bool selected = (area_active || (area_highlighting && noinvcur
|
|
||||||
&& wlv.vcol == wp->w_virtcol));
|
|
||||||
int extmark_attr = decor_redraw_col(wp, (colnr_T)v - 1, wlv.off,
|
|
||||||
selected, &decor_state);
|
|
||||||
if (extmark_attr != 0) {
|
if (extmark_attr != 0) {
|
||||||
if (!attr_pri) {
|
if (!attr_pri) {
|
||||||
wlv.char_attr = hl_combine_attr(wlv.char_attr, extmark_attr);
|
wlv.char_attr = hl_combine_attr(wlv.char_attr, extmark_attr);
|
||||||
|
@ -295,17 +295,25 @@ unsigned linetabsize(win_T *wp, linenr_T lnum)
|
|||||||
/// Prepare the structure passed to chartabsize functions.
|
/// Prepare the structure passed to chartabsize functions.
|
||||||
///
|
///
|
||||||
/// "line" is the start of the line, "ptr" is the first relevant character.
|
/// "line" is the start of the line, "ptr" is the first relevant character.
|
||||||
/// When "lnum" is zero do not use text properties that insert text.
|
/// When "lnum" is zero do not use inline virtual text.
|
||||||
void init_chartabsize_arg(chartabsize_T *cts, win_T *wp, linenr_T lnum FUNC_ATTR_UNUSED,
|
void init_chartabsize_arg(chartabsize_T *cts, win_T *wp, linenr_T lnum, colnr_T col, char *line,
|
||||||
colnr_T col, char *line, char *ptr)
|
char *ptr)
|
||||||
{
|
{
|
||||||
cts->cts_win = wp;
|
cts->cts_win = wp;
|
||||||
cts->cts_vcol = col;
|
cts->cts_vcol = col;
|
||||||
cts->cts_line = line;
|
cts->cts_line = line;
|
||||||
cts->cts_ptr = ptr;
|
cts->cts_ptr = ptr;
|
||||||
cts->cts_cur_text_width = 0;
|
cts->cts_cur_text_width = 0;
|
||||||
// TODO(bfredl): actually lookup inline virtual text here
|
|
||||||
cts->cts_has_virt_text = false;
|
cts->cts_has_virt_text = false;
|
||||||
|
cts->cts_row = lnum - 1;
|
||||||
|
|
||||||
|
if (cts->cts_row >= 0) {
|
||||||
|
marktree_itr_get(wp->w_buffer->b_marktree, cts->cts_row, 0, cts->cts_iter);
|
||||||
|
mtkey_t mark = marktree_itr_current(cts->cts_iter);
|
||||||
|
if (mark.pos.row == cts->cts_row) {
|
||||||
|
cts->cts_has_virt_text = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Free any allocated item in "cts".
|
/// Free any allocated item in "cts".
|
||||||
@ -383,7 +391,22 @@ int win_lbr_chartabsize(chartabsize_T *cts, int *headp)
|
|||||||
// First get normal size, without 'linebreak' or virtual text
|
// First get normal size, without 'linebreak' or virtual text
|
||||||
int size = win_chartabsize(wp, s, vcol);
|
int size = win_chartabsize(wp, s, vcol);
|
||||||
if (cts->cts_has_virt_text) {
|
if (cts->cts_has_virt_text) {
|
||||||
// TODO(bfredl): inline virtual text
|
int col = (int)(s - line);
|
||||||
|
while (true) {
|
||||||
|
mtkey_t mark = marktree_itr_current(cts->cts_iter);
|
||||||
|
if (mark.pos.row != cts->cts_row || mark.pos.col > col) {
|
||||||
|
break;
|
||||||
|
} else if (mark.pos.col == col) { // TODO: or maybe unconditionally, what if byte-misaligned?
|
||||||
|
if (!mt_end(mark)) {
|
||||||
|
Decoration decor = get_decor(mark);
|
||||||
|
if (decor.virt_text_pos == kVTInline) {
|
||||||
|
cts->cts_cur_text_width = decor.virt_text_width;
|
||||||
|
size += cts->cts_cur_text_width;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
marktree_itr_next(wp->w_buffer->b_marktree, cts->cts_iter);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int c = (uint8_t)(*s);
|
int c = (uint8_t)(*s);
|
||||||
|
@ -11,9 +11,11 @@ typedef struct {
|
|||||||
win_T *cts_win;
|
win_T *cts_win;
|
||||||
char *cts_line; // start of the line
|
char *cts_line; // start of the line
|
||||||
char *cts_ptr; // current position in line
|
char *cts_ptr; // current position in line
|
||||||
|
int cts_row;
|
||||||
|
|
||||||
bool cts_has_virt_text; // true if if a property inserts text
|
bool cts_has_virt_text; // true if if a property inserts text
|
||||||
int cts_cur_text_width; // width of current inserted text
|
int cts_cur_text_width; // width of current inserted text
|
||||||
|
MarkTreeIter cts_iter[1];
|
||||||
// TODO(bfredl): iterator in to the marktree for scanning virt text
|
// TODO(bfredl): iterator in to the marktree for scanning virt text
|
||||||
|
|
||||||
int cts_vcol; // virtual column at current position
|
int cts_vcol; // virtual column at current position
|
||||||
|
@ -645,6 +645,7 @@ describe('extmark decorations', function()
|
|||||||
[25] = {background = Screen.colors.LightRed};
|
[25] = {background = Screen.colors.LightRed};
|
||||||
[26] = {background=Screen.colors.DarkGrey, foreground=Screen.colors.LightGrey};
|
[26] = {background=Screen.colors.DarkGrey, foreground=Screen.colors.LightGrey};
|
||||||
[27] = {background = Screen.colors.Plum1};
|
[27] = {background = Screen.colors.Plum1};
|
||||||
|
[28] = {foreground = Screen.colors.SlateBlue};
|
||||||
}
|
}
|
||||||
|
|
||||||
ns = meths.create_namespace 'test'
|
ns = meths.create_namespace 'test'
|
||||||
@ -1166,6 +1167,84 @@ end]]
|
|||||||
screen:expect_unchanged(true)
|
screen:expect_unchanged(true)
|
||||||
end)
|
end)
|
||||||
|
|
||||||
|
it('can have virtual text of inline position', function()
|
||||||
|
insert(example_text)
|
||||||
|
feed 'gg'
|
||||||
|
screen:expect{grid=[[
|
||||||
|
^for _,item in ipairs(items) do |
|
||||||
|
local text, hl_id_cell, count = unpack(item) |
|
||||||
|
if hl_id_cell ~= nil then |
|
||||||
|
hl_id = hl_id_cell |
|
||||||
|
end |
|
||||||
|
for _ = 1, (count or 1) do |
|
||||||
|
local cell = line[colpos] |
|
||||||
|
cell.text = text |
|
||||||
|
cell.hl_id = hl_id |
|
||||||
|
colpos = colpos+1 |
|
||||||
|
end |
|
||||||
|
end |
|
||||||
|
{1:~ }|
|
||||||
|
{1:~ }|
|
||||||
|
|
|
||||||
|
]]}
|
||||||
|
|
||||||
|
meths.buf_set_extmark(0, ns, 1, 14, {virt_text={{': ', 'Special'}, {'string', 'Type'}}, virt_text_pos='inline'})
|
||||||
|
screen:expect{grid=[[
|
||||||
|
^for _,item in ipairs(items) do |
|
||||||
|
local text{28:: }{3:string}, hl_id_cell, count = unpack|
|
||||||
|
(item) |
|
||||||
|
if hl_id_cell ~= nil then |
|
||||||
|
hl_id = hl_id_cell |
|
||||||
|
end |
|
||||||
|
for _ = 1, (count or 1) do |
|
||||||
|
local cell = line[colpos] |
|
||||||
|
cell.text = text |
|
||||||
|
cell.hl_id = hl_id |
|
||||||
|
colpos = colpos+1 |
|
||||||
|
end |
|
||||||
|
end |
|
||||||
|
{1:~ }|
|
||||||
|
|
|
||||||
|
]]}
|
||||||
|
|
||||||
|
screen:try_resize(55, 15)
|
||||||
|
screen:expect{grid=[[
|
||||||
|
^for _,item in ipairs(items) do |
|
||||||
|
local text{28:: }{3:string}, hl_id_cell, count = unpack(item|
|
||||||
|
) |
|
||||||
|
if hl_id_cell ~= nil then |
|
||||||
|
hl_id = hl_id_cell |
|
||||||
|
end |
|
||||||
|
for _ = 1, (count or 1) do |
|
||||||
|
local cell = line[colpos] |
|
||||||
|
cell.text = text |
|
||||||
|
cell.hl_id = hl_id |
|
||||||
|
colpos = colpos+1 |
|
||||||
|
end |
|
||||||
|
end |
|
||||||
|
{1:~ }|
|
||||||
|
|
|
||||||
|
]]}
|
||||||
|
|
||||||
|
screen:try_resize(56, 15)
|
||||||
|
screen:expect{grid=[[
|
||||||
|
^for _,item in ipairs(items) do |
|
||||||
|
local text{28:: }{3:string}, hl_id_cell, count = unpack(item)|
|
||||||
|
if hl_id_cell ~= nil then |
|
||||||
|
hl_id = hl_id_cell |
|
||||||
|
end |
|
||||||
|
for _ = 1, (count or 1) do |
|
||||||
|
local cell = line[colpos] |
|
||||||
|
cell.text = text |
|
||||||
|
cell.hl_id = hl_id |
|
||||||
|
colpos = colpos+1 |
|
||||||
|
end |
|
||||||
|
end |
|
||||||
|
{1:~ }|
|
||||||
|
{1:~ }|
|
||||||
|
|
|
||||||
|
]]}
|
||||||
|
end)
|
||||||
end)
|
end)
|
||||||
|
|
||||||
describe('decorations: virtual lines', function()
|
describe('decorations: virtual lines', function()
|
||||||
|
Loading…
Reference in New Issue
Block a user