decorations: allow virt_text overlay at any column

This commit is contained in:
Björn Linse
2021-02-15 14:00:34 +01:00
parent d623400cad
commit 4781333a7a
5 changed files with 238 additions and 69 deletions

View File

@@ -188,20 +188,21 @@ bool decor_redraw_start(buf_T *buf, int top_row, DecorState *state)
goto next_mark;
}
int attr_id = decor->hl_id > 0 ? syn_id2attr(decor->hl_id) : 0;
VirtText *vt = kv_size(decor->virt_text) ? &decor->virt_text : NULL;
HlRange range;
if (mark.id&MARKTREE_END_FLAG) {
range = (HlRange){ altpos.row, altpos.col, mark.row, mark.col,
attr_id, decor->priority, vt, false };
decor_add(state, altpos.row, altpos.col, mark.row, mark.col,
decor, false, 0);
} else {
range = (HlRange){ mark.row, mark.col, altpos.row,
altpos.col, attr_id, decor->priority, vt, false };
if (altpos.row == -1) {
altpos.row = mark.row;
altpos.col = mark.col;
}
decor_add(state, mark.row, mark.col, altpos.row, altpos.col,
decor, false, 0);
}
hlrange_activate(range, state);
next_mark:
if (marktree_itr_node_done(state->itr)) {
marktree_itr_next(buf->b_marktree, state->itr);
break;
}
marktree_itr_next(buf->b_marktree, state->itr);
@@ -220,41 +221,39 @@ bool decor_redraw_line(buf_T *buf, int row, DecorState *state)
return true; // TODO(bfredl): be more precise
}
static void hlrange_activate(HlRange range, DecorState *state)
static void decor_add(DecorState *state, int start_row, int start_col,
int end_row, int end_col, Decoration *decor, bool owned,
DecorPriority priority)
{
// Get size before preparing the push, to have the number of elements
size_t s = kv_size(state->active);
int attr_id = decor->hl_id > 0 ? syn_id2attr(decor->hl_id) : 0;
HlRange range = { start_row, start_col, end_row, end_col,
attr_id, MAX(priority, decor->priority),
kv_size(decor->virt_text) ? &decor->virt_text : NULL,
decor->virt_text_pos,
kv_size(decor->virt_text) && owned, -1 };
kv_pushp(state->active);
size_t dest_index = 0;
// Determine insertion dest_index
while (dest_index < s) {
HlRange item = kv_A(state->active, dest_index);
if (item.priority > range.priority) {
size_t index;
for (index = kv_size(state->active)-1; index > 0; index--) {
HlRange item = kv_A(state->active, index-1);
if (item.priority <= range.priority) {
break;
}
dest_index++;
}
// Splice
for (size_t index = s; index > dest_index; index--) {
kv_A(state->active, index) = kv_A(state->active, index-1);
}
// Insert
kv_A(state->active, dest_index) = range;
kv_A(state->active, index) = range;
}
int decor_redraw_col(buf_T *buf, int col, DecorState *state)
int decor_redraw_col(buf_T *buf, int col, int virt_col, DecorState *state)
{
if (col <= state->col_until) {
return state->current;
}
state->col_until = MAXCOL;
while (true) {
// TODO(bfredl): check duplicate entry in "intersection"
// branch
mtmark_t mark = marktree_itr_current(state->itr);
if (mark.row < 0 || mark.row > state->row) {
break;
@@ -278,6 +277,11 @@ int decor_redraw_col(buf_T *buf, int col, DecorState *state)
}
Decoration *decor = item->decor;
if (endpos.row == -1) {
endpos.row = mark.row;
endpos.col = mark.col;
}
if (endpos.row < mark.row
|| (endpos.row == mark.row && endpos.col <= mark.col)) {
if (!kv_size(decor->virt_text)) {
@@ -285,12 +289,8 @@ int decor_redraw_col(buf_T *buf, int col, DecorState *state)
}
}
int attr_id = decor->hl_id > 0 ? syn_id2attr(decor->hl_id) : 0;
VirtText *vt = kv_size(decor->virt_text) ? &decor->virt_text : NULL;
hlrange_activate((HlRange){ mark.row, mark.col,
endpos.row, endpos.col,
attr_id, decor->priority,
vt, false }, state);
decor_add(state, mark.row, mark.col, endpos.row, endpos.col,
decor, false, 0);
next_mark:
marktree_itr_next(buf->b_marktree, state->itr);
@@ -310,7 +310,7 @@ next_mark:
if (item.start_row < state->row
|| (item.start_row == state->row && item.start_col <= col)) {
active = true;
if (item.end_row == state->row) {
if (item.end_row == state->row && item.end_col > col) {
state->col_until = MIN(state->col_until, item.end_col-1);
}
} else {
@@ -322,8 +322,12 @@ next_mark:
if (active && item.attr_id > 0) {
attr = hl_combine_attr(attr, item.attr_id);
}
if ((item.start_row == state->row && item.start_col <= col)
&& item.virt_text && item.virt_col == -1) {
item.virt_col = virt_col;
}
if (keep) {
kv_A(state->active, j++) = kv_A(state->active, i);
kv_A(state->active, j++) = item;
} else if (item.virt_text_owned) {
clear_virttext(item.virt_text);
xfree(item.virt_text);
@@ -341,21 +345,20 @@ void decor_redraw_end(DecorState *state)
VirtText *decor_redraw_virt_text(buf_T *buf, DecorState *state)
{
decor_redraw_col(buf, MAXCOL, state);
decor_redraw_col(buf, MAXCOL, MAXCOL, state);
for (size_t i = 0; i < kv_size(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
&& item.virt_text_pos == kVTEndOfLine) {
return item.virt_text;
}
}
return NULL;
}
void decor_add_ephemeral(int attr_id, int start_row, int start_col,
int end_row, int end_col, DecorPriority priority,
VirtText *virt_text)
void decor_add_ephemeral(int start_row, int start_col, int end_row, int end_col,
Decoration *decor, DecorPriority priority)
{
hlrange_activate(((HlRange){ start_row, start_col, end_row, end_col, attr_id,
priority, virt_text, virt_text != NULL }),
&decor_state);
decor_add(&decor_state, start_row, start_col, end_row, end_col, decor, true,
priority);
}