]> granicus.if.org Git - vim/commitdiff
patch 8.1.0636: line2byte() gives wrong values with text properties v8.1.0636
authorBram Moolenaar <Bram@vim.org>
Tue, 25 Dec 2018 22:15:46 +0000 (23:15 +0100)
committerBram Moolenaar <Bram@vim.org>
Tue, 25 Dec 2018 22:15:46 +0000 (23:15 +0100)
Problem:    line2byte() gives wrong values with text properties. (Bjorn Linse)
Solution:   Compute byte offsets differently when text properties were added.
            (closes #3718)

src/memline.c
src/proto/textprop.pro
src/structs.h
src/testdir/test_textprop.vim
src/textprop.c
src/version.c

index eaa3b65abaaf6ee32565f1f86299768b7c461621..9f082660a5c7393d5291743a933393f45e4ccd0d 100644 (file)
@@ -3179,14 +3179,14 @@ ml_replace_len(linenr_T lnum, char_u *line_arg, colnr_T len_arg, int copy)
        curbuf->b_ml.ml_flags &= ~ML_LINE_DIRTY;
 
 #ifdef FEAT_TEXT_PROP
-       if (has_any_text_properties(curbuf))
+       if (curbuf->b_has_textprop)
            // Need to fetch the old line to copy over any text properties.
            ml_get_buf(curbuf, lnum, TRUE);
 #endif
     }
 
 #ifdef FEAT_TEXT_PROP
-    if (has_any_text_properties(curbuf))
+    if (curbuf->b_has_textprop)
     {
        size_t  oldtextlen = STRLEN(curbuf->b_ml.ml_line_ptr) + 1;
 
@@ -5131,6 +5131,7 @@ ml_updatechunk(
        {
            int     count;          /* number of entries in block */
            int     idx;
+           int     end_idx;
            int     text_end;
            int     linecnt;
 
@@ -5154,23 +5155,39 @@ ml_updatechunk(
                        (long)(buf->b_ml.ml_locked_low) + 1;
                idx = curline - buf->b_ml.ml_locked_low;
                curline = buf->b_ml.ml_locked_high + 1;
-               if (idx == 0)/* first line in block, text at the end */
-                   text_end = dp->db_txt_end;
-               else
-                   text_end = ((dp->db_index[idx - 1]) & DB_INDEX_MASK);
-               /* Compute index of last line to use in this MEMLINE */
+
+               // compute index of last line to use in this MEMLINE
                rest = count - idx;
                if (linecnt + rest > MLCS_MINL)
                {
-                   idx += MLCS_MINL - linecnt - 1;
+                   end_idx = idx + MLCS_MINL - linecnt - 1;
                    linecnt = MLCS_MINL;
                }
                else
                {
-                   idx = count - 1;
+                   end_idx = count - 1;
                    linecnt += rest;
                }
-               size += text_end - ((dp->db_index[idx]) & DB_INDEX_MASK);
+#ifdef FEAT_TEXT_PROP
+               if (buf->b_has_textprop)
+               {
+                   int i;
+
+                   // We cannot use the text pointers to get the text length,
+                   // the text prop info would also be counted.  Go over the
+                   // lines.
+                   for (i = end_idx; i < idx; ++i)
+                       size += STRLEN((char_u *)dp + (dp->db_index[i] & DB_INDEX_MASK)) + 1;
+               }
+               else
+#endif
+               {
+                   if (idx == 0)/* first line in block, text at the end */
+                       text_end = dp->db_txt_end;
+                   else
+                       text_end = ((dp->db_index[idx - 1]) & DB_INDEX_MASK);
+                   size += text_end - ((dp->db_index[end_idx]) & DB_INDEX_MASK);
+               }
            }
            buf->b_ml.ml_chunksize[curix].mlcs_numlines = linecnt;
            buf->b_ml.ml_chunksize[curix + 1].mlcs_numlines -= linecnt;
@@ -5360,7 +5377,20 @@ ml_find_line_or_offset(buf_T *buf, linenr_T lnum, long *offp)
                idx++;
            }
        }
-       len = text_end - ((dp->db_index[idx]) & DB_INDEX_MASK);
+#ifdef FEAT_TEXT_PROP
+       if (buf->b_has_textprop)
+       {
+           int i;
+
+           // cannot use the db_index pointer, need to get the actual text
+           // lengths.
+           len = 0;
+           for (i = start_idx; i <= idx; ++i)
+               len += STRLEN((char_u *)dp + ((dp->db_index[idx]) & DB_INDEX_MASK)) + 1;
+       }
+       else
+#endif
+           len = text_end - ((dp->db_index[idx]) & DB_INDEX_MASK);
        size += len;
        if (offset != 0 && size >= offset)
        {
index 62aef4f6b9f8b657ae62e58e69afb03138a316ce..52bb6bcc37beba401697e7ca0a6cbbc477158807 100644 (file)
@@ -1,6 +1,5 @@
 /* textprop.c */
 void f_prop_add(typval_T *argvars, typval_T *rettv);
-int has_any_text_properties(buf_T *buf);
 int get_text_props(buf_T *buf, linenr_T lnum, char_u **props, int will_change);
 proptype_T *text_prop_type_by_id(buf_T *buf, int id);
 void f_prop_clear(typval_T *argvars, typval_T *rettv);
index e4311eda41e71d5362d80261390d22a411196d38..2f2795a1281437e572a7a203c66220311e4583fd 100644 (file)
@@ -2411,7 +2411,8 @@ struct file_buffer
     dict_T     *b_vars;        /* internal variables, local to buffer */
 #endif
 #ifdef FEAT_TEXT_PROP
-    hashtab_T  *b_proptypes;   /* text property types local to buffer */
+    int                b_has_textprop; // TRUE when text props were added
+    hashtab_T  *b_proptypes;   // text property types local to buffer
 #endif
 
 #if defined(FEAT_BEVAL) && defined(FEAT_EVAL)
index 081d4ab5f132d2633a5da233d4646c008c8a6c94..3ec6ea81dba015e4639aee14ee3abbfff856acd7 100644 (file)
@@ -226,5 +226,17 @@ func Test_prop_multiline()
   call prop_type_delete('comment')
 endfunc
 
+func Test_prop_byteoff()
+  call prop_type_add('comment', {'highlight': 'Directory'})
+  new
+  call setline(1, ['line1', 'line2', ''])
+  call assert_equal(13, line2byte(3))
+  call prop_add(1, 1, {'end_col': 3, 'type': 'comment'})
+  call assert_equal(13, line2byte(3))
+
+  bwipe!
+  call prop_type_delete('comment')
+endfunc
+
 
 " TODO: screenshot test with highlighting
index f5b977a7a0fa71f1495e54cdf050c05e1e441fe1..ade99a7bf63b1748268d312df0f1881363c27282 100644 (file)
  * 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
+ * - Also test line2byte() with many lines, so that ml_updatechunk() is taken
+ *   into account.
  * - add mechanism to keep track of changed lines.
  */
 
@@ -261,7 +265,7 @@ f_prop_add(typval_T *argvars, typval_T *rettv UNUSED)
            length = end_col - col + 1;
        else
            length = textlen - col + 1;
-       if (length > textlen)
+       if (length > (long)textlen)
            length = textlen;  // can include the end-of-line
        if (length < 1)
            length = 1;
@@ -308,19 +312,10 @@ f_prop_add(typval_T *argvars, typval_T *rettv UNUSED)
        buf->b_ml.ml_flags |= ML_LINE_DIRTY;
     }
 
+    buf->b_has_textprop = TRUE;  // this is never reset
     redraw_buf_later(buf, NOT_VALID);
 }
 
-/*
- * Return TRUE if any text properties are defined globally or for buffer
- * "buf".
- */
-    int
-has_any_text_properties(buf_T *buf)
-{
-    return buf->b_proptypes != NULL || global_proptypes != NULL;
-}
-
 /*
  * Fetch the text properties for line "lnum" in buffer "buf".
  * Returns the number of text properties and, when non-zero, a pointer to the
@@ -334,8 +329,9 @@ get_text_props(buf_T *buf, linenr_T lnum, char_u **props, int will_change)
     size_t textlen;
     size_t proplen;
 
-    // Be quick when no text property types are defined.
-    if (!has_any_text_properties(buf))
+    // Be quick when no text property types have been defined or the buffer,
+    // unless we are adding one.
+    if (!buf->b_has_textprop && !will_change)
        return 0;
 
     // Fetch the line to get the ml_line_len field updated.
index 0712bcc33b973f51d177ac0fef291723cddd72ce..b2dbe38be5c42ec819b37ccb168ed08bc24355b7 100644 (file)
@@ -799,6 +799,8 @@ static char *(features[]) =
 
 static int included_patches[] =
 {   /* Add new patch number below this line */
+/**/
+    636,
 /**/
     635,
 /**/