aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLuuk van Baal <luukvbaal@gmail.com>2024-06-10 16:55:16 +0200
committerLuuk van Baal <luukvbaal@gmail.com>2024-06-10 20:00:59 +0200
commit1dcda865591b9bdda2fec1a1860efb4df56ea533 (patch)
tree881b423a64bd4d2a9e6f4170c9115a2a1e73d67b
parentd9af8c2431b7c6395abece8104be6a47d6f61f39 (diff)
downloadrneovim-1dcda865591b9bdda2fec1a1860efb4df56ea533.tar.gz
rneovim-1dcda865591b9bdda2fec1a1860efb4df56ea533.tar.bz2
rneovim-1dcda865591b9bdda2fec1a1860efb4df56ea533.zip
fix(column): clamp line number for legacy signs
Problem: Legacy :sign API still allows placing signs beyond the end of the buffer. This is unaccounted for by the signcolumn tracking logic and is disallowed in general for the extmark API which implements it now. Solution: Clamp legacy sign line number to the length of the buffer.
-rw-r--r--src/nvim/sign.c4
-rw-r--r--test/functional/ui/sign_spec.lua30
-rw-r--r--test/old/testdir/test_signs.vim6
3 files changed, 36 insertions, 4 deletions
diff --git a/src/nvim/sign.c b/src/nvim/sign.c
index 1ca0e846a9..605098fb66 100644
--- a/src/nvim/sign.c
+++ b/src/nvim/sign.c
@@ -126,8 +126,8 @@ static void buf_set_sign(buf_T *buf, uint32_t *id, char *group, int prio, linenr
| (has_hl ? MT_FLAG_DECOR_SIGNHL : 0);
DecorInline decor = { .ext = true, .data.ext = { .vt = NULL, .sh_idx = decor_put_sh(sign) } };
- extmark_set(buf, ns, id, lnum - 1, 0, -1, -1, decor, decor_flags, true,
- false, true, true, NULL);
+ extmark_set(buf, ns, id, MIN(buf->b_ml.ml_line_count, lnum) - 1, 0, -1, -1,
+ decor, decor_flags, true, false, true, true, NULL);
}
/// For an existing, placed sign with "id", modify the sign, group or priority.
diff --git a/test/functional/ui/sign_spec.lua b/test/functional/ui/sign_spec.lua
index b353b3738a..6f4bf5695d 100644
--- a/test/functional/ui/sign_spec.lua
+++ b/test/functional/ui/sign_spec.lua
@@ -577,4 +577,34 @@ describe('Signs', function()
]])
eq({}, eval('sign_getdefined()'))
end)
+
+ it('no crash when unplacing signs beyond end of buffer', function()
+ exec([[
+ sign define S1 text=S1
+ sign define S2 text=S2
+ sign place 1 line=8 name=S1
+ sign place 2 line=9 name=S2
+ ]])
+ -- Now placed at end of buffer
+ local s1 = {
+ grid = [[
+ S2^ |
+ {0:~ }|*12
+ |
+ ]],
+ }
+ screen:expect(s1)
+ -- Signcolumn tracking used to not count signs placed beyond end of buffer here
+ exec('set signcolumn=auto:9')
+ screen:expect({
+ grid = [[
+ S2S1^ |
+ {0:~ }|*12
+ |
+ ]],
+ })
+ -- Unplacing the sign does not crash by decrementing tracked signs below zero
+ exec('sign unplace 1')
+ screen:expect(s1)
+ end)
end)
diff --git a/test/old/testdir/test_signs.vim b/test/old/testdir/test_signs.vim
index d7baa7e870..69fefccb3f 100644
--- a/test/old/testdir/test_signs.vim
+++ b/test/old/testdir/test_signs.vim
@@ -89,8 +89,9 @@ func Test_sign()
" Place a sign without specifying the filename or buffer
sign place 77 line=9 name=Sign2
let a=execute('sign place')
+ " Nvim: sign line clamped to buffer length
call assert_equal("\n--- Signs ---\nSigns for [NULL]:\n" .
- \ " line=9 id=77 name=Sign2 priority=10\n", a)
+ \ " line=4 id=77 name=Sign2 priority=10\n", a)
sign unplace *
" Check :jump with file=...
@@ -799,10 +800,11 @@ func Test_sign_group()
set buftype=nofile
sign place 25 line=76 name=sign1 priority=99 file=foo
let a = execute('sign place')
+ " Nvim: sign line clamped to buffer length
call assert_equal("\n--- Signs ---\nSigns for Xsign:\n" .
\ " line=10 id=5 name=sign1 priority=10\n" .
\ "Signs for foo:\n" .
- \ " line=76 id=25 name=sign1 priority=99\n", a)
+ \ " line=1 id=25 name=sign1 priority=99\n", a)
close
bwipe foo