aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorbfredl <bjorn.linse@gmail.com>2024-02-17 18:42:47 +0100
committerGitHub <noreply@github.com>2024-02-17 18:42:47 +0100
commitb12d193b4a68242fb0c7e4f924c8abce3488e1c8 (patch)
treecd2a63aeaa043f48bd119ed8901c96a3e31f5052
parent01c15a30c0ab56e14342f9996bea3ad86a68a343 (diff)
parent2accf2480530c7df2120d8522103f5f1516268cf (diff)
downloadrneovim-b12d193b4a68242fb0c7e4f924c8abce3488e1c8.tar.gz
rneovim-b12d193b4a68242fb0c7e4f924c8abce3488e1c8.tar.bz2
rneovim-b12d193b4a68242fb0c7e4f924c8abce3488e1c8.zip
Merge pull request #27481 from bfredl/meta_revise
fix(decorations): crash with revised mark with changed decoration flags
-rw-r--r--src/nvim/extmark.c8
-rw-r--r--src/nvim/marktree.c29
-rw-r--r--test/functional/ui/decorations_spec.lua30
3 files changed, 65 insertions, 2 deletions
diff --git a/src/nvim/extmark.c b/src/nvim/extmark.c
index e753ad199a..e4c4960b9e 100644
--- a/src/nvim/extmark.c
+++ b/src/nvim/extmark.c
@@ -74,11 +74,15 @@ void extmark_set(buf_T *buf, uint32_t ns_id, uint32_t *idp, int row, colnr_T col
if (old_mark.pos.row == row && old_mark.pos.col == col) {
// not paired: we can revise in place
if (!invalid && mt_decor_any(old_mark)) {
+ // TODO(bfredl): conflict of concerns: buf_decor_remove() must process
+ // the buffer as if MT_FLAG_DECOR_SIGNTEXT is already removed, however
+ // marktree must precisely adjust the set of flags from the old set to the new
+ uint16_t save_flags = mt_itr_rawkey(itr).flags;
mt_itr_rawkey(itr).flags &= (uint16_t) ~MT_FLAG_DECOR_SIGNTEXT;
buf_decor_remove(buf, row, row, col, mt_decor(old_mark), true);
+ mt_itr_rawkey(itr).flags = save_flags;
}
- mt_itr_rawkey(itr).flags &= (uint16_t) ~MT_FLAG_EXTERNAL_MASK;
- mt_itr_rawkey(itr).flags |= flags;
+ marktree_revise_flags(buf->b_marktree, itr, flags);
mt_itr_rawkey(itr).decor_data = decor.data;
goto revised;
}
diff --git a/src/nvim/marktree.c b/src/nvim/marktree.c
index 9da7503524..1da75eb2af 100644
--- a/src/nvim/marktree.c
+++ b/src/nvim/marktree.c
@@ -774,6 +774,35 @@ uint64_t marktree_del_itr(MarkTree *b, MarkTreeIter *itr, bool rev)
return other;
}
+void marktree_revise_flags(MarkTree *b, MarkTreeIter *itr, uint16_t new_flags)
+{
+ uint32_t meta_old[4];
+ meta_describe_key(meta_old, rawkey(itr));
+ rawkey(itr).flags &= (uint16_t) ~MT_FLAG_EXTERNAL_MASK;
+ rawkey(itr).flags |= new_flags;
+
+ uint32_t meta_new[4];
+ meta_describe_key(meta_new, rawkey(itr));
+
+ if (!memcmp(meta_old, meta_new, sizeof(meta_old))) {
+ return;
+ }
+
+ MTNode *lnode = itr->x;
+ while (lnode->parent) {
+ uint32_t *meta_p = lnode->parent->meta[lnode->p_idx];
+ for (int m = 0; m < kMTMetaCount; m++) {
+ meta_p[m] += meta_new[m] - meta_old[m];
+ }
+
+ lnode = lnode->parent;
+ }
+
+ for (int m = 0; m < kMTMetaCount; m++) {
+ b->meta_root[m] += meta_new[m] - meta_old[m];
+ }
+}
+
/// similar to intersect_common but modify x and y in place to retain
/// only the items which are NOT in common
static void intersect_merge(Intersection *restrict m, Intersection *restrict x,
diff --git a/test/functional/ui/decorations_spec.lua b/test/functional/ui/decorations_spec.lua
index 930e4c3f10..9bbae0dae0 100644
--- a/test/functional/ui/decorations_spec.lua
+++ b/test/functional/ui/decorations_spec.lua
@@ -2371,6 +2371,36 @@ describe('extmark decorations', function()
|
]]}
end)
+
+ it('can replace marks in place with different decorations #27211', function()
+ local mark = api.nvim_buf_set_extmark(0, ns, 0, 0, { virt_lines = {{{"foo", "ErrorMsg"}}}, })
+ screen:expect{grid=[[
+ ^ |
+ {4:foo} |
+ {1:~ }|*12
+ |
+ ]]}
+
+ api.nvim_buf_set_extmark(0, ns, 0, 0, {
+ id = mark,
+ virt_text = { { "testing", "NonText" } },
+ virt_text_pos = "inline",
+ })
+ screen:expect{grid=[[
+ {1:^testing} |
+ {1:~ }|*13
+ |
+ ]]}
+
+ api.nvim_buf_del_extmark(0, ns, mark)
+ screen:expect{grid=[[
+ ^ |
+ {1:~ }|*13
+ |
+ ]]}
+
+ helpers.assert_alive()
+ end)
end)
describe('decorations: inline virtual text', function()