changeset 19534:36ec10251b2b v8.2.0324

patch 8.2.0324: text property not updated correctly when inserting/deleting Commit: https://github.com/vim/vim/commit/12f20038714928bfecdeee31ed1f927324542034 Author: Bram Moolenaar <Bram@vim.org> Date: Wed Feb 26 22:06:00 2020 +0100 patch 8.2.0324: text property not updated correctly when inserting/deleting Problem: Text property not updated correctly when inserting/deleting. Solution: Use the right column when deleting. Make zero-width text properties respect start_incl and end_incl. (Axel Forsman, closes #5696, closes #5679)
author Bram Moolenaar <Bram@vim.org>
date Wed, 26 Feb 2020 22:15:04 +0100
parents ffe25b424609
children b8ce0a9d1657
files src/change.c src/testdir/test_listener.vim src/testdir/test_textprop.vim src/textprop.c src/version.c
diffstat 5 files changed, 84 insertions(+), 47 deletions(-) [+]
line wrap: on
line diff
--- a/src/change.c
+++ b/src/change.c
@@ -1301,7 +1301,7 @@ del_bytes(
 #endif
 
     // mark the buffer as changed and prepare for displaying
-    inserted_bytes(lnum, curwin->w_cursor.col, -count);
+    inserted_bytes(lnum, col, -count);
 
     return OK;
 }
--- a/src/testdir/test_listener.vim
+++ b/src/testdir/test_listener.vim
@@ -326,3 +326,16 @@ func Test_listener_cleared_newbuf()
   bwipe!
   delfunc Listener
 endfunc
+
+func Test_col_after_deletion_moved_cur()
+	func Listener(bufnr, start, end, added, changes)
+    call assert_equal([#{lnum: 1, end: 2, added: 0, col: 2}], a:changes)
+	endfunc
+	new
+	call setline(1, ['foo'])
+	let lid = listener_add('Listener')
+	call feedkeys("lD", 'xt')
+  call listener_flush()
+	bwipe!
+	delfunc Listener
+endfunc
--- a/src/testdir/test_textprop.vim
+++ b/src/testdir/test_textprop.vim
@@ -6,8 +6,6 @@ CheckFeature textprop
 
 source screendump.vim
 
-" test length zero
-
 func Test_proptype_global()
   call prop_type_add('comment', {'highlight': 'Directory', 'priority': 123, 'start_incl': 1, 'end_incl': 1})
   let proptypes = prop_type_list()
@@ -233,13 +231,20 @@ func Test_prop_add()
 
   " Prop without length or end column is zero length
   call prop_clear(1)
-  call prop_add(1, 5, {'type': 'two'})
-  let expected = [{'col': 5, 'length': 0, 'type': 'two', 'id': 0, 'start': 1, 'end': 1}]
+  call prop_type_add('included', {'start_incl': 1, 'end_incl': 1})
+  call prop_add(1, 5, #{type: 'included'})
+  let expected = [#{col: 5, length: 0, type: 'included', id: 0, start: 1, end: 1}]
+  call assert_equal(expected, prop_list(1))
+
+  " Inserting text makes the prop bigger.
+  exe "normal 5|ixx\<Esc>"
+  let expected = [#{col: 5, length: 2, type: 'included', id: 0, start: 1, end: 1}]
   call assert_equal(expected, prop_list(1))
 
   call assert_fails("call prop_add(1, 5, {'type': 'two', 'bufnr': 234343})", 'E158:')
 
   call DeletePropTypes()
+  call prop_type_delete('included')
   bwipe!
 endfunc
 
--- a/src/textprop.c
+++ b/src/textprop.c
@@ -1232,7 +1232,6 @@ adjust_prop_columns(
 {
     int		proplen;
     char_u	*props;
-    textprop_T	tmp_prop;
     proptype_T  *pt;
     int		dirty = FALSE;
     int		ri, wi;
@@ -1249,62 +1248,80 @@ adjust_prop_columns(
     wi = 0; // write index
     for (ri = 0; ri < proplen; ++ri)
     {
-	int start_incl;
+	textprop_T	prop;
+	int		start_incl, end_incl;
+	int		can_drop;
+
+	mch_memmove(&prop, props + ri * sizeof(textprop_T), sizeof(textprop_T));
+	pt = text_prop_type_by_id(curbuf, prop.tp_type);
+	start_incl = (pt != NULL && (pt->pt_flags & PT_FLAG_INS_START_INCL))
+						   || (flags & APC_SUBSTITUTE);
+	end_incl = (pt != NULL && (pt->pt_flags & PT_FLAG_INS_END_INCL));
+	// Do not drop zero-width props if they later can increase in size
+	can_drop = !(start_incl || end_incl);
 
-	mch_memmove(&tmp_prop, props + ri * sizeof(textprop_T),
-							   sizeof(textprop_T));
-	pt = text_prop_type_by_id(curbuf, tmp_prop.tp_type);
-	start_incl = (flags & APC_SUBSTITUTE) ||
-		       (pt != NULL && (pt->pt_flags & PT_FLAG_INS_START_INCL));
+	if (bytes_added > 0)
+	{
+	    if (col + 1 <= prop.tp_col
+			      - (start_incl || (prop.tp_len == 0 && end_incl)))
+	    {
+		// Change is entirely before the text property: Only shift
+		prop.tp_col += bytes_added;
+		// Save for undo if requested and not done yet.
+		if ((flags & APC_SAVE_FOR_UNDO) && !dirty)
+		    u_savesub(lnum);
+		dirty = TRUE;
+	    }
+	    else if (col + 1 < prop.tp_col + prop.tp_len + end_incl)
+	    {
+		// Insertion was inside text property
+		prop.tp_len += bytes_added;
+		// Save for undo if requested and not done yet.
+		if ((flags & APC_SAVE_FOR_UNDO) && !dirty)
+		    u_savesub(lnum);
+		dirty = TRUE;
+	    }
+	}
+	else if (prop.tp_col > col + 1)
+	{
+	    int len_changed = FALSE;
 
-	if (bytes_added > 0
-		&& (tmp_prop.tp_col >= col + (start_incl ? 2 : 1)))
-	{
-	    tmp_prop.tp_col += bytes_added;
+	    if (prop.tp_col + bytes_added < col + 1)
+	    {
+		prop.tp_len += (prop.tp_col - 1 - col) + bytes_added;
+		prop.tp_col = col + 1;
+		len_changed = TRUE;
+	    }
+	    else
+		prop.tp_col += bytes_added;
 	    // Save for undo if requested and not done yet.
 	    if ((flags & APC_SAVE_FOR_UNDO) && !dirty)
 		u_savesub(lnum);
 	    dirty = TRUE;
-	}
-	else if (bytes_added <= 0 && (tmp_prop.tp_col > col + 1))
-	{
-	    int len_changed = FALSE;
-
-	    if (tmp_prop.tp_col + bytes_added < col + 1)
+	    if (len_changed && prop.tp_len <= 0)
 	    {
-		tmp_prop.tp_len += (tmp_prop.tp_col - 1 - col) + bytes_added;
-		tmp_prop.tp_col = col + 1;
-		len_changed = TRUE;
+		prop.tp_len = 0;
+		if (can_drop)
+		    continue;  // drop this text property
 	    }
+	}
+	else if (prop.tp_len > 0 && prop.tp_col + prop.tp_len > col)
+	{
+	    int after = col - bytes_added - (prop.tp_col - 1 + prop.tp_len);
+
+	    if (after > 0)
+		prop.tp_len += bytes_added + after;
 	    else
-		tmp_prop.tp_col += bytes_added;
+		prop.tp_len += bytes_added;
 	    // Save for undo if requested and not done yet.
 	    if ((flags & APC_SAVE_FOR_UNDO) && !dirty)
 		u_savesub(lnum);
 	    dirty = TRUE;
-	    if (len_changed && tmp_prop.tp_len <= 0)
+	    if (prop.tp_len <= 0 && can_drop)
 		continue;  // drop this text property
 	}
-	else if (tmp_prop.tp_len > 0
-		&& tmp_prop.tp_col + tmp_prop.tp_len > col
-		       + ((pt != NULL && (pt->pt_flags & PT_FLAG_INS_END_INCL))
-								      ? 0 : 1))
-	{
-	    int after = col - bytes_added
-				     - (tmp_prop.tp_col - 1 + tmp_prop.tp_len);
-	    if (after > 0)
-		tmp_prop.tp_len += bytes_added + after;
-	    else
-		tmp_prop.tp_len += bytes_added;
-	    // Save for undo if requested and not done yet.
-	    if ((flags & APC_SAVE_FOR_UNDO) && !dirty)
-		u_savesub(lnum);
-	    dirty = TRUE;
-	    if (tmp_prop.tp_len <= 0)
-		continue;  // drop this text property
-	}
-	mch_memmove(props + wi * sizeof(textprop_T), &tmp_prop,
-							   sizeof(textprop_T));
+
+	mch_memmove(props + wi * sizeof(textprop_T), &prop, sizeof(textprop_T));
 	++wi;
     }
     if (dirty)
--- a/src/version.c
+++ b/src/version.c
@@ -739,6 +739,8 @@ static char *(features[]) =
 static int included_patches[] =
 {   /* Add new patch number below this line */
 /**/
+    324,
+/**/
     323,
 /**/
     322,