mirror of
https://github.com/neovim/neovim.git
synced 2025-09-17 00:38:17 +00:00
refactor(extmarks): use a more efficient representation
marktree.c was originally constructed as a "generic" datatype, to make the prototyping of its internal logic as simple as possible and also as the usecases for various kinds of extmarks/decorations was not yet decided. As a consequence of this, various extra indirections and allocations was needed to use marktree to implement extmarks (ns/id pairs) and decorations of different kinds (some which is just a single highlight id, other an allocated list of virtual text/lines) This change removes a lot of indirection, by making Marktree specialized for the usecase. In particular, the namespace id and mark id is stored directly, instead of the 64-bit global id particular to the Marktree struct. This removes the two maps needed to convert between global and per-ns ids. Also, "small" decorations are stored inline, i.e. those who doesn't refer to external heap memory anyway. That is highlights (with priority+flags) are stored inline, while virtual text, which anyway occurs a lot of heap allocations, do not. (previously a hack was used to elide heap allocations for highlights with standard prio+flags) TODO(bfredl): the functionaltest-lua CI version of gcc is having severe issues with uint16_t bitfields, so splitting up compound assignments and redundant casts are needed. Clean this up once we switch to a working compiler version.
This commit is contained in:
@@ -48,28 +48,29 @@
|
||||
# include "extmark.c.generated.h"
|
||||
#endif
|
||||
|
||||
static ExtmarkNs *buf_ns_ref(buf_T *buf, uint64_t ns_id, bool put)
|
||||
static uint32_t *buf_ns_ref(buf_T *buf, uint32_t ns_id, bool put)
|
||||
{
|
||||
return map_ref(uint64_t, ExtmarkNs)(buf->b_extmark_ns, ns_id, put);
|
||||
return map_ref(uint32_t, uint32_t)(buf->b_extmark_ns, ns_id, put);
|
||||
}
|
||||
|
||||
|
||||
/// Create or update an extmark
|
||||
///
|
||||
/// must not be used during iteration!
|
||||
/// @returns the internal mark id
|
||||
uint64_t extmark_set(buf_T *buf, uint64_t ns_id, uint64_t *idp, int row, colnr_T col, int end_row,
|
||||
colnr_T end_col, Decoration *decor, bool right_gravity, bool end_right_gravity,
|
||||
ExtmarkOp op)
|
||||
void extmark_set(buf_T *buf, uint32_t ns_id, uint32_t *idp, int row, colnr_T col, int end_row,
|
||||
colnr_T end_col, Decoration *decor, bool right_gravity, bool end_right_gravity,
|
||||
ExtmarkOp op)
|
||||
{
|
||||
ExtmarkNs *ns = buf_ns_ref(buf, ns_id, true);
|
||||
assert(ns != NULL);
|
||||
mtpos_t old_pos;
|
||||
uint64_t mark = 0;
|
||||
uint64_t id = idp ? *idp : 0;
|
||||
uint32_t *ns = buf_ns_ref(buf, ns_id, true);
|
||||
uint32_t id = idp ? *idp : 0;
|
||||
bool decor_full = false;
|
||||
|
||||
uint8_t decor_level = kDecorLevelNone; // no decor
|
||||
if (decor) {
|
||||
if (kv_size(decor->virt_text) || kv_size(decor->virt_lines)) {
|
||||
decor_full = true;
|
||||
decor = xmemdup(decor, sizeof *decor);
|
||||
}
|
||||
decor_level = kDecorLevelVisible; // decor affects redraw
|
||||
if (kv_size(decor->virt_lines)) {
|
||||
decor_level = kDecorLevelVirtLine; // decor affects horizontal size
|
||||
@@ -77,50 +78,64 @@ uint64_t extmark_set(buf_T *buf, uint64_t ns_id, uint64_t *idp, int row, colnr_T
|
||||
}
|
||||
|
||||
if (id == 0) {
|
||||
id = ns->free_id++;
|
||||
id = ++*ns;
|
||||
} else {
|
||||
uint64_t old_mark = map_get(uint64_t, uint64_t)(ns->map, id);
|
||||
if (old_mark) {
|
||||
if (old_mark & MARKTREE_PAIRED_FLAG || end_row > -1) {
|
||||
MarkTreeIter itr[1] = { 0 };
|
||||
mtkey_t old_mark = marktree_lookup_ns(buf->b_marktree, ns_id, id, false, itr);
|
||||
if (old_mark.id) {
|
||||
if (mt_paired(old_mark) || end_row > -1) {
|
||||
extmark_del(buf, ns_id, id);
|
||||
} else {
|
||||
MarkTreeIter itr[1] = { 0 };
|
||||
old_pos = marktree_lookup(buf->b_marktree, old_mark, itr);
|
||||
// TODO(bfredl): we need to do more if "revising" a decoration mark.
|
||||
assert(itr->node);
|
||||
if (old_pos.row == row && old_pos.col == col) {
|
||||
ExtmarkItem it = map_del(uint64_t, ExtmarkItem)(buf->b_extmark_index,
|
||||
old_mark);
|
||||
if (it.decor) {
|
||||
decor_remove(buf, row, row, it.decor);
|
||||
if (old_mark.pos.row == row && old_mark.pos.col == col) {
|
||||
if (marktree_decor_level(old_mark) > kDecorLevelNone) {
|
||||
decor_remove(buf, row, row, old_mark.decor_full);
|
||||
old_mark.decor_full = NULL;
|
||||
}
|
||||
mark = marktree_revise(buf->b_marktree, itr, decor_level);
|
||||
old_mark.flags = 0;
|
||||
if (decor_full) {
|
||||
old_mark.decor_full = decor;
|
||||
} else if (decor) {
|
||||
old_mark.hl_id = decor->hl_id;
|
||||
// Workaround: the gcc compiler of functionaltest-lua build
|
||||
// apparently incapable of handling basic integer constants.
|
||||
// This can be underanged as soon as we bump minimal gcc version.
|
||||
old_mark.flags = (uint16_t)(old_mark.flags
|
||||
| (decor->hl_eol ? (uint16_t)MT_FLAG_HL_EOL : (uint16_t)0));
|
||||
old_mark.priority = decor->priority;
|
||||
}
|
||||
marktree_revise(buf->b_marktree, itr, decor_level, old_mark);
|
||||
goto revised;
|
||||
}
|
||||
marktree_del_itr(buf->b_marktree, itr, false);
|
||||
}
|
||||
} else {
|
||||
ns->free_id = MAX(ns->free_id, id+1);
|
||||
*ns = MAX(*ns, id);
|
||||
}
|
||||
}
|
||||
|
||||
if (end_row > -1) {
|
||||
mark = marktree_put_pair(buf->b_marktree,
|
||||
row, col, right_gravity,
|
||||
end_row, end_col, end_right_gravity, decor_level);
|
||||
} else {
|
||||
mark = marktree_put(buf->b_marktree, row, col, right_gravity, decor_level);
|
||||
mtkey_t mark = { { row, col }, ns_id, id, 0,
|
||||
mt_flags(right_gravity, decor_level), 0, NULL };
|
||||
if (decor_full) {
|
||||
mark.decor_full = decor;
|
||||
} else if (decor) {
|
||||
mark.hl_id = decor->hl_id;
|
||||
// workaround: see above
|
||||
mark.flags = (uint16_t)(mark.flags | (decor->hl_eol ? (uint16_t)MT_FLAG_HL_EOL : (uint16_t)0));
|
||||
mark.priority = decor->priority;
|
||||
}
|
||||
|
||||
revised:
|
||||
map_put(uint64_t, ExtmarkItem)(buf->b_extmark_index, mark,
|
||||
(ExtmarkItem){ ns_id, id, decor });
|
||||
map_put(uint64_t, uint64_t)(ns->map, id, mark);
|
||||
marktree_put(buf->b_marktree, mark, end_row, end_col, end_right_gravity);
|
||||
|
||||
revised:
|
||||
if (op != kExtmarkNoUndo) {
|
||||
// TODO(bfredl): this doesn't cover all the cases and probably shouldn't
|
||||
// be done "prematurely". Any movement in undo history might necessitate
|
||||
// adding new marks to old undo headers.
|
||||
u_extmark_set(buf, mark, row, col);
|
||||
// adding new marks to old undo headers. add a test case for this (doesn't
|
||||
// fail extmark_spec.lua, and it should)
|
||||
uint64_t mark_id = mt_lookup_id(ns_id, id, false);
|
||||
u_extmark_set(buf, mark_id, row, col);
|
||||
}
|
||||
|
||||
if (decor) {
|
||||
@@ -133,18 +148,17 @@ revised:
|
||||
if (idp) {
|
||||
*idp = id;
|
||||
}
|
||||
return mark;
|
||||
}
|
||||
|
||||
static bool extmark_setraw(buf_T *buf, uint64_t mark, int row, colnr_T col)
|
||||
{
|
||||
MarkTreeIter itr[1] = { 0 };
|
||||
mtpos_t pos = marktree_lookup(buf->b_marktree, mark, itr);
|
||||
if (pos.row == -1) {
|
||||
mtkey_t key = marktree_lookup(buf->b_marktree, mark, itr);
|
||||
if (key.pos.row == -1) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (pos.row == row && pos.col == col) {
|
||||
if (key.pos.row == row && key.pos.col == col) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -154,45 +168,35 @@ static bool extmark_setraw(buf_T *buf, uint64_t mark, int row, colnr_T col)
|
||||
|
||||
// Remove an extmark
|
||||
// Returns 0 on missing id
|
||||
bool extmark_del(buf_T *buf, uint64_t ns_id, uint64_t id)
|
||||
bool extmark_del(buf_T *buf, uint32_t ns_id, uint32_t id)
|
||||
{
|
||||
ExtmarkNs *ns = buf_ns_ref(buf, ns_id, false);
|
||||
if (!ns) {
|
||||
return false;
|
||||
}
|
||||
|
||||
uint64_t mark = map_get(uint64_t, uint64_t)(ns->map, id);
|
||||
if (!mark) {
|
||||
return false;
|
||||
}
|
||||
|
||||
MarkTreeIter itr[1] = { 0 };
|
||||
mtpos_t pos = marktree_lookup(buf->b_marktree, mark, itr);
|
||||
assert(pos.row >= 0);
|
||||
mtkey_t key = marktree_lookup_ns(buf->b_marktree, ns_id, id, false, itr);
|
||||
if (!key.id) {
|
||||
return false;
|
||||
}
|
||||
assert(key.pos.row >= 0);
|
||||
marktree_del_itr(buf->b_marktree, itr, false);
|
||||
ExtmarkItem item = map_get(uint64_t, ExtmarkItem)(buf->b_extmark_index, mark);
|
||||
mtpos_t pos2 = pos;
|
||||
|
||||
if (mark & MARKTREE_PAIRED_FLAG) {
|
||||
pos2 = marktree_lookup(buf->b_marktree, mark|MARKTREE_END_FLAG, itr);
|
||||
assert(pos2.row >= 0);
|
||||
mtkey_t key2 = key;
|
||||
|
||||
if (mt_paired(key)) {
|
||||
key2 = marktree_lookup_ns(buf->b_marktree, ns_id, id, true, itr);
|
||||
assert(key2.pos.row >= 0);
|
||||
marktree_del_itr(buf->b_marktree, itr, false);
|
||||
}
|
||||
|
||||
if (item.decor) {
|
||||
decor_remove(buf, pos.row, pos2.row, item.decor);
|
||||
if (marktree_decor_level(key) > kDecorLevelNone) {
|
||||
decor_remove(buf, key.pos.row, key2.pos.row, key.decor_full);
|
||||
}
|
||||
|
||||
map_del(uint64_t, uint64_t)(ns->map, id);
|
||||
map_del(uint64_t, ExtmarkItem)(buf->b_extmark_index, mark);
|
||||
|
||||
// TODO(bfredl): delete it from current undo header, opportunistically?
|
||||
return true;
|
||||
}
|
||||
|
||||
// Free extmarks in a ns between lines
|
||||
// if ns = 0, it means clear all namespaces
|
||||
bool extmark_clear(buf_T *buf, uint64_t ns_id, int l_row, colnr_T l_col, int u_row, colnr_T u_col)
|
||||
bool extmark_clear(buf_T *buf, uint32_t ns_id, int l_row, colnr_T l_col, int u_row, colnr_T u_col)
|
||||
{
|
||||
if (!map_size(buf->b_extmark_ns)) {
|
||||
return false;
|
||||
@@ -201,68 +205,58 @@ bool extmark_clear(buf_T *buf, uint64_t ns_id, int l_row, colnr_T l_col, int u_r
|
||||
bool marks_cleared = false;
|
||||
|
||||
bool all_ns = (ns_id == 0);
|
||||
ExtmarkNs *ns = NULL;
|
||||
uint32_t *ns = NULL;
|
||||
if (!all_ns) {
|
||||
ns = buf_ns_ref(buf, ns_id, false);
|
||||
if (!ns) {
|
||||
// nothing to do
|
||||
return false;
|
||||
}
|
||||
|
||||
// TODO(bfredl): if map_size(ns->map) << buf->b_marktree.n_nodes
|
||||
// it could be faster to iterate over the map instead
|
||||
}
|
||||
|
||||
// the value is either zero or the lnum (row+1) if highlight was present.
|
||||
static Map(uint64_t, ssize_t) delete_set = MAP_INIT;
|
||||
typedef struct { Decoration *decor; int row1; } DecorItem;
|
||||
typedef struct { int row1; } DecorItem;
|
||||
static kvec_t(DecorItem) decors;
|
||||
|
||||
MarkTreeIter itr[1] = { 0 };
|
||||
marktree_itr_get(buf->b_marktree, l_row, l_col, itr);
|
||||
while (true) {
|
||||
mtmark_t mark = marktree_itr_current(itr);
|
||||
if (mark.row < 0
|
||||
|| mark.row > u_row
|
||||
|| (mark.row == u_row && mark.col > u_col)) {
|
||||
mtkey_t mark = marktree_itr_current(itr);
|
||||
if (mark.pos.row < 0
|
||||
|| mark.pos.row > u_row
|
||||
|| (mark.pos.row == u_row && mark.pos.col > u_col)) {
|
||||
break;
|
||||
}
|
||||
ssize_t *del_status = map_ref(uint64_t, ssize_t)(&delete_set, mark.id,
|
||||
ssize_t *del_status = map_ref(uint64_t, ssize_t)(&delete_set, mt_lookup_key(mark),
|
||||
false);
|
||||
if (del_status) {
|
||||
marktree_del_itr(buf->b_marktree, itr, false);
|
||||
if (*del_status >= 0) { // we had a decor_id
|
||||
DecorItem it = kv_A(decors, *del_status);
|
||||
decor_remove(buf, it.row1, mark.row, it.decor);
|
||||
decor_remove(buf, it.row1, mark.pos.row, mark.decor_full);
|
||||
}
|
||||
map_del(uint64_t, ssize_t)(&delete_set, mark.id);
|
||||
map_del(uint64_t, ssize_t)(&delete_set, mt_lookup_key(mark));
|
||||
continue;
|
||||
}
|
||||
|
||||
uint64_t start_id = mark.id & ~MARKTREE_END_FLAG;
|
||||
ExtmarkItem item = map_get(uint64_t, ExtmarkItem)(buf->b_extmark_index,
|
||||
start_id);
|
||||
|
||||
assert(item.ns_id > 0 && item.mark_id > 0);
|
||||
if (item.mark_id > 0 && (item.ns_id == ns_id || all_ns)) {
|
||||
assert(mark.ns > 0 && mark.id > 0);
|
||||
if (mark.ns == ns_id || all_ns) {
|
||||
marks_cleared = true;
|
||||
if (mark.id & MARKTREE_PAIRED_FLAG) {
|
||||
uint64_t other = mark.id ^ MARKTREE_END_FLAG;
|
||||
if (mt_paired(mark)) {
|
||||
uint64_t other = mt_lookup_id(mark.ns, mark.id, !mt_end(mark));
|
||||
ssize_t decor_id = -1;
|
||||
if (item.decor) {
|
||||
if (marktree_decor_level(mark) > kDecorLevelNone) {
|
||||
// Save the decoration and the first pos. Clear the decoration
|
||||
// later when we know the full range.
|
||||
decor_id = (ssize_t)kv_size(decors);
|
||||
kv_push(decors,
|
||||
((DecorItem) { .decor = item.decor, .row1 = mark.row }));
|
||||
((DecorItem) { .row1 = mark.pos.row }));
|
||||
}
|
||||
map_put(uint64_t, ssize_t)(&delete_set, other, decor_id);
|
||||
} else if (item.decor) {
|
||||
decor_remove(buf, mark.row, mark.row, item.decor);
|
||||
} else if (mark.decor_full) {
|
||||
decor_remove(buf, mark.pos.row, mark.pos.row, mark.decor_full);
|
||||
}
|
||||
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, ExtmarkItem)(buf->b_extmark_index, start_id);
|
||||
marktree_del_itr(buf->b_marktree, itr, false);
|
||||
} else {
|
||||
marktree_itr_next(buf->b_marktree, itr);
|
||||
@@ -271,12 +265,12 @@ bool extmark_clear(buf_T *buf, uint64_t ns_id, int l_row, colnr_T l_col, int u_r
|
||||
uint64_t id;
|
||||
ssize_t decor_id;
|
||||
map_foreach(&delete_set, id, decor_id, {
|
||||
mtpos_t pos = marktree_lookup(buf->b_marktree, id, itr);
|
||||
mtkey_t mark = marktree_lookup(buf->b_marktree, id, itr);
|
||||
assert(itr->node);
|
||||
marktree_del_itr(buf->b_marktree, itr, false);
|
||||
if (decor_id >= 0) {
|
||||
DecorItem it = kv_A(decors, decor_id);
|
||||
decor_remove(buf, it.row1, pos.row, it.decor);
|
||||
decor_remove(buf, it.row1, mark.pos.row, mark.decor_full);
|
||||
}
|
||||
});
|
||||
map_clear(uint64_t, ssize_t)(&delete_set);
|
||||
@@ -290,7 +284,7 @@ bool extmark_clear(buf_T *buf, uint64_t ns_id, int l_row, colnr_T l_col, int u_r
|
||||
// will be searched to the start, or end
|
||||
// dir can be set to control the order of the array
|
||||
// amount = amount of marks to find or -1 for all
|
||||
ExtmarkInfoArray extmark_get(buf_T *buf, uint64_t ns_id, int l_row, colnr_T l_col, int u_row,
|
||||
ExtmarkInfoArray extmark_get(buf_T *buf, uint32_t ns_id, int l_row, colnr_T l_col, int u_row,
|
||||
colnr_T u_col, int64_t amount, bool reverse)
|
||||
{
|
||||
ExtmarkInfoArray array = KV_INITIAL_VALUE;
|
||||
@@ -300,30 +294,24 @@ ExtmarkInfoArray extmark_get(buf_T *buf, uint64_t ns_id, int l_row, colnr_T l_co
|
||||
itr, reverse, false, NULL);
|
||||
int order = reverse ? -1 : 1;
|
||||
while ((int64_t)kv_size(array) < amount) {
|
||||
mtmark_t mark = marktree_itr_current(itr);
|
||||
mtpos_t endpos = { -1, -1 };
|
||||
if (mark.row < 0
|
||||
|| (mark.row - u_row) * order > 0
|
||||
|| (mark.row == u_row && (mark.col - u_col) * order > 0)) {
|
||||
mtkey_t mark = marktree_itr_current(itr);
|
||||
if (mark.pos.row < 0
|
||||
|| (mark.pos.row - u_row) * order > 0
|
||||
|| (mark.pos.row == u_row && (mark.pos.col - u_col) * order > 0)) {
|
||||
break;
|
||||
}
|
||||
if (mark.id & MARKTREE_END_FLAG) {
|
||||
if (mt_end(mark)) {
|
||||
goto next_mark;
|
||||
} else if (mark.id & MARKTREE_PAIRED_FLAG) {
|
||||
endpos = marktree_lookup(buf->b_marktree, mark.id | MARKTREE_END_FLAG,
|
||||
NULL);
|
||||
}
|
||||
|
||||
|
||||
ExtmarkItem item = map_get(uint64_t, ExtmarkItem)(buf->b_extmark_index,
|
||||
mark.id);
|
||||
if (item.ns_id == ns_id) {
|
||||
kv_push(array, ((ExtmarkInfo) { .ns_id = item.ns_id,
|
||||
.mark_id = item.mark_id,
|
||||
.row = mark.row, .col = mark.col,
|
||||
if (mark.ns == ns_id) {
|
||||
mtpos_t endpos = marktree_get_altpos(buf->b_marktree, mark, NULL);
|
||||
kv_push(array, ((ExtmarkInfo) { .ns_id = mark.ns,
|
||||
.mark_id = mark.id,
|
||||
.row = mark.pos.row, .col = mark.pos.col,
|
||||
.end_row = endpos.row,
|
||||
.end_col = endpos.col,
|
||||
.decor = item.decor }));
|
||||
.decor = get_decor(mark) }));
|
||||
}
|
||||
next_mark:
|
||||
if (reverse) {
|
||||
@@ -336,36 +324,23 @@ next_mark:
|
||||
}
|
||||
|
||||
// Lookup an extmark by id
|
||||
ExtmarkInfo extmark_from_id(buf_T *buf, uint64_t ns_id, uint64_t id)
|
||||
ExtmarkInfo extmark_from_id(buf_T *buf, uint32_t ns_id, uint32_t id)
|
||||
{
|
||||
ExtmarkNs *ns = buf_ns_ref(buf, ns_id, false);
|
||||
ExtmarkInfo ret = { 0, 0, -1, -1, -1, -1, NULL };
|
||||
if (!ns) {
|
||||
ExtmarkInfo ret = { 0, 0, -1, -1, -1, -1, DECORATION_INIT };
|
||||
mtkey_t mark = marktree_lookup_ns(buf->b_marktree, ns_id, id, false, NULL);
|
||||
if (!mark.id) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
uint64_t mark = map_get(uint64_t, uint64_t)(ns->map, id);
|
||||
if (!mark) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
mtpos_t pos = marktree_lookup(buf->b_marktree, mark, NULL);
|
||||
mtpos_t endpos = { -1, -1 };
|
||||
if (mark & MARKTREE_PAIRED_FLAG) {
|
||||
endpos = marktree_lookup(buf->b_marktree, mark | MARKTREE_END_FLAG, NULL);
|
||||
}
|
||||
assert(pos.row >= 0);
|
||||
|
||||
ExtmarkItem item = map_get(uint64_t, ExtmarkItem)(buf->b_extmark_index,
|
||||
mark);
|
||||
assert(mark.pos.row >= 0);
|
||||
mtpos_t endpos = marktree_get_altpos(buf->b_marktree, mark, NULL);
|
||||
|
||||
ret.ns_id = ns_id;
|
||||
ret.mark_id = id;
|
||||
ret.row = pos.row;
|
||||
ret.col = pos.col;
|
||||
ret.row = mark.pos.row;
|
||||
ret.col = mark.pos.col;
|
||||
ret.end_row = endpos.row;
|
||||
ret.end_col = endpos.col;
|
||||
ret.decor = item.decor;
|
||||
ret.decor = get_decor(mark);
|
||||
|
||||
return ret;
|
||||
}
|
||||
@@ -378,25 +353,26 @@ void extmark_free_all(buf_T *buf)
|
||||
return;
|
||||
}
|
||||
|
||||
uint64_t id;
|
||||
ExtmarkNs ns;
|
||||
ExtmarkItem item;
|
||||
MarkTreeIter itr[1] = { 0 };
|
||||
marktree_itr_get(buf->b_marktree, 0, 0, itr);
|
||||
while (true) {
|
||||
mtkey_t mark = marktree_itr_current(itr);
|
||||
if (mark.pos.row < 0) {
|
||||
break;
|
||||
}
|
||||
|
||||
// don't free mark.decor_full twice for a paired mark.
|
||||
if (!(mt_paired(mark) && mt_end(mark))) {
|
||||
decor_free(mark.decor_full);
|
||||
}
|
||||
|
||||
marktree_itr_next(buf->b_marktree, itr);
|
||||
}
|
||||
|
||||
marktree_clear(buf->b_marktree);
|
||||
|
||||
map_foreach(buf->b_extmark_ns, id, ns, {
|
||||
(void)id;
|
||||
map_destroy(uint64_t, uint64_t)(ns.map);
|
||||
});
|
||||
map_destroy(uint64_t, ExtmarkNs)(buf->b_extmark_ns);
|
||||
map_init(uint64_t, ExtmarkNs, buf->b_extmark_ns);
|
||||
|
||||
map_foreach(buf->b_extmark_index, id, item, {
|
||||
(void)id;
|
||||
decor_free(item.decor);
|
||||
});
|
||||
map_destroy(uint64_t, ExtmarkItem)(buf->b_extmark_index);
|
||||
map_init(uint64_t, ExtmarkItem, buf->b_extmark_index);
|
||||
map_destroy(uint32_t, uint32_t)(buf->b_extmark_ns);
|
||||
map_init(uint32_t, uint32_t, buf->b_extmark_ns);
|
||||
}
|
||||
|
||||
|
||||
@@ -437,16 +413,16 @@ void u_extmark_copy(buf_T *buf, int l_row, colnr_T l_col, int u_row, colnr_T u_c
|
||||
MarkTreeIter itr[1] = { 0 };
|
||||
marktree_itr_get(buf->b_marktree, l_row, l_col, itr);
|
||||
while (true) {
|
||||
mtmark_t mark = marktree_itr_current(itr);
|
||||
if (mark.row < 0
|
||||
|| mark.row > u_row
|
||||
|| (mark.row == u_row && mark.col > u_col)) {
|
||||
mtkey_t mark = marktree_itr_current(itr);
|
||||
if (mark.pos.row < 0
|
||||
|| mark.pos.row > u_row
|
||||
|| (mark.pos.row == u_row && mark.pos.col > u_col)) {
|
||||
break;
|
||||
}
|
||||
ExtmarkSavePos pos;
|
||||
pos.mark = mark.id;
|
||||
pos.old_row = mark.row;
|
||||
pos.old_col = mark.col;
|
||||
pos.mark = mt_lookup_key(mark);
|
||||
pos.old_row = mark.pos.row;
|
||||
pos.old_col = mark.pos.col;
|
||||
pos.row = -1;
|
||||
pos.col = -1;
|
||||
|
||||
|
Reference in New Issue
Block a user