aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorzeertzjq <zeertzjq@outlook.com>2022-09-29 15:48:39 +0800
committerGitHub <noreply@github.com>2022-09-29 15:48:39 +0800
commit1cf44d6f5794c7b6bd181dfb2ce51f5ff4381ee8 (patch)
tree523d68e4d878b18f244e026125b9e6f69493b109
parenta80ab395aa7beedf8f39870d331b4b32cc6e5d2d (diff)
downloadrneovim-1cf44d6f5794c7b6bd181dfb2ce51f5ff4381ee8.tar.gz
rneovim-1cf44d6f5794c7b6bd181dfb2ce51f5ff4381ee8.tar.bz2
rneovim-1cf44d6f5794c7b6bd181dfb2ce51f5ff4381ee8.zip
fix(column): move sign sentinel after inserting/deleting lines (#20400)
-rw-r--r--src/nvim/sign.c55
-rw-r--r--test/functional/ui/sign_spec.lua85
2 files changed, 123 insertions, 17 deletions
diff --git a/src/nvim/sign.c b/src/nvim/sign.c
index 6f13dd2f06..9c517098b9 100644
--- a/src/nvim/sign.c
+++ b/src/nvim/sign.c
@@ -724,7 +724,27 @@ static void sign_list_placed(buf_T *rbuf, char *sign_group)
}
}
-/// Adjust a placed sign for inserted/deleted lines.
+/// Adjust or delete a placed sign for inserted/deleted lines.
+///
+/// @return the new line number of the sign, or 0 if the sign is in deleted lines.
+static linenr_T sign_adjust_one(const linenr_T se_lnum, linenr_T line1, linenr_T line2,
+ linenr_T amount, linenr_T amount_after)
+{
+ if (se_lnum < line1) {
+ // Ignore changes to lines after the sign
+ return se_lnum;
+ }
+ if (se_lnum > line2) {
+ // Lines inserted or deleted before the sign
+ return se_lnum + amount_after;
+ }
+ if (amount == MAXLNUM) { // sign in deleted lines
+ return 0;
+ }
+ return se_lnum + amount;
+}
+
+/// Adjust placed signs for inserted/deleted lines.
void sign_mark_adjust(linenr_T line1, linenr_T line2, linenr_T amount, linenr_T amount_after)
{
sign_entry_T *sign; // a sign in a b_signlist
@@ -735,9 +755,7 @@ void sign_mark_adjust(linenr_T line1, linenr_T line2, linenr_T amount, linenr_T
int is_fixed = 0;
int signcol = win_signcol_configured(curwin, &is_fixed);
- bool delete = amount == MAXLNUM;
-
- if (delete) {
+ if (amount == MAXLNUM) { // deleting
buf_signcols_del_check(curbuf, line1, line2);
}
@@ -745,11 +763,10 @@ void sign_mark_adjust(linenr_T line1, linenr_T line2, linenr_T amount, linenr_T
for (sign = curbuf->b_signlist; sign != NULL; sign = next) {
next = sign->se_next;
- new_lnum = sign->se_lnum;
- if (sign->se_lnum >= line1 && sign->se_lnum <= line2) {
- if (!delete) {
- new_lnum += amount;
- } else if (!is_fixed || signcol >= 2) {
+
+ new_lnum = sign_adjust_one(sign->se_lnum, line1, line2, amount, amount_after);
+ if (new_lnum == 0) { // sign in deleted lines
+ if (!is_fixed || signcol >= 2) {
*lastp = next;
if (next) {
next->se_prev = last;
@@ -757,19 +774,23 @@ void sign_mark_adjust(linenr_T line1, linenr_T line2, linenr_T amount, linenr_T
xfree(sign);
continue;
}
- } else if (sign->se_lnum > line2) {
- new_lnum += amount_after;
- }
- // If the new sign line number is past the last line in the buffer,
- // then don't adjust the line number. Otherwise, it will always be past
- // the last line and will not be visible.
- if (sign->se_lnum >= line1 && new_lnum <= curbuf->b_ml.ml_line_count) {
- sign->se_lnum = new_lnum;
+ } else {
+ // If the new sign line number is past the last line in the buffer,
+ // then don't adjust the line number. Otherwise, it will always be past
+ // the last line and will not be visible.
+ if (new_lnum <= curbuf->b_ml.ml_line_count) {
+ sign->se_lnum = new_lnum;
+ }
}
last = sign;
lastp = &sign->se_next;
}
+
+ new_lnum = sign_adjust_one(curbuf->b_signcols.sentinel, line1, line2, amount, amount_after);
+ if (new_lnum != 0) {
+ curbuf->b_signcols.sentinel = new_lnum;
+ }
}
/// Find index of a ":sign" subcmd from its name.
diff --git a/test/functional/ui/sign_spec.lua b/test/functional/ui/sign_spec.lua
index dbc92ca222..ff3e143126 100644
--- a/test/functional/ui/sign_spec.lua
+++ b/test/functional/ui/sign_spec.lua
@@ -2,6 +2,7 @@ local helpers = require('test.functional.helpers')(after_each)
local Screen = require('test.functional.ui.screen')
local clear, feed, command = helpers.clear, helpers.feed, helpers.command
local source = helpers.source
+local meths = helpers.meths
describe('Signs', function()
local screen
@@ -592,4 +593,88 @@ describe('Signs', function()
]])
end)
end)
+
+ it('signcolumn width is updated when removing all signs after deleting lines', function()
+ meths.buf_set_lines(0, 0, 1, true, {'a', 'b', 'c', 'd', 'e'})
+ command('sign define piet text=>>')
+ command('sign place 10001 line=1 name=piet')
+ command('sign place 10002 line=5 name=piet')
+ command('2delete')
+ command('sign unplace 10001')
+ screen:expect([[
+ {2: }a |
+ {2: }^c |
+ {2: }d |
+ >>e |
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ |
+ ]])
+ command('sign unplace 10002')
+ screen:expect([[
+ a |
+ ^c |
+ d |
+ e |
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ |
+ ]])
+ end)
+
+ it('signcolumn width is updated when removing all signs after inserting lines', function()
+ meths.buf_set_lines(0, 0, 1, true, {'a', 'b', 'c', 'd', 'e'})
+ command('sign define piet text=>>')
+ command('sign place 10001 line=1 name=piet')
+ command('sign place 10002 line=5 name=piet')
+ command('copy .')
+ command('sign unplace 10001')
+ screen:expect([[
+ {2: }a |
+ {2: }^a |
+ {2: }b |
+ {2: }c |
+ {2: }d |
+ >>e |
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ |
+ ]])
+ command('sign unplace 10002')
+ screen:expect([[
+ a |
+ ^a |
+ b |
+ c |
+ d |
+ e |
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ |
+ ]])
+ end)
end)