From fb4cf05e446baf2aa13f0499f4c2a1999ed2d153 Mon Sep 17 00:00:00 2001 From: Andrej Zieger Date: Mon, 20 May 2019 20:04:47 +0200 Subject: [PATCH] vim-patch:8.1.0767: when deleting lines at the bottom signs are misplaced Problem: When deleting lines at the bottom signs are misplaced. Solution: Properly update the line number of signs at the end of a buffer after a delete/undo operation. (Yegappan Lakshmanan, closes vim/vim#3798) https://github.com/vim/vim/commit/c771bf901622064dc27421b04853e16b6914a295 --- src/nvim/sign.c | 12 ++++++++-- src/nvim/testdir/test_signs.vim | 42 +++++++++++++++++++++++++++++++-- 2 files changed, 50 insertions(+), 4 deletions(-) diff --git a/src/nvim/sign.c b/src/nvim/sign.c index 9750101ac4..7c55742d4d 100644 --- a/src/nvim/sign.c +++ b/src/nvim/sign.c @@ -647,23 +647,31 @@ void sign_mark_adjust(linenr_T line1, linenr_T line2, long amount, long amount_a signlist_T *sign; // a sign in a b_signlist signlist_T *next; // the next sign in a b_signlist signlist_T **lastp; // pointer to pointer to current sign + linenr_T new_lnum; // new line number to assign to sign curbuf->b_signcols_max = -1; lastp = &curbuf->b_signlist; FOR_ALL_SIGNS_IN_BUF(curbuf, sign) { next = sign->next; + new_lnum = sign->lnum; if (sign->lnum >= line1 && sign->lnum <= line2) { if (amount == MAXLNUM) { *lastp = next; xfree(sign); continue; } else { - sign->lnum += amount; + new_lnum += amount; } } else if (sign->lnum > line2) { - sign->lnum += amount_after; + 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->lnum >= line1 && new_lnum <= curbuf->b_ml.ml_line_count) { + sign->lnum = new_lnum; + } lastp = &sign->next; } } diff --git a/src/nvim/testdir/test_signs.vim b/src/nvim/testdir/test_signs.vim index 3d6990f136..3edb4b4ae0 100644 --- a/src/nvim/testdir/test_signs.vim +++ b/src/nvim/testdir/test_signs.vim @@ -1202,13 +1202,13 @@ func Test_sign_lnum_adjust() enew! | only! sign define sign1 text=#> linehl=Comment - call setline(1, ['A', 'B', 'C', 'D']) + call setline(1, ['A', 'B', 'C', 'D', 'E']) exe 'sign place 5 line=3 name=sign1 buffer=' . bufnr('') let l = sign_getplaced(bufnr('')) call assert_equal(3, l[0].signs[0].lnum) " Add some lines before the sign and check the sign line number - call append(2, ['AA', 'AB', 'AC']) + call append(2, ['BA', 'BB', 'BC']) let l = sign_getplaced(bufnr('')) call assert_equal(6, l[0].signs[0].lnum) @@ -1217,6 +1217,44 @@ func Test_sign_lnum_adjust() let l = sign_getplaced(bufnr('')) call assert_equal(4, l[0].signs[0].lnum) + " Insert some lines after the sign and check the sign line number + call append(5, ['DA', 'DB']) + let l = sign_getplaced(bufnr('')) + call assert_equal(4, l[0].signs[0].lnum) + + " Delete some lines after the sign and check the sign line number + call deletebufline('', 6, 7) + let l = sign_getplaced(bufnr('')) + call assert_equal(4, l[0].signs[0].lnum) + + " Break the undo. Otherwise the undo operation below will undo all the + " changes made by this function. + let &undolevels=&undolevels + + " Delete the line with the sign + call deletebufline('', 4) + let l = sign_getplaced(bufnr('')) + call assert_equal(4, l[0].signs[0].lnum) + + " Undo the delete operation + undo + let l = sign_getplaced(bufnr('')) + call assert_equal(5, l[0].signs[0].lnum) + + " Break the undo + let &undolevels=&undolevels + + " Delete few lines at the end of the buffer including the line with the sign + " Sign line number should not change (as it is placed outside of the buffer) + call deletebufline('', 3, 6) + let l = sign_getplaced(bufnr('')) + call assert_equal(5, l[0].signs[0].lnum) + + " Undo the delete operation. Sign should be restored to the previous line + undo + let l = sign_getplaced(bufnr('')) + call assert_equal(5, l[0].signs[0].lnum) + sign unplace * group=* sign undefine sign1 enew!