feat(decorations): support more than one virt_lines block

This commit is contained in:
Björn Linse 2021-10-13 21:35:37 +02:00
parent 8ade2f5b04
commit 8d7816cf27
13 changed files with 130 additions and 106 deletions

View File

@ -247,7 +247,6 @@ Boolean nvim_buf_detach(uint64_t channel_id, Buffer buffer, Error *err)
} }
void nvim__buf_redraw_range(Buffer buffer, Integer first, Integer last, Error *err) void nvim__buf_redraw_range(Buffer buffer, Integer first, Integer last, Error *err)
FUNC_API_LUA_ONLY
{ {
buf_T *buf = find_buffer_by_handle(buffer, err); buf_T *buf = find_buffer_by_handle(buffer, err);
if (!buf) { if (!buf) {
@ -1531,12 +1530,6 @@ Array nvim_buf_get_extmarks(Buffer buffer, Integer ns_id, Object start, Object e
/// option is still used for hard tabs. By default lines are /// option is still used for hard tabs. By default lines are
/// placed below the buffer line containing the mark. /// placed below the buffer line containing the mark.
/// ///
/// Note: currently virtual lines are limited to one block
/// per buffer. Thus setting a new mark disables any previous
/// `virt_lines` decoration. However plugins should not rely
/// on this behaviour, as this limitation is planned to be
/// removed.
///
/// - virt_lines_above: place virtual lines above instead. /// - virt_lines_above: place virtual lines above instead.
/// - virt_lines_leftcol: Place extmarks in the leftmost /// - virt_lines_leftcol: Place extmarks in the leftmost
/// column of the window, bypassing /// column of the window, bypassing
@ -1680,9 +1673,8 @@ Integer nvim_buf_set_extmark(Buffer buffer, Integer ns_id, Integer line, Integer
goto error; goto error;
} }
VirtLines virt_lines = KV_INITIAL_VALUE;
bool virt_lines_above = false;
bool virt_lines_leftcol = false; bool virt_lines_leftcol = false;
OPTION_TO_BOOL(virt_lines_leftcol, virt_lines_leftcol, false);
if (opts->virt_lines.type == kObjectTypeArray) { if (opts->virt_lines.type == kObjectTypeArray) {
Array a = opts->virt_lines.data.array; Array a = opts->virt_lines.data.array;
@ -1693,7 +1685,7 @@ Integer nvim_buf_set_extmark(Buffer buffer, Integer ns_id, Integer line, Integer
} }
int dummig; int dummig;
VirtText jtem = parse_virt_text(a.items[j].data.array, err, &dummig); VirtText jtem = parse_virt_text(a.items[j].data.array, err, &dummig);
kv_push(virt_lines, jtem); kv_push(decor.virt_lines, ((struct virt_line){ jtem, virt_lines_leftcol }));
if (ERROR_SET(err)) { if (ERROR_SET(err)) {
goto error; goto error;
} }
@ -1703,8 +1695,8 @@ Integer nvim_buf_set_extmark(Buffer buffer, Integer ns_id, Integer line, Integer
goto error; goto error;
} }
OPTION_TO_BOOL(virt_lines_above, virt_lines_above, false);
OPTION_TO_BOOL(virt_lines_leftcol, virt_lines_leftcol, false); OPTION_TO_BOOL(decor.virt_lines_above, virt_lines_above, false);
if (opts->priority.type == kObjectTypeInteger) { if (opts->priority.type == kObjectTypeInteger) {
Integer val = opts->priority.data.integer; Integer val = opts->priority.data.integer;
@ -1774,7 +1766,7 @@ Integer nvim_buf_set_extmark(Buffer buffer, Integer ns_id, Integer line, Integer
if (ephemeral) { if (ephemeral) {
d = &decor; d = &decor;
} else if (kv_size(decor.virt_text) } else if (kv_size(decor.virt_text) || kv_size(decor.virt_lines)
|| decor.priority != DECOR_PRIORITY_BASE || decor.priority != DECOR_PRIORITY_BASE
|| decor.hl_eol) { || decor.hl_eol) {
// TODO(bfredl): this is a bit sketchy. eventually we should // TODO(bfredl): this is a bit sketchy. eventually we should
@ -1794,22 +1786,11 @@ Integer nvim_buf_set_extmark(Buffer buffer, Integer ns_id, Integer line, Integer
goto error; goto error;
} }
if (kv_size(virt_lines) && buf->b_virt_line_mark) { extmark_set(buf, (uint64_t)ns_id, &id, (int)line, (colnr_T)col, line2, col2,
mtpos_t pos = marktree_lookup(buf->b_marktree, buf->b_virt_line_mark, NULL); d, right_gravity, end_right_gravity, kExtmarkNoUndo);
clear_virt_lines(buf, pos.row); // handles pos.row == -1
}
uint64_t mark = extmark_set(buf, (uint64_t)ns_id, &id, (int)line, (colnr_T)col, if (kv_size(decor.virt_lines)) {
line2, col2, d, right_gravity, redraw_buf_line_later(buf, MIN(buf->b_ml.ml_line_count, line+1+(decor.virt_lines_above?0:1)));
end_right_gravity, kExtmarkNoUndo);
if (kv_size(virt_lines)) {
buf->b_virt_lines = virt_lines;
buf->b_virt_line_mark = mark;
buf->b_virt_line_pos = -1;
buf->b_virt_line_above = virt_lines_above;
buf->b_virt_line_leftcol = virt_lines_leftcol;
redraw_buf_line_later(buf, MIN(buf->b_ml.ml_line_count, line+1+(virt_lines_above?0:1)));
} }
} }
@ -2013,6 +1994,7 @@ Dictionary nvim__buf_stats(Buffer buffer, Error *err)
// this exists to debug issues // this exists to debug issues
PUT(rv, "dirty_bytes", INTEGER_OBJ((Integer)buf->deleted_bytes)); PUT(rv, "dirty_bytes", INTEGER_OBJ((Integer)buf->deleted_bytes));
PUT(rv, "dirty_bytes2", INTEGER_OBJ((Integer)buf->deleted_bytes2)); PUT(rv, "dirty_bytes2", INTEGER_OBJ((Integer)buf->deleted_bytes2));
PUT(rv, "virt_blocks", INTEGER_OBJ((Integer)buf->b_virt_line_blocks));
u_header_T *uhp = NULL; u_header_T *uhp = NULL;
if (buf->b_u_curhead != NULL) { if (buf->b_u_curhead != NULL) {

View File

@ -818,7 +818,6 @@ static void free_buffer_stuff(buf_T *buf, int free_flags)
uc_clear(&buf->b_ucmds); // clear local user commands uc_clear(&buf->b_ucmds); // clear local user commands
buf_delete_signs(buf, (char_u *)"*"); // delete any signs buf_delete_signs(buf, (char_u *)"*"); // delete any signs
extmark_free_all(buf); // delete any extmarks extmark_free_all(buf); // delete any extmarks
clear_virt_lines(buf, -1);
map_clear_int(buf, MAP_ALL_MODES, true, false); // clear local mappings map_clear_int(buf, MAP_ALL_MODES, true, false); // clear local mappings
map_clear_int(buf, MAP_ALL_MODES, true, true); // clear local abbrevs map_clear_int(buf, MAP_ALL_MODES, true, true); // clear local abbrevs
XFREE_CLEAR(buf->b_start_fenc); XFREE_CLEAR(buf->b_start_fenc);

View File

@ -866,12 +866,7 @@ struct file_buffer {
MarkTree b_marktree[1]; MarkTree b_marktree[1];
Map(uint64_t, ExtmarkItem) b_extmark_index[1]; Map(uint64_t, ExtmarkItem) b_extmark_index[1];
Map(uint64_t, ExtmarkNs) b_extmark_ns[1]; // extmark namespaces Map(uint64_t, ExtmarkNs) b_extmark_ns[1]; // extmark namespaces
size_t b_virt_line_blocks; // number of virt_line blocks
VirtLines b_virt_lines;
uint64_t b_virt_line_mark;
int b_virt_line_pos;
bool b_virt_line_above;
bool b_virt_line_leftcol;
// array of channel_id:s which have asked to receive updates for this // array of channel_id:s which have asked to receive updates for this
// buffer. // buffer.

View File

@ -91,12 +91,31 @@ void decor_redraw(buf_T *buf, int row1, int row2, Decoration *decor)
if (kv_size(decor->virt_text)) { if (kv_size(decor->virt_text)) {
redraw_buf_line_later(buf, row1+1); redraw_buf_line_later(buf, row1+1);
} }
if (kv_size(decor->virt_lines)) {
redraw_buf_line_later(buf, MIN(buf->b_ml.ml_line_count,
row1+1+(decor->virt_lines_above?0:1)));
}
}
void decor_remove(buf_T *buf, int row, int row2, Decoration *decor)
{
if (kv_size(decor->virt_lines)) {
assert(buf->b_virt_line_blocks > 0);
buf->b_virt_line_blocks--;
}
decor_redraw(buf, row, row2, decor);
decor_free(decor);
} }
void decor_free(Decoration *decor) void decor_free(Decoration *decor)
{ {
if (decor && !decor->shared) { if (decor && !decor->shared) {
clear_virttext(&decor->virt_text); clear_virttext(&decor->virt_text);
for (size_t i = 0; i < kv_size(decor->virt_lines); i++) {
clear_virttext(&kv_A(decor->virt_lines, i).line);
}
kv_destroy(decor->virt_lines);
xfree(decor); xfree(decor);
} }
} }
@ -118,7 +137,7 @@ Decoration *decor_find_virttext(buf_T *buf, int row, uint64_t ns_id)
mtmark_t mark = marktree_itr_current(itr); mtmark_t mark = marktree_itr_current(itr);
if (mark.row < 0 || mark.row > row) { if (mark.row < 0 || mark.row > row) {
break; break;
} else if (mt_decor_level(mark.id) < 1) { } else if (marktree_decor_level(mark.id) < kDecorLevelVisible) {
goto next_mark; goto next_mark;
} }
ExtmarkItem *item = map_ref(uint64_t, ExtmarkItem)(buf->b_extmark_index, ExtmarkItem *item = map_ref(uint64_t, ExtmarkItem)(buf->b_extmark_index,
@ -162,7 +181,7 @@ bool decor_redraw_start(buf_T *buf, int top_row, DecorState *state)
break; break;
} }
if ((mark.row < top_row && mark.id&MARKTREE_END_FLAG) if ((mark.row < top_row && mark.id&MARKTREE_END_FLAG)
|| mt_decor_level(mark.id) < 1) { || marktree_decor_level(mark.id) < kDecorLevelVisible) {
goto next_mark; goto next_mark;
} }
@ -255,7 +274,8 @@ int decor_redraw_col(buf_T *buf, int col, int win_col, bool hidden, DecorState *
break; break;
} }
if ((mark.id&MARKTREE_END_FLAG) || mt_decor_level(mark.id) < 1) { if ((mark.id&MARKTREE_END_FLAG)
|| marktree_decor_level(mark.id) < kDecorLevelVisible) {
goto next_mark; goto next_mark;
} }
@ -417,33 +437,38 @@ void decor_free_all_mem(void)
} }
int decor_virtual_lines(win_T *wp, linenr_T lnum) int decor_virt_lines(win_T *wp, linenr_T lnum, VirtLines *lines)
{ {
buf_T *buf = wp->w_buffer; buf_T *buf = wp->w_buffer;
if (!buf->b_virt_line_mark) { if (!buf->b_virt_line_blocks) {
// Only pay for what you use: in case virt_lines feature is not active
// in a buffer, plines do not need to access the marktree at all
return 0; return 0;
} }
if (buf->b_virt_line_pos < 0) {
mtpos_t pos = marktree_lookup(buf->b_marktree, buf->b_virt_line_mark, NULL); int virt_lines = 0;
if (pos.row < 0) { int row = (int)MAX(lnum - 2, 0);
buf->b_virt_line_mark = 0; int end_row = (int)lnum;
MarkTreeIter itr[1] = { 0 };
marktree_itr_get(buf->b_marktree, row, 0, itr);
while (true) {
mtmark_t mark = marktree_itr_current(itr);
if (mark.row < 0 || mark.row >= end_row) {
break;
} else if (marktree_decor_level(mark.id) < kDecorLevelVirtLine) {
goto next_mark;
} }
buf->b_virt_line_pos = pos.row + (buf->b_virt_line_above ? 0 : 1); bool above = mark.row > (int)(lnum - 2);
ExtmarkItem *item = map_ref(uint64_t, ExtmarkItem)(buf->b_extmark_index, mark.id, false);
if (item && item->decor && item->decor->virt_lines_above == above) {
virt_lines += (int)kv_size(item->decor->virt_lines);
if (lines) {
kv_splice(*lines, item->decor->virt_lines);
}
}
next_mark:
marktree_itr_next(buf->b_marktree, itr);
} }
return (lnum-1 == buf->b_virt_line_pos) ? (int)kv_size(buf->b_virt_lines) : 0; return virt_lines;
}
void clear_virt_lines(buf_T *buf, int row)
{
if (row > -1) {
redraw_buf_line_later(buf, MIN(buf->b_ml.ml_line_count,
row+1+(buf->b_virt_line_above?0:1)));
}
for (size_t i = 0; i < kv_size(buf->b_virt_lines); i++) {
clear_virttext(&kv_A(buf->b_virt_lines, i));
}
kv_destroy(buf->b_virt_lines); // re-initializes
buf->b_virt_line_pos = -1;
buf->b_virt_line_mark = 0;
} }

View File

@ -24,22 +24,34 @@ typedef enum {
kHlModeBlend, kHlModeBlend,
} HlMode; } HlMode;
typedef kvec_t(VirtTextChunk) VirtText;
#define VIRTTEXT_EMPTY ((VirtText)KV_INITIAL_VALUE)
typedef kvec_t(struct virt_line { VirtText line; bool left_col; }) VirtLines;
struct Decoration struct Decoration
{ {
VirtText virt_text; VirtText virt_text;
VirtLines virt_lines;
int hl_id; // highlight group int hl_id; // highlight group
VirtTextPos virt_text_pos; VirtTextPos virt_text_pos;
HlMode hl_mode; HlMode hl_mode;
// TODO(bfredl): at some point turn this into FLAGS
bool virt_text_hide; bool virt_text_hide;
bool hl_eol; bool hl_eol;
bool shared; // shared decoration, don't free bool shared; // shared decoration, don't free
bool virt_lines_above;
// TODO(bfredl): style, signs, etc // TODO(bfredl): style, signs, etc
DecorPriority priority; DecorPriority priority;
int col; // fixed col value, like win_col int col; // fixed col value, like win_col
int virt_text_width; // width of virt_text int virt_text_width; // width of virt_text
}; };
#define DECORATION_INIT { KV_INITIAL_VALUE, 0, kVTEndOfLine, kHlModeUnknown, \ #define DECORATION_INIT { KV_INITIAL_VALUE, KV_INITIAL_VALUE, 0, kVTEndOfLine, kHlModeUnknown, \
false, false, false, DECOR_PRIORITY_BASE, 0, 0 } false, false, false, false, DECOR_PRIORITY_BASE, 0, 0 }
typedef struct { typedef struct {
int start_row; int start_row;
@ -60,9 +72,7 @@ typedef struct {
int row; int row;
int col_until; int col_until;
int current; int current;
int eol_col; int eol_col;
VirtText *virt_text;
} DecorState; } DecorState;
typedef struct { typedef struct {

View File

@ -83,8 +83,7 @@ uint64_t extmark_set(buf_T *buf, uint64_t ns_id, uint64_t *idp, int row, colnr_T
ExtmarkItem it = map_del(uint64_t, ExtmarkItem)(buf->b_extmark_index, ExtmarkItem it = map_del(uint64_t, ExtmarkItem)(buf->b_extmark_index,
old_mark); old_mark);
if (it.decor) { if (it.decor) {
decor_redraw(buf, row, row, it.decor); decor_remove(buf, row, row, it.decor);
decor_free(it.decor);
} }
mark = marktree_revise(buf->b_marktree, itr); mark = marktree_revise(buf->b_marktree, itr);
goto revised; goto revised;
@ -96,7 +95,13 @@ uint64_t extmark_set(buf_T *buf, uint64_t ns_id, uint64_t *idp, int row, colnr_T
} }
} }
uint8_t decor_level = (decor != NULL) ? 1 : 0; uint8_t decor_level = kDecorLevelNone; // no decor
if (decor) {
decor_level = kDecorLevelVisible; // decor affects redraw
if (kv_size(decor->virt_lines)) {
decor_level = kDecorLevelVirtLine; // decor affects horizontal size
}
}
if (end_row > -1) { if (end_row > -1) {
mark = marktree_put_pair(buf->b_marktree, mark = marktree_put_pair(buf->b_marktree,
@ -119,6 +124,9 @@ revised:
} }
if (decor) { if (decor) {
if (kv_size(decor->virt_lines)) {
buf->b_virt_line_blocks++;
}
decor_redraw(buf, row, end_row > -1 ? end_row : row, decor); decor_redraw(buf, row, end_row > -1 ? end_row : row, decor);
} }
@ -172,12 +180,7 @@ bool extmark_del(buf_T *buf, uint64_t ns_id, uint64_t id)
} }
if (item.decor) { if (item.decor) {
decor_redraw(buf, pos.row, pos2.row, item.decor); decor_remove(buf, pos.row, pos2.row, item.decor);
decor_free(item.decor);
}
if (mark == buf->b_virt_line_mark) {
clear_virt_lines(buf, pos.row);
} }
map_del(uint64_t, uint64_t)(ns->map, id); map_del(uint64_t, uint64_t)(ns->map, id);
@ -230,17 +233,13 @@ bool extmark_clear(buf_T *buf, uint64_t ns_id, int l_row, colnr_T l_col, int u_r
marktree_del_itr(buf->b_marktree, itr, false); marktree_del_itr(buf->b_marktree, itr, false);
if (*del_status >= 0) { // we had a decor_id if (*del_status >= 0) { // we had a decor_id
DecorItem it = kv_A(decors, *del_status); DecorItem it = kv_A(decors, *del_status);
decor_redraw(buf, it.row1, mark.row, it.decor); decor_remove(buf, it.row1, mark.row, it.decor);
decor_free(it.decor);
} }
map_del(uint64_t, ssize_t)(&delete_set, mark.id); map_del(uint64_t, ssize_t)(&delete_set, mark.id);
continue; continue;
} }
uint64_t start_id = mark.id & ~MARKTREE_END_FLAG; uint64_t start_id = mark.id & ~MARKTREE_END_FLAG;
if (start_id == buf->b_virt_line_mark) {
clear_virt_lines(buf, mark.row);
}
ExtmarkItem item = map_get(uint64_t, ExtmarkItem)(buf->b_extmark_index, ExtmarkItem item = map_get(uint64_t, ExtmarkItem)(buf->b_extmark_index,
start_id); start_id);
@ -259,8 +258,7 @@ bool extmark_clear(buf_T *buf, uint64_t ns_id, int l_row, colnr_T l_col, int u_r
} }
map_put(uint64_t, ssize_t)(&delete_set, other, decor_id); map_put(uint64_t, ssize_t)(&delete_set, other, decor_id);
} else if (item.decor) { } else if (item.decor) {
decor_redraw(buf, mark.row, mark.row, item.decor); decor_remove(buf, mark.row, mark.row, item.decor);
decor_free(item.decor);
} }
ExtmarkNs *my_ns = all_ns ? buf_ns_ref(buf, item.ns_id, false) : ns; ExtmarkNs *my_ns = all_ns ? buf_ns_ref(buf, item.ns_id, false) : ns;
map_del(uint64_t, uint64_t)(my_ns->map, item.mark_id); map_del(uint64_t, uint64_t)(my_ns->map, item.mark_id);
@ -278,8 +276,7 @@ bool extmark_clear(buf_T *buf, uint64_t ns_id, int l_row, colnr_T l_col, int u_r
marktree_del_itr(buf->b_marktree, itr, false); marktree_del_itr(buf->b_marktree, itr, false);
if (decor_id >= 0) { if (decor_id >= 0) {
DecorItem it = kv_A(decors, decor_id); DecorItem it = kv_A(decors, decor_id);
decor_redraw(buf, it.row1, pos.row, it.decor); decor_remove(buf, it.row1, pos.row, it.decor);
decor_free(it.decor);
} }
}); });
map_clear(uint64_t, ssize_t)(&delete_set); map_clear(uint64_t, ssize_t)(&delete_set);
@ -510,7 +507,6 @@ void extmark_apply_undo(ExtmarkUndoObject undo_info, bool undo)
kExtmarkNoUndo); kExtmarkNoUndo);
} }
} }
curbuf->b_virt_line_pos = -1;
} }
@ -590,7 +586,6 @@ void extmark_splice_impl(buf_T *buf, int start_row, colnr_T start_col, bcount_t
colnr_T new_col, bcount_t new_byte, ExtmarkOp undo) colnr_T new_col, bcount_t new_byte, ExtmarkOp undo)
{ {
buf->deleted_bytes2 = 0; buf->deleted_bytes2 = 0;
buf->b_virt_line_pos = -1;
buf_updates_send_splice(buf, start_row, start_col, start_byte, buf_updates_send_splice(buf, start_row, start_col, start_byte,
old_row, old_col, old_byte, old_row, old_col, old_byte,
new_row, new_col, new_byte); new_row, new_col, new_byte);
@ -682,7 +677,6 @@ void extmark_move_region(buf_T *buf, int start_row, colnr_T start_col, bcount_t
colnr_T new_col, bcount_t new_byte, ExtmarkOp undo) colnr_T new_col, bcount_t new_byte, ExtmarkOp undo)
{ {
buf->deleted_bytes2 = 0; buf->deleted_bytes2 = 0;
buf->b_virt_line_pos = -1;
// TODO(bfredl): this is not synced to the buffer state inside the callback. // TODO(bfredl): this is not synced to the buffer state inside the callback.
// But unless we make the undo implementation smarter, this is not ensured // But unless we make the undo implementation smarter, this is not ensured
// anyway. // anyway.

View File

@ -11,10 +11,6 @@ typedef struct {
int hl_id; int hl_id;
} VirtTextChunk; } VirtTextChunk;
typedef kvec_t(VirtTextChunk) VirtText;
#define VIRTTEXT_EMPTY ((VirtText)KV_INITIAL_VALUE)
typedef kvec_t(VirtText) VirtLines;
typedef struct typedef struct
{ {
@ -38,4 +34,10 @@ typedef enum {
kExtmarkUndoNoRedo, // Operation should be undoable, but not redoable kExtmarkUndoNoRedo, // Operation should be undoable, but not redoable
} ExtmarkOp; } ExtmarkOp;
typedef enum {
kDecorLevelNone = 0,
kDecorLevelVisible = 1,
kDecorLevelVirtLine = 2,
} DecorLevel;
#endif // NVIM_EXTMARK_DEFS_H #endif // NVIM_EXTMARK_DEFS_H

View File

@ -94,6 +94,17 @@
memcpy((v1).items, (v0).items, sizeof((v1).items[0]) * (v0).size); \ memcpy((v1).items, (v0).items, sizeof((v1).items[0]) * (v0).size); \
} while (0) } while (0)
#define kv_splice(v1, v0) \
do { \
if ((v1).capacity < (v1).size + (v0).size) { \
(v1).capacity = (v1).size + (v0).size; \
kv_roundup32((v1).capacity); \
kv_resize((v1), (v1).capacity); \
} \
memcpy((v1).items + (v1).size, (v0).items, sizeof((v1).items[0]) * (v0).size); \
(v1).size = (v1).size + (v0).size; \
} while (0)
#define kv_pushp(v) \ #define kv_pushp(v) \
((((v).size == (v).capacity) ? (kv_resize_full(v), 0) : 0), \ ((((v).size == (v).capacity) ? (kv_resize_full(v), 0) : 0), \
((v).items + ((v).size++))) ((v).items + ((v).size++)))
@ -101,6 +112,7 @@
#define kv_push(v, x) \ #define kv_push(v, x) \
(*kv_pushp(v) = (x)) (*kv_pushp(v) = (x))
#define kv_a(v, i) \ #define kv_a(v, i) \
(*(((v).capacity <= (size_t)(i) \ (*(((v).capacity <= (size_t)(i) \
? ((v).capacity = (v).size = (i) + 1, \ ? ((v).capacity = (v).size = (i) + 1, \

View File

@ -78,7 +78,9 @@ typedef struct {
#define DECOR_LEVELS 4 #define DECOR_LEVELS 4
#define DECOR_OFFSET 61 #define DECOR_OFFSET 61
#define DECOR_MASK (((uint64_t)(DECOR_LEVELS-1)) << DECOR_OFFSET) #define DECOR_MASK (((uint64_t)(DECOR_LEVELS-1)) << DECOR_OFFSET)
static inline uint8_t mt_decor_level(uint64_t id) {
static inline uint8_t marktree_decor_level(uint64_t id)
{
return (uint8_t)((id&DECOR_MASK) >> DECOR_OFFSET); return (uint8_t)((id&DECOR_MASK) >> DECOR_OFFSET);
} }

View File

@ -54,7 +54,7 @@ int plines_win(win_T *wp, linenr_T lnum, bool winheight)
/// @return Number of filler lines above lnum /// @return Number of filler lines above lnum
int win_get_fill(win_T *wp, linenr_T lnum) int win_get_fill(win_T *wp, linenr_T lnum)
{ {
int virt_lines = decor_virtual_lines(wp, lnum); int virt_lines = decor_virt_lines(wp, lnum, NULL);
// be quick when there are no filler lines // be quick when there are no filler lines
if (diffopt_filler()) { if (diffopt_filler()) {
@ -69,7 +69,7 @@ int win_get_fill(win_T *wp, linenr_T lnum)
bool win_may_fill(win_T *wp) bool win_may_fill(win_T *wp)
{ {
return (wp->w_p_diff && diffopt_filler()) || wp->w_buffer->b_virt_line_mark; return (wp->w_p_diff && diffopt_filler()) || wp->w_buffer->b_virt_line_blocks;
} }
/// @param winheight when true limit to window height /// @param winheight when true limit to window height

View File

@ -2372,11 +2372,12 @@ static int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool noc
filler_lines = 0; filler_lines = 0;
area_highlighting = true; area_highlighting = true;
} }
int virtual_lines = decor_virtual_lines(wp, lnum); VirtLines virt_lines = KV_INITIAL_VALUE;
filler_lines += virtual_lines; int n_virt_lines = decor_virt_lines(wp, lnum, &virt_lines);
filler_lines += n_virt_lines;
if (lnum == wp->w_topline) { if (lnum == wp->w_topline) {
filler_lines = wp->w_topfill; filler_lines = wp->w_topfill;
virtual_lines = MIN(virtual_lines, filler_lines); n_virt_lines = MIN(n_virt_lines, filler_lines);
} }
filler_todo = filler_lines; filler_todo = filler_lines;
@ -2904,7 +2905,7 @@ static int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool noc
if (draw_state == WL_SBR - 1 && n_extra == 0) { if (draw_state == WL_SBR - 1 && n_extra == 0) {
draw_state = WL_SBR; draw_state = WL_SBR;
if (filler_todo > filler_lines - virtual_lines) { if (filler_todo > filler_lines - n_virt_lines) {
// TODO(bfredl): check this doesn't inhibit TUI-style // TODO(bfredl): check this doesn't inhibit TUI-style
// clear-to-end-of-line. // clear-to-end-of-line.
c_extra = ' '; c_extra = ' ';
@ -4423,12 +4424,12 @@ static int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool noc
int draw_col = col - boguscols; int draw_col = col - boguscols;
if (filler_todo > 0) { if (filler_todo > 0) {
int index = filler_todo - (filler_lines - virtual_lines); int index = filler_todo - (filler_lines - n_virt_lines);
if (index > 0) { if (index > 0) {
int fpos = kv_size(buf->b_virt_lines) - index; int i = kv_size(virt_lines) - index;
assert(fpos >= 0); assert(i >= 0);
int offset = buf->b_virt_line_leftcol ? 0 : win_col_offset; int offset = kv_A(virt_lines, i).left_col ? 0 : win_col_offset;
draw_virt_text_item(buf, offset, kv_A(buf->b_virt_lines, fpos), draw_virt_text_item(buf, offset, kv_A(virt_lines, i).line,
kHlModeReplace, grid->Columns, offset); kHlModeReplace, grid->Columns, offset);
} }
} else { } else {
@ -4506,6 +4507,7 @@ static int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool noc
cap_col = 0; cap_col = 0;
} }
kv_destroy(virt_lines);
xfree(p_extra_free); xfree(p_extra_free);
return row; return row;
} }

View File

@ -901,15 +901,15 @@ if (h->n_buckets < new_n_buckets) { // expand
screen:expect{grid=[[ screen:expect{grid=[[
if (h->n_buckets < new_n_buckets) { // expand | if (h->n_buckets < new_n_buckets) { // expand |
khkey_t *new_keys = (khkey_t *) | khkey_t *new_keys = (khkey_t *) |
{1:>> }{2:krealloc}: change the size of an allocation |
{3:krealloc}((void *)h->keys, new_n_buckets * sizeof(k| {3:krealloc}((void *)h->keys, new_n_buckets * sizeof(k|
hkey_t)); | hkey_t)); |
h->keys = new_keys; | h->keys = new_keys; |
if (kh_is_map && val_size) { | if (kh_is_map && val_size) { |
char *new_vals = {3:krealloc}( h->vals_buf, new_n_| ^char *new_vals = {3:krealloc}( h->vals_buf, new_n_|
buck^ets * val_size); | buckets * val_size); |
{5:^^ REVIEW:}{6: new_vals variable seems unneccesary?} | {5:^^ REVIEW:}{6: new_vals variable seems unneccesary?} |
h->vals_buf = new_vals; | h->vals_buf = new_vals; |
} |
| |
]]} ]]}
@ -1235,6 +1235,7 @@ if (h->n_buckets < new_n_buckets) { // expand
| |
]]} ]]}
meths.buf_clear_namespace(0, ns, 0, -1)
meths.buf_set_extmark(0, ns, 2, 0, { meths.buf_set_extmark(0, ns, 2, 0, {
virt_lines={ virt_lines={
{{"Some special", "Special"}}; {{"Some special", "Special"}};

View File

@ -97,7 +97,7 @@ describe('marktree', function()
for i = 1,100 do for i = 1,100 do
for j = 1,100 do for j = 1,100 do
local gravitate = (i%2) > 0 local gravitate = (i%2) > 0
local id = tonumber(lib.marktree_put(tree, j, i, gravitate)) local id = tonumber(lib.marktree_put(tree, j, i, gravitate, 0))
ok(id > 0) ok(id > 0)
eq(nil, shadow[id]) eq(nil, shadow[id])
shadow[id] = {j,i,gravitate} shadow[id] = {j,i,gravitate}
@ -191,7 +191,7 @@ describe('marktree', function()
-- https://github.com/neovim/neovim/pull/14719 -- https://github.com/neovim/neovim/pull/14719
lib.marktree_clear(tree) lib.marktree_clear(tree)
for i = 1,20 do for i = 1,20 do
lib.marktree_put(tree, i, i, false) lib.marktree_put(tree, i, i, false, 0)
end end
lib.marktree_itr_get(tree, 10, 10, iter) lib.marktree_itr_get(tree, 10, 10, iter)