diff src/textprop.c @ 15367:273649cad196 v8.1.0691

patch 8.1.0691: text properties are not adjusted for :substitute commit https://github.com/vim/vim/commit/4164bb204e97a2ff3d6c43cba779bdff9e853892 Author: Bram Moolenaar <Bram@vim.org> Date: Fri Jan 4 23:09:49 2019 +0100 patch 8.1.0691: text properties are not adjusted for :substitute Problem: Text properties are not adjusted for :substitute. Solution: Adjust text properties as well as possible.
author Bram Moolenaar <Bram@vim.org>
date Fri, 04 Jan 2019 23:15:04 +0100
parents 73b153ed5af8
children 44dd3ce11201
line wrap: on
line diff
--- a/src/textprop.c
+++ b/src/textprop.c
@@ -18,6 +18,8 @@
  *
  * TODO:
  * - Adjust text property column and length when text is inserted/deleted.
+ *   -> a :substitute with a multi-line match
+ *   -> search for changed_bytes() from ex_cmds.c
  * - Perhaps we only need TP_FLAG_CONT_NEXT and can drop TP_FLAG_CONT_PREV?
  * - 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
@@ -346,6 +348,34 @@ get_text_props(buf_T *buf, linenr_T lnum
     return (int)(proplen / sizeof(textprop_T));
 }
 
+/*
+ * Set the text properties for line "lnum" to "props" with length "len".
+ * If "len" is zero text properties are removed, "props" is not used.
+ * Any existing text properties are dropped.
+ * Only works for the current buffer.
+ */
+    static void
+set_text_props(linenr_T lnum, char_u *props, int len)
+{
+    char_u *text;
+    char_u *newtext;
+    size_t textlen;
+
+    text = ml_get(lnum);
+    textlen = STRLEN(text) + 1;
+    newtext = alloc(textlen + len);
+    if (newtext == NULL)
+	return;
+    mch_memmove(newtext, text, textlen);
+    if (len > 0)
+	mch_memmove(newtext + textlen, props, len);
+    if (curbuf->b_ml.ml_flags & ML_LINE_DIRTY)
+	vim_free(curbuf->b_ml.ml_line_ptr);
+    curbuf->b_ml.ml_line_ptr = newtext;
+    curbuf->b_ml.ml_line_len = textlen + len;
+    curbuf->b_ml.ml_flags |= ML_LINE_DIRTY;
+}
+
     static proptype_T *
 find_type_by_id(hashtab_T *ht, int id)
 {
@@ -976,4 +1006,69 @@ adjust_prop_columns(
     }
 }
 
+/*
+ * Adjust text properties for a line that was split in two.
+ * "lnum" is the newly inserted line.  The text properties are now on the line
+ * below it.  "kept" is the number of bytes kept in the first line, while
+ * "deleted" is the number of bytes deleted.
+ */
+    void
+adjust_props_for_split(linenr_T lnum, int kept, int deleted)
+{
+    char_u	*props;
+    int		count;
+    garray_T    prevprop;
+    garray_T    nextprop;
+    int		i;
+    int		skipped = kept + deleted;
+
+    if (!curbuf->b_has_textprop)
+	return;
+    count = get_text_props(curbuf, lnum + 1, &props, FALSE);
+    ga_init2(&prevprop, sizeof(textprop_T), 10);
+    ga_init2(&nextprop, sizeof(textprop_T), 10);
+
+    // Get the text properties, which are at "lnum + 1".
+    // Keep the relevant ones in the first line, reducing the length if needed.
+    // Copy the ones that include the split to the second line.
+    // Move the ones after the split to the second line.
+    for (i = 0; i < count; ++i)
+    {
+	textprop_T  prop;
+	textprop_T *p;
+
+	// copy the prop to an aligned structure
+	mch_memmove(&prop, props + i * sizeof(textprop_T), sizeof(textprop_T));
+
+	if (prop.tp_col < kept && ga_grow(&prevprop, 1) == OK)
+	{
+	    p = ((textprop_T *)prevprop.ga_data) + prevprop.ga_len;
+	    *p = prop;
+	    if (p->tp_col + p->tp_len >= kept)
+		p->tp_len = kept - p->tp_col;
+	    ++prevprop.ga_len;
+	}
+
+	if (prop.tp_col + prop.tp_len >= skipped && ga_grow(&nextprop, 1) == OK)
+	{
+	    p = ((textprop_T *)nextprop.ga_data) + nextprop.ga_len;
+	    *p = prop;
+	    if (p->tp_col > skipped)
+		p->tp_col -= skipped - 1;
+	    else
+	    {
+		p->tp_len -= skipped - p->tp_col;
+		p->tp_col = 1;
+	    }
+	    ++nextprop.ga_len;
+	}
+    }
+
+    set_text_props(lnum, prevprop.ga_data, prevprop.ga_len * sizeof(textprop_T));
+    ga_clear(&prevprop);
+
+    set_text_props(lnum + 1, nextprop.ga_data, nextprop.ga_len * sizeof(textprop_T));
+    ga_clear(&nextprop);
+}
+
 #endif // FEAT_TEXT_PROP