changeset 15294:2d8225cc1315 v8.1.0655

patch 8.1.0655: when appending a line text property flags are not added commit https://github.com/vim/vim/commit/b56ac049ea6ca77a0a9b0a415bac5e82ae60b842 Author: Bram Moolenaar <Bram@vim.org> Date: Fri Dec 28 23:22:40 2018 +0100 patch 8.1.0655: when appending a line text property flags are not added Problem: When appending a line text property flags are not added. Solution: Add text properties to a newly added line.
author Bram Moolenaar <Bram@vim.org>
date Fri, 28 Dec 2018 23:30:05 +0100
parents 0613129efe93
children a8727dd4d239
files src/memline.c src/testdir/test_textprop.vim src/textprop.c src/version.c
diffstat 4 files changed, 119 insertions(+), 33 deletions(-) [+]
line wrap: on
line diff
--- a/src/memline.c
+++ b/src/memline.c
@@ -2568,6 +2568,66 @@ ml_line_alloced(void)
     return (curbuf->b_ml.ml_flags & ML_LINE_DIRTY);
 }
 
+#ifdef FEAT_TEXT_PROP
+    static void
+add_text_props_for_append(
+	    buf_T	*buf,
+	    linenr_T	lnum,
+	    char_u	**line,
+	    int		*len,
+	    char_u	**tofree)
+{
+    int		round;
+    int		new_prop_count = 0;
+    int		count;
+    int		n;
+    char_u	*props;
+    int		new_len;
+    char_u	*new_line;
+    textprop_T	prop;
+
+    // Make two rounds:
+    // 1. calculate the extra space needed
+    // 2. allocate the space and fill it
+    for (round = 1; round <= 2; ++round)
+    {
+	if (round == 2)
+	{
+	    if (new_prop_count == 0)
+		return;  // nothing to do
+	    new_len = *len + new_prop_count * sizeof(textprop_T);
+	    new_line = alloc((unsigned)new_len);
+	    if (new_line == NULL)
+		return;
+	    mch_memmove(new_line, *line, *len);
+	    new_prop_count = 0;
+	}
+
+	// Get the line above to find any props that continue in the next
+	// line.
+	count = get_text_props(buf, lnum, &props, FALSE);
+	for (n = 0; n < count; ++n)
+	{
+	    mch_memmove(&prop, props + n * sizeof(textprop_T), sizeof(textprop_T));
+	    if (prop.tp_flags & TP_FLAG_CONT_NEXT)
+	    {
+		if (round == 2)
+		{
+		    prop.tp_flags |= TP_FLAG_CONT_PREV;
+		    prop.tp_col = 1;
+		    prop.tp_len = *len;
+		    mch_memmove(new_line + *len + new_prop_count * sizeof(textprop_T), &prop, sizeof(textprop_T));
+		}
+		++new_prop_count;
+	    }
+	}
+    }
+    *line = new_line;
+    *tofree = new_line;
+    *len = new_len;
+}
+#endif
+
 /*
  * Append a line after lnum (may be 0 to insert a line in front of the file).
  * "line" does not need to be allocated, but can't be another line in a
@@ -2622,12 +2682,13 @@ ml_append_buf(
 ml_append_int(
     buf_T	*buf,
     linenr_T	lnum,		// append after this line (can be 0)
-    char_u	*line,		// text of the new line
+    char_u	*line_arg,	// text of the new line
     colnr_T	len_arg,	// length of line, including NUL, or 0
     int		newfile,	// flag, see above
     int		mark)		// mark the new line
 {
-    colnr_T	len = len_arg;	// length of line, including NUL, or 0
+    char_u	*line = line_arg;
+    colnr_T	len = len_arg;
     int		i;
     int		line_count;	// number of indexes in current block
     int		offset;
@@ -2641,16 +2702,26 @@ ml_append_int(
     DATA_BL	*dp;
     PTR_BL	*pp;
     infoptr_T	*ip;
-
-					/* lnum out of range */
+#ifdef FEAT_TEXT_PROP
+    char_u	*tofree = NULL;
+#endif
+    int		ret = FAIL;
+
     if (lnum > buf->b_ml.ml_line_count || buf->b_ml.ml_mfp == NULL)
-	return FAIL;
+	return FAIL;  // lnum out of range
 
     if (lowest_marked && lowest_marked > lnum)
 	lowest_marked = lnum + 1;
 
     if (len == 0)
 	len = (colnr_T)STRLEN(line) + 1;	// space needed for the text
+
+#ifdef FEAT_TEXT_PROP
+    if (curbuf->b_has_textprop && lnum > 0)
+	// Add text properties that continue from the previous line.
+	add_text_props_for_append(buf, lnum, &line, &len, &tofree);
+#endif
+
     space_needed = len + INDEX_SIZE;	// space needed for text + index
 
     mfp = buf->b_ml.ml_mfp;
@@ -2663,7 +2734,7 @@ ml_append_int(
  */
     if ((hp = ml_find_line(buf, lnum == 0 ? (linenr_T)1 : lnum,
 							  ML_INSERT)) == NULL)
-	return FAIL;
+	goto theend;
 
     buf->b_ml.ml_flags &= ~ML_EMPTY;
 
@@ -2694,7 +2765,7 @@ ml_append_int(
 	--(buf->b_ml.ml_locked_lineadd);
 	--(buf->b_ml.ml_locked_high);
 	if ((hp = ml_find_line(buf, lnum + 1, ML_INSERT)) == NULL)
-	    return FAIL;
+	    goto theend;
 
 	db_idx = -1;		    /* careful, it is negative! */
 		    /* get line count before the insertion */
@@ -2708,9 +2779,10 @@ ml_append_int(
 
     if ((int)dp->db_free >= space_needed)	/* enough room in data block */
     {
-/*
- * Insert new line in existing data block, or in data block allocated above.
- */
+	/*
+	 * Insert the new line in an existing data block, or in the data block
+	 * allocated above.
+	 */
 	dp->db_txt_start -= len;
 	dp->db_free -= space_needed;
 	++(dp->db_line_count);
@@ -2756,15 +2828,6 @@ ml_append_int(
     }
     else	    /* not enough space in data block */
     {
-/*
- * If there is not enough room we have to create a new data block and copy some
- * lines into it.
- * Then we have to insert an entry in the pointer block.
- * If this pointer block also is full, we go up another block, and so on, up
- * to the root if necessary.
- * The line counts in the pointer blocks have already been adjusted by
- * ml_find_line().
- */
 	long	    line_count_left, line_count_right;
 	int	    page_count_left, page_count_right;
 	bhdr_T	    *hp_left;
@@ -2783,6 +2846,14 @@ ml_append_int(
 	PTR_BL	    *pp_new;
 
 	/*
+	 * There is not enough room, we have to create a new data block and
+	 * copy some lines into it.
+	 * Then we have to insert an entry in the pointer block.
+	 * If this pointer block also is full, we go up another block, and so
+	 * on, up to the root if necessary.
+	 * The line counts in the pointer blocks have already been adjusted by
+	 * ml_find_line().
+	 *
 	 * We are going to allocate a new data block. Depending on the
 	 * situation it will be put to the left or right of the existing
 	 * block.  If possible we put the new line in the left block and move
@@ -2826,7 +2897,7 @@ ml_append_int(
 			/* correct line counts in pointer blocks */
 	    --(buf->b_ml.ml_locked_lineadd);
 	    --(buf->b_ml.ml_locked_high);
-	    return FAIL;
+	    goto theend;
 	}
 	if (db_idx < 0)		/* left block is new */
 	{
@@ -2951,13 +3022,13 @@ ml_append_int(
 	    ip = &(buf->b_ml.ml_stack[stack_idx]);
 	    pb_idx = ip->ip_index;
 	    if ((hp = mf_get(mfp, ip->ip_bnum, 1)) == NULL)
-		return FAIL;
+		goto theend;
 	    pp = (PTR_BL *)(hp->bh_data);   /* must be pointer block */
 	    if (pp->pb_id != PTR_ID)
 	    {
 		IEMSG(_("E317: pointer block id wrong 3"));
 		mf_put(mfp, hp, FALSE, FALSE);
-		return FAIL;
+		goto theend;
 	    }
 	    /*
 	     * TODO: If the pointer block is full and we are adding at the end
@@ -3014,7 +3085,7 @@ ml_append_int(
 		{
 		    hp_new = ml_new_ptr(mfp);
 		    if (hp_new == NULL)	    /* TODO: try to fix tree */
-			return FAIL;
+			goto theend;
 		    pp_new = (PTR_BL *)(hp_new->bh_data);
 
 		    if (hp->bh_bnum != 1)
@@ -3119,8 +3190,13 @@ ml_append_int(
     if (buf->b_write_to_channel)
 	channel_write_new_lines(buf);
 #endif
-
-    return OK;
+    ret = OK;
+
+theend:
+#ifdef FEAT_TEXT_PROP
+    vim_free(tofree);
+#endif
+    return ret;
 }
 
 /*
--- a/src/testdir/test_textprop.vim
+++ b/src/testdir/test_textprop.vim
@@ -257,6 +257,16 @@ func Test_prop_multiline()
   call assert_equal([expect_short], prop_list(4))
   bwipe!
 
+  " Test appending a line below the text prop start.
+  call Setup_three_line_prop()
+  let expect2 = {'col': 4, 'length': 4, 'type': 'comment', 'start': 1, 'end': 0, 'id': 0}
+  call assert_equal([expect2], prop_list(2))
+  call append(2, "new line")
+  call assert_equal([expect2], prop_list(2))
+  let expect3 = {'col': 1, 'length': 9, 'type': 'comment', 'start': 0, 'end': 0, 'id': 0}
+  call assert_equal([expect3], prop_list(3))
+  bwipe!
+
   call prop_type_delete('comment')
 endfunc
 
--- a/src/textprop.c
+++ b/src/textprop.c
@@ -17,14 +17,12 @@
  * Text properties have a type, which can be used to specify highlighting.
  *
  * TODO:
- * - mismatch in column 1 being the first column
- * - Let props overrule syntax HL.
- * - When deleting a line where a prop ended, adjust flag of previous line.
- * - When deleting a line where a prop started, adjust flag of next line.
- * - When inserting a line add props that continue from previous line.
- * - Adjust property column and length when text is inserted/deleted
- * - Add an arrray for global_proptypes, to quickly lookup a proptype by ID
- * - Add an arrray for b_proptypes, to quickly lookup a proptype by ID
+ * - Perhaps we only need TP_FLAG_CONT_NEXT ?
+ * - Adjust text property column and length when text is inserted/deleted
+ * - Add an arrray for global_proptypes, to quickly lookup a prop type by ID
+ * - Add an arrray for b_proptypes, to quickly lookup a prop type by ID
+ * - Checking the text length to detect text properties is slow.  Use a flag in
+ *   the index, like DB_MARKED?
  * - Also test line2byte() with many lines, so that ml_updatechunk() is taken
  *   into account.
  * - add mechanism to keep track of changed lines.
--- a/src/version.c
+++ b/src/version.c
@@ -800,6 +800,8 @@ static char *(features[]) =
 static int included_patches[] =
 {   /* Add new patch number below this line */
 /**/
+    655,
+/**/
     654,
 /**/
     653,