diff --git a/src/nvim/sign.c b/src/nvim/sign.c index 6f13dd2f0627dc..9c517098b99771 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 dbc92ca222dc77..ff3e1431265b68 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)