Skip to content

Commit b413d2e

Browse files
committed
patch 8.1.0636: line2byte() gives wrong values with text properties
Problem: line2byte() gives wrong values with text properties. (Bjorn Linse) Solution: Compute byte offsets differently when text properties were added. (closes #3718)
1 parent e38197d commit b413d2e

6 files changed

Lines changed: 66 additions & 26 deletions

File tree

src/memline.c

Lines changed: 41 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -3179,14 +3179,14 @@ ml_replace_len(linenr_T lnum, char_u *line_arg, colnr_T len_arg, int copy)
31793179
curbuf->b_ml.ml_flags &= ~ML_LINE_DIRTY;
31803180

31813181
#ifdef FEAT_TEXT_PROP
3182-
if (has_any_text_properties(curbuf))
3182+
if (curbuf->b_has_textprop)
31833183
// Need to fetch the old line to copy over any text properties.
31843184
ml_get_buf(curbuf, lnum, TRUE);
31853185
#endif
31863186
}
31873187

31883188
#ifdef FEAT_TEXT_PROP
3189-
if (has_any_text_properties(curbuf))
3189+
if (curbuf->b_has_textprop)
31903190
{
31913191
size_t oldtextlen = STRLEN(curbuf->b_ml.ml_line_ptr) + 1;
31923192

@@ -5131,6 +5131,7 @@ ml_updatechunk(
51315131
{
51325132
int count; /* number of entries in block */
51335133
int idx;
5134+
int end_idx;
51345135
int text_end;
51355136
int linecnt;
51365137

@@ -5154,23 +5155,39 @@ ml_updatechunk(
51545155
(long)(buf->b_ml.ml_locked_low) + 1;
51555156
idx = curline - buf->b_ml.ml_locked_low;
51565157
curline = buf->b_ml.ml_locked_high + 1;
5157-
if (idx == 0)/* first line in block, text at the end */
5158-
text_end = dp->db_txt_end;
5159-
else
5160-
text_end = ((dp->db_index[idx - 1]) & DB_INDEX_MASK);
5161-
/* Compute index of last line to use in this MEMLINE */
5158+
5159+
// compute index of last line to use in this MEMLINE
51625160
rest = count - idx;
51635161
if (linecnt + rest > MLCS_MINL)
51645162
{
5165-
idx += MLCS_MINL - linecnt - 1;
5163+
end_idx = idx + MLCS_MINL - linecnt - 1;
51665164
linecnt = MLCS_MINL;
51675165
}
51685166
else
51695167
{
5170-
idx = count - 1;
5168+
end_idx = count - 1;
51715169
linecnt += rest;
51725170
}
5173-
size += text_end - ((dp->db_index[idx]) & DB_INDEX_MASK);
5171+
#ifdef FEAT_TEXT_PROP
5172+
if (buf->b_has_textprop)
5173+
{
5174+
int i;
5175+
5176+
// We cannot use the text pointers to get the text length,
5177+
// the text prop info would also be counted. Go over the
5178+
// lines.
5179+
for (i = end_idx; i < idx; ++i)
5180+
size += STRLEN((char_u *)dp + (dp->db_index[i] & DB_INDEX_MASK)) + 1;
5181+
}
5182+
else
5183+
#endif
5184+
{
5185+
if (idx == 0)/* first line in block, text at the end */
5186+
text_end = dp->db_txt_end;
5187+
else
5188+
text_end = ((dp->db_index[idx - 1]) & DB_INDEX_MASK);
5189+
size += text_end - ((dp->db_index[end_idx]) & DB_INDEX_MASK);
5190+
}
51745191
}
51755192
buf->b_ml.ml_chunksize[curix].mlcs_numlines = linecnt;
51765193
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)
53605377
idx++;
53615378
}
53625379
}
5363-
len = text_end - ((dp->db_index[idx]) & DB_INDEX_MASK);
5380+
#ifdef FEAT_TEXT_PROP
5381+
if (buf->b_has_textprop)
5382+
{
5383+
int i;
5384+
5385+
// cannot use the db_index pointer, need to get the actual text
5386+
// lengths.
5387+
len = 0;
5388+
for (i = start_idx; i <= idx; ++i)
5389+
len += STRLEN((char_u *)dp + ((dp->db_index[idx]) & DB_INDEX_MASK)) + 1;
5390+
}
5391+
else
5392+
#endif
5393+
len = text_end - ((dp->db_index[idx]) & DB_INDEX_MASK);
53645394
size += len;
53655395
if (offset != 0 && size >= offset)
53665396
{

src/proto/textprop.pro

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
/* textprop.c */
22
void f_prop_add(typval_T *argvars, typval_T *rettv);
3-
int has_any_text_properties(buf_T *buf);
43
int get_text_props(buf_T *buf, linenr_T lnum, char_u **props, int will_change);
54
proptype_T *text_prop_type_by_id(buf_T *buf, int id);
65
void f_prop_clear(typval_T *argvars, typval_T *rettv);

src/structs.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2411,7 +2411,8 @@ struct file_buffer
24112411
dict_T *b_vars; /* internal variables, local to buffer */
24122412
#endif
24132413
#ifdef FEAT_TEXT_PROP
2414-
hashtab_T *b_proptypes; /* text property types local to buffer */
2414+
int b_has_textprop; // TRUE when text props were added
2415+
hashtab_T *b_proptypes; // text property types local to buffer
24152416
#endif
24162417

24172418
#if defined(FEAT_BEVAL) && defined(FEAT_EVAL)

src/testdir/test_textprop.vim

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -226,5 +226,17 @@ func Test_prop_multiline()
226226
call prop_type_delete('comment')
227227
endfunc
228228

229+
func Test_prop_byteoff()
230+
call prop_type_add('comment', {'highlight': 'Directory'})
231+
new
232+
call setline(1, ['line1', 'line2', ''])
233+
call assert_equal(13, line2byte(3))
234+
call prop_add(1, 1, {'end_col': 3, 'type': 'comment'})
235+
call assert_equal(13, line2byte(3))
236+
237+
bwipe!
238+
call prop_type_delete('comment')
239+
endfunc
240+
229241

230242
" TODO: screenshot test with highlighting

src/textprop.c

Lines changed: 9 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -17,12 +17,16 @@
1717
* Text properties have a type, which can be used to specify highlighting.
1818
*
1919
* TODO:
20+
* - mismatch in column 1 being the first column
21+
* - Let props overrule syntax HL.
2022
* - When deleting a line where a prop ended, adjust flag of previous line.
2123
* - When deleting a line where a prop started, adjust flag of next line.
2224
* - When inserting a line add props that continue from previous line.
2325
* - Adjust property column and length when text is inserted/deleted
2426
* - Add an arrray for global_proptypes, to quickly lookup a proptype by ID
2527
* - Add an arrray for b_proptypes, to quickly lookup a proptype by ID
28+
* - Also test line2byte() with many lines, so that ml_updatechunk() is taken
29+
* into account.
2630
* - add mechanism to keep track of changed lines.
2731
*/
2832

@@ -261,7 +265,7 @@ f_prop_add(typval_T *argvars, typval_T *rettv UNUSED)
261265
length = end_col - col + 1;
262266
else
263267
length = textlen - col + 1;
264-
if (length > textlen)
268+
if (length > (long)textlen)
265269
length = textlen; // can include the end-of-line
266270
if (length < 1)
267271
length = 1;
@@ -308,19 +312,10 @@ f_prop_add(typval_T *argvars, typval_T *rettv UNUSED)
308312
buf->b_ml.ml_flags |= ML_LINE_DIRTY;
309313
}
310314

315+
buf->b_has_textprop = TRUE; // this is never reset
311316
redraw_buf_later(buf, NOT_VALID);
312317
}
313318

314-
/*
315-
* Return TRUE if any text properties are defined globally or for buffer
316-
* "buf".
317-
*/
318-
int
319-
has_any_text_properties(buf_T *buf)
320-
{
321-
return buf->b_proptypes != NULL || global_proptypes != NULL;
322-
}
323-
324319
/*
325320
* Fetch the text properties for line "lnum" in buffer "buf".
326321
* 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)
334329
size_t textlen;
335330
size_t proplen;
336331

337-
// Be quick when no text property types are defined.
338-
if (!has_any_text_properties(buf))
332+
// Be quick when no text property types have been defined or the buffer,
333+
// unless we are adding one.
334+
if (!buf->b_has_textprop && !will_change)
339335
return 0;
340336

341337
// Fetch the line to get the ml_line_len field updated.

src/version.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -799,6 +799,8 @@ static char *(features[]) =
799799

800800
static int included_patches[] =
801801
{ /* Add new patch number below this line */
802+
/**/
803+
636,
802804
/**/
803805
635,
804806
/**/

0 commit comments

Comments
 (0)