aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorluukvbaal <luukvbaal@gmail.com>2025-03-16 12:15:50 +0100
committerGitHub <noreply@github.com>2025-03-16 12:15:50 +0100
commit72f630f92dc806e96c064c0e75248c27b26c5171 (patch)
tree150e54d7bd40100282c45a396030a4f72df5d1d6
parent466f20dd7039e1602c9382f76ac6471d9feb49b7 (diff)
downloadrneovim-72f630f92dc806e96c064c0e75248c27b26c5171.tar.gz
rneovim-72f630f92dc806e96c064c0e75248c27b26c5171.tar.bz2
rneovim-72f630f92dc806e96c064c0e75248c27b26c5171.zip
fix(marks): issues with invalid marks and marks beyond eob (#32862)
Problem: Marks that go beyond the end of the buffer, and paired marks whose end is in front of its start mark are added to and removed from the decor. This results in incorrect tracking of the signcolumn. Solution: Ensure such marks are not added to and removed from the decor.
-rw-r--r--src/nvim/decoration.c12
-rw-r--r--src/nvim/drawscreen.c2
-rw-r--r--src/nvim/extmark.c14
-rw-r--r--test/functional/ui/decorations_spec.lua24
4 files changed, 41 insertions, 11 deletions
diff --git a/src/nvim/decoration.c b/src/nvim/decoration.c
index 1226bba436..a7339772ae 100644
--- a/src/nvim/decoration.c
+++ b/src/nvim/decoration.c
@@ -182,8 +182,9 @@ DecorSignHighlight decor_sh_from_inline(DecorHighlightInline item)
void buf_put_decor(buf_T *buf, DecorInline decor, int row, int row2)
{
- if (decor.ext) {
+ if (decor.ext && row < buf->b_ml.ml_line_count) {
uint32_t idx = decor.data.ext.sh_idx;
+ row2 = MIN(buf->b_ml.ml_line_count - 1, row2);
while (idx != DECOR_ID_INVALID) {
DecorSignHighlight *sh = &kv_A(decor_items, idx);
buf_put_decor_sh(buf, sh, row, row2);
@@ -222,16 +223,17 @@ void buf_put_decor_sh(buf_T *buf, DecorSignHighlight *sh, int row1, int row2)
void buf_decor_remove(buf_T *buf, int row1, int row2, int col1, DecorInline decor, bool free)
{
decor_redraw(buf, row1, row2, col1, decor);
- if (decor.ext) {
+ if (decor.ext && row1 < buf->b_ml.ml_line_count) {
uint32_t idx = decor.data.ext.sh_idx;
+ row2 = MIN(buf->b_ml.ml_line_count - 1, row2);
while (idx != DECOR_ID_INVALID) {
DecorSignHighlight *sh = &kv_A(decor_items, idx);
buf_remove_decor_sh(buf, row1, row2, sh);
idx = sh->next;
}
- if (free) {
- decor_free(decor);
- }
+ }
+ if (free) {
+ decor_free(decor);
}
}
diff --git a/src/nvim/drawscreen.c b/src/nvim/drawscreen.c
index e958610f20..35dcbf295b 100644
--- a/src/nvim/drawscreen.c
+++ b/src/nvim/drawscreen.c
@@ -1238,7 +1238,7 @@ static bool win_redraw_signcols(win_T *wp)
if (!buf->b_signcols.autom
&& (*wp->w_p_stc != NUL || (wp->w_maxscwidth > 1 && wp->w_minscwidth != wp->w_maxscwidth))) {
buf->b_signcols.autom = true;
- buf_signcols_count_range(buf, 0, buf->b_ml.ml_line_count, MAXLNUM, kFalse);
+ buf_signcols_count_range(buf, 0, buf->b_ml.ml_line_count - 1, MAXLNUM, kFalse);
}
while (buf->b_signcols.max > 0 && buf->b_signcols.count[buf->b_signcols.max - 1] == 0) {
diff --git a/src/nvim/extmark.c b/src/nvim/extmark.c
index 7e6dfb8dea..cad0f71941 100644
--- a/src/nvim/extmark.c
+++ b/src/nvim/extmark.c
@@ -135,7 +135,7 @@ static void extmark_setraw(buf_T *buf, uint64_t mark, int row, colnr_T col, bool
} else if (!mt_invalid(key) && key.flags & MT_FLAG_DECOR_SIGNTEXT && buf->b_signcols.autom) {
row1 = MIN(alt.pos.row, MIN(key.pos.row, row));
row2 = MAX(alt.pos.row, MAX(key.pos.row, row));
- buf_signcols_count_range(buf, row1, row2, 0, kTrue);
+ buf_signcols_count_range(buf, row1, MIN(curbuf->b_ml.ml_line_count - 1, row2), 0, kTrue);
}
if (move) {
@@ -145,7 +145,7 @@ static void extmark_setraw(buf_T *buf, uint64_t mark, int row, colnr_T col, bool
if (invalid) {
buf_put_decor(buf, mt_decor(key), MIN(row, key.pos.row), MAX(row, key.pos.row));
} else if (!mt_invalid(key) && key.flags & MT_FLAG_DECOR_SIGNTEXT && buf->b_signcols.autom) {
- buf_signcols_count_range(buf, row1, row2, 0, kNone);
+ buf_signcols_count_range(buf, row1, MIN(curbuf->b_ml.ml_line_count - 1, row2), 0, kNone);
}
}
@@ -180,7 +180,9 @@ void extmark_del(buf_T *buf, MarkTreeIter *itr, MTKey key, bool restore)
}
if (mt_decor_any(key)) {
- if (mt_invalid(key)) {
+ // If key is an end mark it has been found first while iterating the marktree,
+ // indicating the decor is already invalid.
+ if (mt_invalid(key) || mt_end(key)) {
decor_free(mt_decor(key));
} else {
buf_decor_remove(buf, key.pos.row, key2.pos.row, key.pos.col, mt_decor(key), true);
@@ -575,7 +577,8 @@ void extmark_splice_impl(buf_T *buf, int start_row, colnr_T start_col, bcount_t
// Remove signs inside edited region from "b_signcols.count", add after splicing.
if (old_row > 0 || new_row > 0) {
- buf_signcols_count_range(buf, start_row, start_row + old_row, 0, kTrue);
+ int row2 = MIN(buf->b_ml.ml_line_count - (new_row - old_row) - 1, start_row + old_row);
+ buf_signcols_count_range(buf, start_row, row2, 0, kTrue);
}
marktree_splice(buf->b_marktree, (int32_t)start_row, start_col,
@@ -583,7 +586,8 @@ void extmark_splice_impl(buf_T *buf, int start_row, colnr_T start_col, bcount_t
new_row, new_col);
if (old_row > 0 || new_row > 0) {
- buf_signcols_count_range(buf, start_row, start_row + new_row, 0, kNone);
+ int row2 = MIN(buf->b_ml.ml_line_count - 1, start_row + new_row);
+ buf_signcols_count_range(buf, start_row, row2, 0, kNone);
}
if (undo == kExtmarkUndo) {
diff --git a/test/functional/ui/decorations_spec.lua b/test/functional/ui/decorations_spec.lua
index c0c0bf4fc1..240a5acc99 100644
--- a/test/functional/ui/decorations_spec.lua
+++ b/test/functional/ui/decorations_spec.lua
@@ -6366,6 +6366,30 @@ l5
]]
})
end)
+
+ it('signcolumn correctly tracked with signs beyond eob and pair end before start', function()
+ api.nvim_set_option_value('signcolumn', 'auto:2', {})
+ api.nvim_set_option_value('filetype', 'lua', {})
+ api.nvim_buf_set_lines(0, 0, -1, false, {'foo', 'bar'})
+ api.nvim_buf_set_extmark(0, ns, 2, 0, {sign_text='S1'})
+ api.nvim_set_hl(0, 'SignColumn', { link = 'Error' })
+ screen:expect([[
+ ^foo |
+ bar |
+ {1:~ }|*7
+ |
+ ]])
+ api.nvim_buf_set_extmark(0, ns, 0, 0, {sign_text='S2', end_row = 1})
+ api.nvim_buf_set_lines(0, 0, -1, false, {'-- foo', '-- bar'})
+ api.nvim_buf_clear_namespace(0, ns, 0, -1)
+ screen:expect([[
+ ^-- foo |
+ -- bar |
+ {1:~ }|*7
+ |
+ ]])
+ assert_alive()
+ end)
end)
describe('decorations: virt_text', function()