diff --git a/src/nvim/extmark.c b/src/nvim/extmark.c index 4ff298cde5..c20c7dea23 100644 --- a/src/nvim/extmark.c +++ b/src/nvim/extmark.c @@ -70,24 +70,19 @@ void extmark_set(buf_T *buf, uint32_t ns_id, uint32_t *idp, int row, colnr_T col extmark_del_id(buf, ns_id, id); } else { assert(marktree_itr_valid(itr)); - bool invalid = mt_invalid(old_mark); 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; + if (!mt_invalid(old_mark) && mt_decor_any(old_mark)) { + mt_itr_rawkey(itr).flags &= (uint16_t) ~MT_FLAG_EXTERNAL_MASK; buf_decor_remove(buf, row, row, col, mt_decor(old_mark), true); - mt_itr_rawkey(itr).flags = save_flags; } - marktree_revise_flags(buf->b_marktree, itr, flags); + mt_itr_rawkey(itr).flags |= flags; mt_itr_rawkey(itr).decor_data = decor.data; + marktree_revise_meta(buf->b_marktree, itr, old_mark); goto revised; } marktree_del_itr(buf->b_marktree, itr, false); - if (!invalid) { + if (!mt_invalid(old_mark)) { buf_decor_remove(buf, old_mark.pos.row, old_mark.pos.row, old_mark.pos.col, mt_decor(old_mark), true); } @@ -131,6 +126,7 @@ static void extmark_setraw(buf_T *buf, uint64_t mark, int row, colnr_T col, bool int row2 = 0; if (invalid) { mt_itr_rawkey(itr).flags &= (uint16_t) ~MT_FLAG_INVALID; + marktree_revise_meta(buf->b_marktree, itr, key); } else if (move && key.flags & MT_FLAG_DECOR_SIGNTEXT && buf->b_signcols.autom) { MTPos end = marktree_get_altpos(buf->b_marktree, key, NULL); row1 = MIN(end.row, MIN(key.pos.row, row)); @@ -394,6 +390,7 @@ void extmark_splice_delete(buf_T *buf, int l_row, colnr_T l_col, int u_row, coln } else { invalidated = true; mt_itr_rawkey(itr).flags |= MT_FLAG_INVALID; + marktree_revise_meta(buf->b_marktree, itr, mark); buf_decor_remove(buf, mark.pos.row, endpos.row, mark.pos.col, mt_decor(mark), false); } } diff --git a/src/nvim/marktree.c b/src/nvim/marktree.c index 9e3005b6a3..555fef5bbd 100644 --- a/src/nvim/marktree.c +++ b/src/nvim/marktree.c @@ -446,7 +446,7 @@ static MTNode *marktree_alloc_node(MarkTree *b, bool internal) // really meta_inc[kMTMetaCount] static void meta_describe_key_inc(uint32_t *meta_inc, MTKey *k) { - if (!mt_end(*k)) { + if (!mt_end(*k) && !mt_invalid(*k)) { meta_inc[kMTMetaInline] += (k->flags & MT_FLAG_DECOR_VIRT_TEXT_INLINE) ? 1 : 0; meta_inc[kMTMetaLines] += (k->flags & MT_FLAG_DECOR_VIRT_LINES) ? 1 : 0; meta_inc[kMTMetaSignHL] += (k->flags & MT_FLAG_DECOR_SIGNHL) ? 1 : 0; @@ -774,14 +774,10 @@ 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) +void marktree_revise_meta(MarkTree *b, MarkTreeIter *itr, MTKey old_key) { - 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]; + uint32_t meta_old[4], meta_new[4]; + meta_describe_key(meta_old, old_key); meta_describe_key(meta_new, rawkey(itr)); if (!memcmp(meta_old, meta_new, sizeof(meta_old))) { diff --git a/test/functional/ui/decorations_spec.lua b/test/functional/ui/decorations_spec.lua index 61a5e1d6f7..042975f898 100644 --- a/test/functional/ui/decorations_spec.lua +++ b/test/functional/ui/decorations_spec.lua @@ -5641,6 +5641,19 @@ l5 ]]) eq("Invalid 'sign_text'", pcall_err(api.nvim_buf_set_extmark, 0, ns, 5, 0, {sign_text='❤️x'})) end) + + it('auto signcolumn hides with invalidated sign', function() + api.nvim_set_option_value('signcolumn', 'auto', {}) + api.nvim_buf_set_extmark(0, ns, 0, 0, {sign_text='S1', invalidate=true}) + feed('iabdd') + screen:expect({ + grid = [[ + ^a | + {1:~ }|*8 + | + ]] + }) + end) end) describe('decorations: virt_text', function()