1
0
forked from aniani/vim

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.
This commit is contained in:
Bram Moolenaar
2018-12-28 23:22:40 +01:00
parent c1a9bc1a72
commit b56ac049ea
4 changed files with 117 additions and 31 deletions

View File

@@ -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;
#ifdef FEAT_TEXT_PROP
char_u *tofree = NULL;
#endif
int ret = FAIL;
/* lnum out of range */
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,8 +2779,9 @@ 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;
@@ -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
ret = OK;
return OK;
theend:
#ifdef FEAT_TEXT_PROP
vim_free(tofree);
#endif
return ret;
}
/*

View File

@@ -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

View File

@@ -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.

View File

@@ -799,6 +799,8 @@ static char *(features[]) =
static int included_patches[] =
{ /* Add new patch number below this line */
/**/
655,
/**/
654,
/**/