summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBram Moolenaar <Bram@vim.org>2018-12-25 23:15:46 +0100
committerBram Moolenaar <Bram@vim.org>2018-12-25 23:15:46 +0100
commitb413d2e6a8cc7b1611a41bfa9462b986393ca5fe (patch)
treee232491163a792882917c0fb1888d6de9bf9cce8
parente38197d50f7068c4b68043792d283da98e526ec3 (diff)
patch 8.1.0636: line2byte() gives wrong values with text propertiesv8.1.0636
Problem: line2byte() gives wrong values with text properties. (Bjorn Linse) Solution: Compute byte offsets differently when text properties were added. (closes #3718)
-rw-r--r--src/memline.c52
-rw-r--r--src/proto/textprop.pro1
-rw-r--r--src/structs.h3
-rw-r--r--src/testdir/test_textprop.vim12
-rw-r--r--src/textprop.c22
-rw-r--r--src/version.c2
6 files changed, 66 insertions, 26 deletions
diff --git a/src/memline.c b/src/memline.c
index eaa3b65aba..9f082660a5 100644
--- a/src/memline.c
+++ b/src/memline.c
@@ -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)
{
diff --git a/src/proto/textprop.pro b/src/proto/textprop.pro
index 62aef4f6b9..52bb6bcc37 100644
--- a/src/proto/textprop.pro
+++ b/src/proto/textprop.pro
@@ -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);
diff --git a/src/structs.h b/src/structs.h
index e4311eda41..2f2795a128 100644
--- a/src/structs.h
+++ b/src/structs.h
@@ -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)
diff --git a/src/testdir/test_textprop.vim b/src/testdir/test_textprop.vim
index 081d4ab5f1..3ec6ea81db 100644
--- a/src/testdir/test_textprop.vim
+++ b/src/testdir/test_textprop.vim
@@ -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
diff --git a/src/textprop.c b/src/textprop.c
index f5b977a7a0..ade99a7bf6 100644
--- a/src/textprop.c
+++ b/src/textprop.c
@@ -17,12 +17,16 @@
* 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,20 +312,11 @@ 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
* first one in "props" (note that it is not aligned, therefore the char_u
@@ -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.
diff --git a/src/version.c b/src/version.c
index 0712bcc33b..b2dbe38be5 100644
--- 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 */
/**/
+ 636,
+/**/
635,
/**/
634,