decorations: add additional styling of virt_text overlays

This commit is contained in:
Björn Linse
2021-02-23 12:16:28 +01:00
parent c12ea02e0b
commit 425bc438ae
5 changed files with 286 additions and 94 deletions

View File

@ -1430,6 +1430,18 @@ Array nvim_buf_get_extmarks(Buffer buffer, Integer ns_id,
/// - "eol": right after eol character (default) /// - "eol": right after eol character (default)
/// - "overlay": display over the specified column, without /// - "overlay": display over the specified column, without
/// shifting the underlying text. /// shifting the underlying text.
/// - virt_text_hide : hide the virtual text when the background
/// text is selected or hidden due to
/// horizontal scroll 'nowrap'
/// - hl_mode : control how highlights are combined with the
/// highlights of the text. Currently only affects
/// virt_text highlights, but might affect `hl_group`
/// in later versions.
/// - "replace": only show the virt_text color. This is the
/// default
/// - "combine": combine with background text color
/// - "blend": blend with background text color.
///
/// - ephemeral : for use with |nvim_set_decoration_provider| /// - ephemeral : for use with |nvim_set_decoration_provider|
/// callbacks. The mark will only be used for the current /// callbacks. The mark will only be used for the current
/// redraw cycle, and not be permantently stored in the /// redraw cycle, and not be permantently stored in the
@ -1477,11 +1489,10 @@ Integer nvim_buf_set_extmark(Buffer buffer, Integer ns_id,
bool ephemeral = false; bool ephemeral = false;
uint64_t id = 0; uint64_t id = 0;
int line2 = -1, hl_id = 0; int line2 = -1;
DecorPriority priority = DECOR_PRIORITY_BASE; Decoration decor = DECORATION_INIT;
colnr_T col2 = -1; colnr_T col2 = -1;
VirtText virt_text = KV_INITIAL_VALUE;
VirtTextPos virt_text_pos = kVTEndOfLine;
bool right_gravity = true; bool right_gravity = true;
bool end_right_gravity = false; bool end_right_gravity = false;
bool end_gravity_set = false; bool end_gravity_set = false;
@ -1528,12 +1539,12 @@ Integer nvim_buf_set_extmark(Buffer buffer, Integer ns_id,
switch (v->type) { switch (v->type) {
case kObjectTypeString: case kObjectTypeString:
hl_group = v->data.string; hl_group = v->data.string;
hl_id = syn_check_group( decor.hl_id = syn_check_group(
(char_u *)(hl_group.data), (char_u *)(hl_group.data),
(int)hl_group.size); (int)hl_group.size);
break; break;
case kObjectTypeInteger: case kObjectTypeInteger:
hl_id = (int)v->data.integer; decor.hl_id = (int)v->data.integer;
break; break;
default: default:
api_set_error(err, kErrorTypeValidation, api_set_error(err, kErrorTypeValidation,
@ -1546,7 +1557,7 @@ Integer nvim_buf_set_extmark(Buffer buffer, Integer ns_id,
"virt_text is not an Array"); "virt_text is not an Array");
goto error; goto error;
} }
virt_text = parse_virt_text(v->data.array, err); decor.virt_text = parse_virt_text(v->data.array, err);
if (ERROR_SET(err)) { if (ERROR_SET(err)) {
goto error; goto error;
} }
@ -1558,9 +1569,33 @@ Integer nvim_buf_set_extmark(Buffer buffer, Integer ns_id,
} }
String str = v->data.string; String str = v->data.string;
if (strequal("eol", str.data)) { if (strequal("eol", str.data)) {
virt_text_pos = kVTEndOfLine; decor.virt_text_pos = kVTEndOfLine;
} else if (strequal("overlay", str.data)) { } else if (strequal("overlay", str.data)) {
virt_text_pos = kVTOverlay; decor.virt_text_pos = kVTOverlay;
} else {
api_set_error(err, kErrorTypeValidation,
"virt_text_pos: invalid value");
goto error;
}
} else if (strequal("virt_text_hide", k.data)) {
decor.virt_text_hide = api_object_to_bool(*v,
"virt_text_hide", false, err);
if (ERROR_SET(err)) {
goto error;
}
} else if (strequal("hl_mode", k.data)) {
if (v->type != kObjectTypeString) {
api_set_error(err, kErrorTypeValidation,
"hl_mode is not a String");
goto error;
}
String str = v->data.string;
if (strequal("replace", str.data)) {
decor.hl_mode = kHlModeReplace;
} else if (strequal("combine", str.data)) {
decor.hl_mode = kHlModeCombine;
} else if (strequal("blend", str.data)) {
decor.hl_mode = kHlModeBlend;
} else { } else {
api_set_error(err, kErrorTypeValidation, api_set_error(err, kErrorTypeValidation,
"virt_text_pos: invalid value"); "virt_text_pos: invalid value");
@ -1583,7 +1618,7 @@ Integer nvim_buf_set_extmark(Buffer buffer, Integer ns_id,
"priority is not a valid value"); "priority is not a valid value");
goto error; goto error;
} }
priority = (DecorPriority)v->data.integer; decor.priority = (DecorPriority)v->data.integer;
} else if (strequal("right_gravity", k.data)) { } else if (strequal("right_gravity", k.data)) {
if (v->type != kObjectTypeBoolean) { if (v->type != kObjectTypeBoolean) {
api_set_error(err, kErrorTypeValidation, api_set_error(err, kErrorTypeValidation,
@ -1631,23 +1666,23 @@ Integer nvim_buf_set_extmark(Buffer buffer, Integer ns_id,
col2 = 0; col2 = 0;
} }
Decoration *decor = NULL, tmp = { 0 }; Decoration *d = NULL;
if (kv_size(virt_text) || priority != DECOR_PRIORITY_BASE) { if (ephemeral) {
d = &decor;
} else if (kv_size(decor.virt_text)
|| decor.priority != DECOR_PRIORITY_BASE) {
// TODO(bfredl): this is a bit sketchy. eventually we should // TODO(bfredl): this is a bit sketchy. eventually we should
// have predefined decorations for both marks/ephemerals // have predefined decorations for both marks/ephemerals
decor = ephemeral ? &tmp : xcalloc(1, sizeof(*decor)); d = xcalloc(1, sizeof(*d));
decor->hl_id = hl_id; *d = decor;
decor->virt_text = virt_text; } else if (decor.hl_id) {
decor->priority = priority; d = decor_hl(decor.hl_id);
decor->virt_text_pos = virt_text_pos;
} else if (hl_id) {
decor = decor_hl(hl_id);
} }
// TODO(bfredl): synergize these two branches even more // TODO(bfredl): synergize these two branches even more
if (ephemeral && decor_state.buf == buf) { if (ephemeral && decor_state.buf == buf) {
decor_add_ephemeral((int)line, (int)col, line2, col2, decor, 0); decor_add_ephemeral((int)line, (int)col, line2, col2, &decor, 0);
} else { } else {
if (ephemeral) { if (ephemeral) {
api_set_error(err, kErrorTypeException, "not yet implemented"); api_set_error(err, kErrorTypeException, "not yet implemented");
@ -1655,14 +1690,14 @@ Integer nvim_buf_set_extmark(Buffer buffer, Integer ns_id,
} }
id = extmark_set(buf, (uint64_t)ns_id, id, (int)line, (colnr_T)col, id = extmark_set(buf, (uint64_t)ns_id, id, (int)line, (colnr_T)col,
line2, col2, decor, right_gravity, line2, col2, d, right_gravity,
end_right_gravity, kExtmarkNoUndo); end_right_gravity, kExtmarkNoUndo);
} }
return (Integer)id; return (Integer)id;
error: error:
clear_virttext(&virt_text); clear_virttext(&decor.virt_text);
return 0; return 0;
} }

View File

@ -230,7 +230,7 @@ static void decor_add(DecorState *state, int start_row, int start_col,
HlRange range = { start_row, start_col, end_row, end_col, HlRange range = { start_row, start_col, end_row, end_col,
attr_id, MAX(priority, decor->priority), attr_id, MAX(priority, decor->priority),
kv_size(decor->virt_text) ? &decor->virt_text : NULL, kv_size(decor->virt_text) ? &decor->virt_text : NULL,
decor->virt_text_pos, decor->virt_text_pos, decor->virt_text_hide, decor->hl_mode,
kv_size(decor->virt_text) && owned, -1 }; kv_size(decor->virt_text) && owned, -1 };
kv_pushp(state->active); kv_pushp(state->active);
@ -245,7 +245,8 @@ static void decor_add(DecorState *state, int start_row, int start_col,
kv_A(state->active, index) = range; kv_A(state->active, index) = range;
} }
int decor_redraw_col(buf_T *buf, int col, int virt_col, DecorState *state) int decor_redraw_col(buf_T *buf, int col, int virt_col, bool hidden,
DecorState *state)
{ {
if (col <= state->col_until) { if (col <= state->col_until) {
return state->current; return state->current;
@ -324,7 +325,7 @@ next_mark:
} }
if ((item.start_row == state->row && item.start_col <= col) if ((item.start_row == state->row && item.start_col <= col)
&& item.virt_text && item.virt_col == -1) { && item.virt_text && item.virt_col == -1) {
item.virt_col = virt_col; item.virt_col = (item.virt_text_hide && hidden) ? -2 : virt_col;
} }
if (keep) { if (keep) {
kv_A(state->active, j++) = item; kv_A(state->active, j++) = item;
@ -345,7 +346,7 @@ void decor_redraw_end(DecorState *state)
VirtText *decor_redraw_virt_text(buf_T *buf, DecorState *state) VirtText *decor_redraw_virt_text(buf_T *buf, DecorState *state)
{ {
decor_redraw_col(buf, MAXCOL, MAXCOL, state); decor_redraw_col(buf, MAXCOL, MAXCOL, false, state);
for (size_t i = 0; i < kv_size(state->active); i++) { for (size_t i = 0; i < kv_size(state->active); i++) {
HlRange item = kv_A(state->active, i); HlRange item = kv_A(state->active, i);
if (item.start_row == state->row && item.virt_text if (item.start_row == state->row && item.virt_text

View File

@ -23,15 +23,26 @@ typedef enum {
kVTOverlay, kVTOverlay,
} VirtTextPos; } VirtTextPos;
typedef enum {
kHlModeUnknown,
kHlModeReplace,
kHlModeCombine,
kHlModeBlend,
} HlMode;
struct Decoration struct Decoration
{ {
int hl_id; // highlight group int hl_id; // highlight group
VirtText virt_text; VirtText virt_text;
VirtTextPos virt_text_pos; VirtTextPos virt_text_pos;
bool virt_text_hide;
HlMode hl_mode;
// TODO(bfredl): style, signs, etc // TODO(bfredl): style, signs, etc
DecorPriority priority; DecorPriority priority;
bool shared; // shared decoration, don't free bool shared; // shared decoration, don't free
}; };
#define DECORATION_INIT { 0, KV_INITIAL_VALUE, kVTEndOfLine, false, \
kHlModeUnknown, DECOR_PRIORITY_BASE, false }
typedef struct { typedef struct {
int start_row; int start_row;
@ -39,9 +50,13 @@ typedef struct {
int end_row; int end_row;
int end_col; int end_col;
int attr_id; int attr_id;
// TODO(bfredl): embed decoration instead, perhaps using an arena
// for ephemerals?
DecorPriority priority; DecorPriority priority;
VirtText *virt_text; VirtText *virt_text;
VirtTextPos virt_text_pos; VirtTextPos virt_text_pos;
bool virt_text_hide;
HlMode hl_mode;
bool virt_text_owned; bool virt_text_owned;
int virt_col; int virt_col;
} HlRange; } HlRange;

View File

@ -2096,6 +2096,8 @@ static int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow,
char_u buf_fold[FOLD_TEXT_LEN + 1]; // Hold value returned by get_foldtext char_u buf_fold[FOLD_TEXT_LEN + 1]; // Hold value returned by get_foldtext
bool area_active = false;
/* draw_state: items that are drawn in sequence: */ /* draw_state: items that are drawn in sequence: */
#define WL_START 0 /* nothing done yet */ #define WL_START 0 /* nothing done yet */
# define WL_CMDLINE WL_START + 1 /* cmdline window column */ # define WL_CMDLINE WL_START + 1 /* cmdline window column */
@ -2850,6 +2852,12 @@ static int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow,
if (draw_state == WL_LINE - 1 && n_extra == 0) { if (draw_state == WL_LINE - 1 && n_extra == 0) {
sign_idx = 0; sign_idx = 0;
draw_state = WL_LINE; draw_state = WL_LINE;
if (has_decor && row == startrow + filler_lines) {
// hide virt_text on text hidden by 'nowrap'
decor_redraw_col(wp->w_buffer, vcol, off, true, &decor_state);
}
if (saved_n_extra) { if (saved_n_extra) {
/* Continue item from end of wrapped line. */ /* Continue item from end of wrapped line. */
n_extra = saved_n_extra; n_extra = saved_n_extra;
@ -2934,10 +2942,14 @@ static int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow,
&& vcol_prev < vcol // not at margin && vcol_prev < vcol // not at margin
&& vcol < tocol)) { && vcol < tocol)) {
area_attr = attr; // start highlighting area_attr = attr; // start highlighting
if (area_highlighting) {
area_active = true;
}
} else if (area_attr != 0 && (vcol == tocol } else if (area_attr != 0 && (vcol == tocol
|| (noinvcur || (noinvcur
&& (colnr_T)vcol == wp->w_virtcol))) { && (colnr_T)vcol == wp->w_virtcol))) {
area_attr = 0; // stop highlighting area_attr = 0; // stop highlighting
area_active = false;
} }
if (!n_extra) { if (!n_extra) {
@ -3397,9 +3409,15 @@ static int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow,
char_attr = hl_combine_attr(spell_attr, char_attr); char_attr = hl_combine_attr(spell_attr, char_attr);
} }
if (wp->w_buffer->terminal) {
char_attr = hl_combine_attr(term_attrs[vcol], char_attr);
}
if (has_decor && v > 0) { if (has_decor && v > 0) {
bool selected = (area_active || (area_highlighting && noinvcur
&& (colnr_T)vcol == wp->w_virtcol));
int extmark_attr = decor_redraw_col(wp->w_buffer, (colnr_T)v-1, off, int extmark_attr = decor_redraw_col(wp->w_buffer, (colnr_T)v-1, off,
&decor_state); selected, &decor_state);
if (extmark_attr != 0) { if (extmark_attr != 0) {
if (!attr_pri) { if (!attr_pri) {
char_attr = hl_combine_attr(char_attr, extmark_attr); char_attr = hl_combine_attr(char_attr, extmark_attr);
@ -3409,10 +3427,6 @@ static int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow,
} }
} }
if (wp->w_buffer->terminal) {
char_attr = hl_combine_attr(term_attrs[vcol], char_attr);
}
// Found last space before word: check for line break. // Found last space before word: check for line break.
if (wp->w_p_lbr && c0 == c && vim_isbreak(c) if (wp->w_p_lbr && c0 == c && vim_isbreak(c)
&& !vim_isbreak((int)(*ptr))) { && !vim_isbreak((int)(*ptr))) {
@ -4355,10 +4369,22 @@ void draw_virt_text(buf_T *buf, int *end_col, int max_col)
virt_pos++; virt_pos++;
continue; continue;
} }
int cells = line_putchar(&s, &linebuf_char[col], 2, false); int attr;
linebuf_attr[col++] = virt_attr; bool through = false;
if (item->hl_mode == kHlModeCombine) {
attr = hl_combine_attr(linebuf_attr[col], virt_attr);
} else if (item->hl_mode == kHlModeBlend) {
through = (*s.p == ' ');
attr = hl_blend_attrs(linebuf_attr[col], virt_attr, &through);
} else {
attr = virt_attr;
}
schar_T dummy[2];
int cells = line_putchar(&s, through ? dummy : &linebuf_char[col],
max_col-col, false);
linebuf_attr[col++] = attr;
if (cells > 1) { if (cells > 1) {
linebuf_attr[col++] = virt_attr; linebuf_attr[col++] = attr;
} }
} }
*end_col = MAX(*end_col, col); *end_col = MAX(*end_col, col);

View File

@ -8,6 +8,7 @@ local exec_lua = helpers.exec_lua
local exec = helpers.exec local exec = helpers.exec
local expect_events = helpers.expect_events local expect_events = helpers.expect_events
local meths = helpers.meths local meths = helpers.meths
local command = helpers.command
describe('decorations providers', function() describe('decorations providers', function()
local screen local screen
@ -314,11 +315,30 @@ describe('extmark decorations', function()
[2] = {foreground = Screen.colors.Brown}; [2] = {foreground = Screen.colors.Brown};
[3] = {bold = true, foreground = Screen.colors.SeaGreen}; [3] = {bold = true, foreground = Screen.colors.SeaGreen};
[4] = {background = Screen.colors.Red1, foreground = Screen.colors.Gray100}; [4] = {background = Screen.colors.Red1, foreground = Screen.colors.Gray100};
[5] = {foreground = Screen.colors.Brown, bold = true};
[6] = {foreground = Screen.colors.DarkCyan};
[7] = {foreground = Screen.colors.Grey0, background = tonumber('0xff4c4c')};
[8] = {foreground = tonumber('0x180606'), background = tonumber('0xff4c4c')};
[9] = {foreground = tonumber('0xe40c0c'), background = tonumber('0xff4c4c'), bold = true};
[10] = {foreground = tonumber('0xb20000'), background = tonumber('0xff4c4c')};
[11] = {blend = 30, background = Screen.colors.Red1};
[12] = {foreground = Screen.colors.Brown, blend = 30, background = Screen.colors.Red1, bold = true};
[13] = {foreground = Screen.colors.Fuchsia};
[14] = {background = Screen.colors.Red1, foreground = Screen.colors.Black};
[15] = {background = Screen.colors.Red1, foreground = tonumber('0xb20000')};
[16] = {blend = 30, background = Screen.colors.Red1, foreground = Screen.colors.Magenta1};
[17] = {bold = true, foreground = Screen.colors.Brown, background = Screen.colors.LightGrey};
[18] = {background = Screen.colors.LightGrey};
[19] = {foreground = Screen.colors.Cyan4, background = Screen.colors.LightGrey};
[20] = {foreground = tonumber('0x180606'), background = tonumber('0xf13f3f')};
[21] = {foreground = Screen.colors.Gray0, background = tonumber('0xf13f3f')};
[22] = {foreground = tonumber('0xb20000'), background = tonumber('0xf13f3f')};
[23] = {foreground = Screen.colors.Magenta1, background = Screen.colors.LightGrey};
[24] = {bold = true};
} }
end) end)
it('can have virtual text of overlay style', function() local example_text = [[
insert [[
for _,item in ipairs(items) do for _,item in ipairs(items) do
local text, hl_id_cell, count = unpack(item) local text, hl_id_cell, count = unpack(item)
if hl_id_cell ~= nil then if hl_id_cell ~= nil then
@ -331,69 +351,164 @@ for _,item in ipairs(items) do
colpos = colpos+1 colpos = colpos+1
end end
end]] end]]
feed 'gg'
local ns = meths.create_namespace 'test' it('can have virtual text of overlay position', function()
for i = 1,9 do insert(example_text)
meths.buf_set_extmark(0, ns, i, 0, { virt_text={{'|', 'LineNr'}}, virt_text_pos='overlay'}) feed 'gg'
if i == 3 or (i >= 6 and i <= 9) then
meths.buf_set_extmark(0, ns, i, 4, { virt_text={{'|', 'NonText'}}, virt_text_pos='overlay'}) local ns = meths.create_namespace 'test'
for i = 1,9 do
meths.buf_set_extmark(0, ns, i, 0, { virt_text={{'|', 'LineNr'}}, virt_text_pos='overlay'})
if i == 3 or (i >= 6 and i <= 9) then
meths.buf_set_extmark(0, ns, i, 4, { virt_text={{'|', 'NonText'}}, virt_text_pos='overlay'})
end
end end
end meths.buf_set_extmark(0, ns, 9, 10, { virt_text={{'foo'}, {'bar', 'MoreMsg'}, {'!!', 'ErrorMsg'}}, virt_text_pos='overlay'})
meths.buf_set_extmark(0, ns, 9, 10, { virt_text={{'foo'}, {'bar', 'MoreMsg'}, {'!!', 'ErrorMsg'}}, virt_text_pos='overlay'})
-- can "float" beyond end of line -- can "float" beyond end of line
meths.buf_set_extmark(0, ns, 5, 28, { virt_text={{'loopy', 'ErrorMsg'}}, virt_text_pos='overlay'}) meths.buf_set_extmark(0, ns, 5, 28, { virt_text={{'loopy', 'ErrorMsg'}}, virt_text_pos='overlay'})
-- bound check: right edge of window -- bound check: right edge of window
meths.buf_set_extmark(0, ns, 2, 26, { virt_text={{'bork bork bork ' }, {'bork bork bork', 'ErrorMsg'}}, virt_text_pos='overlay'}) meths.buf_set_extmark(0, ns, 2, 26, { virt_text={{'bork bork bork ' }, {'bork bork bork', 'ErrorMsg'}}, virt_text_pos='overlay'})
screen:expect{grid=[[ screen:expect{grid=[[
^for _,item in ipairs(items) do | ^for _,item in ipairs(items) do |
{2:|} local text, hl_id_cell, count = unpack(item) | {2:|} local text, hl_id_cell, count = unpack(item) |
{2:|} if hl_id_cell ~= nil tbork bork bork {4:bork bork}| {2:|} if hl_id_cell ~= nil tbork bork bork {4:bork bork}|
{2:|} {1:|} hl_id = hl_id_cell | {2:|} {1:|} hl_id = hl_id_cell |
{2:|} end | {2:|} end |
{2:|} for _ = 1, (count or 1) {4:loopy} | {2:|} for _ = 1, (count or 1) {4:loopy} |
{2:|} {1:|} local cell = line[colpos] | {2:|} {1:|} local cell = line[colpos] |
{2:|} {1:|} cell.text = text | {2:|} {1:|} cell.text = text |
{2:|} {1:|} cell.hl_id = hl_id | {2:|} {1:|} cell.hl_id = hl_id |
{2:|} {1:|} cofoo{3:bar}{4:!!}olpos+1 | {2:|} {1:|} cofoo{3:bar}{4:!!}olpos+1 |
end | end |
end | end |
{1:~ }| {1:~ }|
{1:~ }| {1:~ }|
| |
]]} ]]}
-- handles broken lines -- handles broken lines
screen:try_resize(22, 25) screen:try_resize(22, 25)
screen:expect{grid=[[ screen:expect{grid=[[
^for _,item in ipairs(i| ^for _,item in ipairs(i|
tems) do | tems) do |
{2:|} local text, hl_id_| {2:|} local text, hl_id_|
cell, count = unpack(i| cell, count = unpack(i|
tem) | tem) |
{2:|} if hl_id_cell ~= n| {2:|} if hl_id_cell ~= n|
il tbork bork bork {4:bor}| il tbork bork bork {4:bor}|
{2:|} {1:|} hl_id = hl_id_| {2:|} {1:|} hl_id = hl_id_|
cell | cell |
{2:|} end | {2:|} end |
{2:|} for _ = 1, (count | {2:|} for _ = 1, (count |
or 1) {4:loopy} | or 1) {4:loopy} |
{2:|} {1:|} local cell = l| {2:|} {1:|} local cell = l|
ine[colpos] | ine[colpos] |
{2:|} {1:|} cell.text = te| {2:|} {1:|} cell.text = te|
xt | xt |
{2:|} {1:|} cell.hl_id = h| {2:|} {1:|} cell.hl_id = h|
l_id | l_id |
{2:|} {1:|} cofoo{3:bar}{4:!!}olpo| {2:|} {1:|} cofoo{3:bar}{4:!!}olpo|
s+1 | s+1 |
end | end |
end | end |
{1:~ }| {1:~ }|
{1:~ }| {1:~ }|
| |
]]} ]]}
end)
it('can have virtual text of overlay position and styling', function()
insert(example_text)
feed 'gg'
local ns = meths.create_namespace 'test'
command 'set ft=lua'
command 'syntax on'
screen:expect{grid=[[
{5:^for} _,item {5:in} {6:ipairs}(items) {5:do} |
{5:local} text, hl_id_cell, count = unpack(item) |
{5:if} hl_id_cell ~= {13:nil} {5:then} |
hl_id = hl_id_cell |
{5:end} |
{5:for} _ = {13:1}, (count {5:or} {13:1}) {5:do} |
{5:local} cell = line[colpos] |
cell.text = text |
cell.hl_id = hl_id |
colpos = colpos+{13:1} |
{5:end} |
{5:end} |
{1:~ }|
{1:~ }|
|
]]}
command 'hi Blendy guibg=Red blend=30'
meths.buf_set_extmark(0, ns, 1, 5, { virt_text={{'blendy text - here', 'Blendy'}}, virt_text_pos='overlay', hl_mode='blend'})
meths.buf_set_extmark(0, ns, 2, 5, { virt_text={{'combining color', 'Blendy'}}, virt_text_pos='overlay', hl_mode='combine'})
meths.buf_set_extmark(0, ns, 3, 5, { virt_text={{'replacing color', 'Blendy'}}, virt_text_pos='overlay', hl_mode='replace'})
meths.buf_set_extmark(0, ns, 4, 5, { virt_text={{'blendy text - here', 'Blendy'}}, virt_text_pos='overlay', hl_mode='blend', virt_text_hide=true})
meths.buf_set_extmark(0, ns, 5, 5, { virt_text={{'combining color', 'Blendy'}}, virt_text_pos='overlay', hl_mode='combine', virt_text_hide=true})
meths.buf_set_extmark(0, ns, 6, 5, { virt_text={{'replacing color', 'Blendy'}}, virt_text_pos='overlay', hl_mode='replace', virt_text_hide=true})
screen:expect{grid=[[
{5:^for} _,item {5:in} {6:ipairs}(items) {5:do} |
{5:l}{8:blen}{7:dy}{10:e}{7:text}{10:h}{7:-}{10:_}{7:here}ell, count = unpack(item) |
{5:i}{12:c}{11:ombining color} {13:nil} {5:then} |
{11:replacing color}d_cell |
{5:e}{8:bl}{14:endy}{15:i}{14:text}{15:o}{14:-}{15:o}{14:h}{7:ere} |
{5:f}{12:co}{11:mbini}{16:n}{11:g color}t {5:or} {13:1}) {5:do} |
{11:replacing color} line[colpos] |
cell.text = text |
cell.hl_id = hl_id |
colpos = colpos+{13:1} |
{5:end} |
{5:end} |
{1:~ }|
{1:~ }|
|
]]}
feed 'V5G'
screen:expect{grid=[[
{17:for}{18: _,item }{17:in}{18: }{19:ipairs}{18:(items) }{17:do} |
{18: }{17:l}{20:blen}{21:dy}{22:e}{21:text}{22:h}{21:-}{22:_}{21:here}{18:ell, count = unpack(item)} |
{18: }{17:i}{12:c}{11:ombining color}{18: }{23:nil}{18: }{17:then} |
{18: }{11:replacing color}{18:d_cell} |
{18: }{5:^e}{17:nd} |
{5:f}{12:co}{11:mbini}{16:n}{11:g color}t {5:or} {13:1}) {5:do} |
{11:replacing color} line[colpos] |
cell.text = text |
cell.hl_id = hl_id |
colpos = colpos+{13:1} |
{5:end} |
{5:end} |
{1:~ }|
{1:~ }|
{24:-- VISUAL LINE --} |
]]}
feed 'jj'
screen:expect{grid=[[
{17:for}{18: _,item }{17:in}{18: }{19:ipairs}{18:(items) }{17:do} |
{18: }{17:l}{20:blen}{21:dy}{22:e}{21:text}{22:h}{21:-}{22:_}{21:here}{18:ell, count = unpack(item)} |
{18: }{17:i}{12:c}{11:ombining color}{18: }{23:nil}{18: }{17:then} |
{18: }{11:replacing color}{18:d_cell} |
{18: }{17:end} |
{18: }{17:for}{18: _ = }{23:1}{18:, (count }{17:or}{18: }{23:1}{18:) }{17:do} |
{18: }^ {18: }{17:local}{18: cell = line[colpos]} |
cell.text = text |
cell.hl_id = hl_id |
colpos = colpos+{13:1} |
{5:end} |
{5:end} |
{1:~ }|
{1:~ }|
{24:-- VISUAL LINE --} |
]]}
end) end)
end) end)