changeset 15519:89e76a598b30 v8.1.0767

patch 8.1.0767: when deleting lines at the bottom signs are misplaced commit https://github.com/vim/vim/commit/c771bf901622064dc27421b04853e16b6914a295 Author: Bram Moolenaar <Bram@vim.org> Date: Thu Jan 17 17:36:45 2019 +0100 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 #3798)
author Bram Moolenaar <Bram@vim.org>
date Thu, 17 Jan 2019 17:45:06 +0100
parents a99eedb83c56
children f356d2eb8202
files src/sign.c src/testdir/test_signs.vim src/version.c
diffstat 3 files changed, 57 insertions(+), 7 deletions(-) [+]
line wrap: on
line diff
--- a/src/sign.c
+++ b/src/sign.c
@@ -660,18 +660,28 @@ sign_mark_adjust(
     long	amount_after)
 {
     signlist_T	*sign;		// a sign in a b_signlist
+    linenr_T	new_lnum;
 
     FOR_ALL_SIGNS_IN_BUF(curbuf, sign)
     {
+	// Ignore changes to lines after the sign
+	if (sign->lnum < line1)
+	    continue;
+	new_lnum = sign->lnum;
 	if (sign->lnum >= line1 && sign->lnum <= line2)
 	{
-	    if (amount == MAXLNUM)
-		sign->lnum = line1;
-	    else
-		sign->lnum += amount;
+	    if (amount != MAXLNUM)
+		new_lnum += amount;
 	}
 	else if (sign->lnum > line2)
-	    sign->lnum += amount_after;
+	    // Lines inserted or deleted before the sign
+	    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 (new_lnum <= curbuf->b_ml.ml_line_count)
+	    sign->lnum = new_lnum;
     }
 }
 
--- a/src/testdir/test_signs.vim
+++ b/src/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!
--- a/src/version.c
+++ b/src/version.c
@@ -792,6 +792,8 @@ static char *(features[]) =
 static int included_patches[] =
 {   /* Add new patch number below this line */
 /**/
+    767,
+/**/
     766,
 /**/
     765,