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.
(cherry picked from commit 1dcda86559
extmark_set() namespace scope and screen test reverse sign order conflict)
This commit is contained in:
Luuk van Baal
2024-06-10 16:55:16 +02:00
parent 0ee3147bc7
commit aa1321801d
3 changed files with 36 additions and 4 deletions

View File

@ -125,8 +125,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, false, 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, false, NULL);
}
/// For an existing, placed sign with "id", modify the sign, group or priority.

View File

@ -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 = [[
S1S2^ |
{0:~ }|*12
|
]],
})
-- Unplacing the sign does not crash by decrementing tracked signs below zero
exec('sign unplace 1')
screen:expect(s1)
end)
end)

View File

@ -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