1
0
forked from aniani/vim

patch 8.1.1333: text properties don't always move after changes

Problem:    Text properties don't always move after changes.
Solution:   Update properties before reporting changes to listeners. Move text
            property when splitting a line.
This commit is contained in:
Bram Moolenaar
2019-05-15 22:45:37 +02:00
parent fe1ade0a78
commit 45dd07f10a
6 changed files with 92 additions and 21 deletions

View File

@@ -641,12 +641,12 @@ changed_bytes(linenr_T lnum, colnr_T col)
void void
inserted_bytes(linenr_T lnum, colnr_T col, int added UNUSED) inserted_bytes(linenr_T lnum, colnr_T col, int added UNUSED)
{ {
changed_bytes(lnum, col);
#ifdef FEAT_TEXT_PROP #ifdef FEAT_TEXT_PROP
if (curbuf->b_has_textprop && added != 0) if (curbuf->b_has_textprop && added != 0)
adjust_prop_columns(lnum, col, added); adjust_prop_columns(lnum, col, added);
#endif #endif
changed_bytes(lnum, col);
} }
/* /*
@@ -2133,6 +2133,12 @@ open_line(
) )
mark_adjust(curwin->w_cursor.lnum + 1, (linenr_T)MAXLNUM, 1L, 0L); mark_adjust(curwin->w_cursor.lnum + 1, (linenr_T)MAXLNUM, 1L, 0L);
did_append = TRUE; did_append = TRUE;
#ifdef FEAT_TEXT_PROP
if ((State & INSERT) && !(State & VREPLACE_FLAG))
// properties after the split move to the next line
adjust_props_for_split(curwin->w_cursor.lnum, curwin->w_cursor.lnum,
curwin->w_cursor.col + 1, 0);
#endif
} }
else else
{ {

View File

@@ -5728,7 +5728,7 @@ do_sub(exarg_T *eap)
last_line = lnum + 1; last_line = lnum + 1;
} }
#ifdef FEAT_TEXT_PROP #ifdef FEAT_TEXT_PROP
adjust_props_for_split(lnum, plen, 1); adjust_props_for_split(lnum + 1, lnum, plen, 1);
#endif #endif
// all line numbers increase // all line numbers increase
++sub_firstlnum; ++sub_firstlnum;

View File

@@ -14,5 +14,5 @@ void f_prop_type_list(typval_T *argvars, typval_T *rettv);
void clear_global_prop_types(void); void clear_global_prop_types(void);
void clear_buf_prop_types(buf_T *buf); void clear_buf_prop_types(buf_T *buf);
void adjust_prop_columns(linenr_T lnum, colnr_T col, int bytes_added); void adjust_prop_columns(linenr_T lnum, colnr_T col, int bytes_added);
void adjust_props_for_split(linenr_T lnum, int kept, int deleted); void adjust_props_for_split(linenr_T lnum_props, linenr_T lnum_top, int kept, int deleted);
/* vim: set ft=c : */ /* vim: set ft=c : */

View File

@@ -151,6 +151,7 @@ endfunc
func SetupOneLine() func SetupOneLine()
call setline(1, 'xonex xtwoxx') call setline(1, 'xonex xtwoxx')
normal gg0
call AddPropTypes() call AddPropTypes()
call prop_add(1, 2, {'length': 3, 'id': 11, 'type': 'one'}) call prop_add(1, 2, {'length': 3, 'id': 11, 'type': 'one'})
call prop_add(1, 8, {'length': 3, 'id': 12, 'type': 'two'}) call prop_add(1, 8, {'length': 3, 'id': 12, 'type': 'two'})
@@ -272,6 +273,66 @@ func Test_prop_replace()
set bs& set bs&
endfunc endfunc
func Test_prop_open_line()
new
" open new line, props stay in top line
let expected = SetupOneLine() " 'xonex xtwoxx'
exe "normal o\<Esc>"
call assert_equal('xonex xtwoxx', getline(1))
call assert_equal('', getline(2))
call assert_equal(expected, prop_list(1))
call DeletePropTypes()
" move all props to next line
let expected = SetupOneLine() " 'xonex xtwoxx'
exe "normal 0i\<CR>\<Esc>"
call assert_equal('', getline(1))
call assert_equal('xonex xtwoxx', getline(2))
call assert_equal(expected, prop_list(2))
call DeletePropTypes()
" split just before prop, move all props to next line
let expected = SetupOneLine() " 'xonex xtwoxx'
exe "normal 0li\<CR>\<Esc>"
call assert_equal('x', getline(1))
call assert_equal('onex xtwoxx', getline(2))
let expected[0].col -= 1
let expected[1].col -= 1
call assert_equal(expected, prop_list(2))
call DeletePropTypes()
" split inside prop, split first prop
let expected = SetupOneLine() " 'xonex xtwoxx'
exe "normal 0lli\<CR>\<Esc>"
call assert_equal('xo', getline(1))
call assert_equal('nex xtwoxx', getline(2))
let exp_first = [deepcopy(expected[0])]
let exp_first[0].length = 1
call assert_equal(exp_first, prop_list(1))
let expected[0].col = 1
let expected[0].length = 2
let expected[1].col -= 2
call assert_equal(expected, prop_list(2))
call DeletePropTypes()
" split just after first prop, empty prop and second prop move to next line
let expected = SetupOneLine() " 'xonex xtwoxx'
exe "normal 0fea\<CR>\<Esc>"
call assert_equal('xone', getline(1))
call assert_equal('x xtwoxx', getline(2))
let exp_first = expected[0:0]
call assert_equal(exp_first, prop_list(1))
let expected[0].col = 1
let expected[0].length = 0
let expected[1].col -= 4
call assert_equal(expected, prop_list(2))
call DeletePropTypes()
bwipe!
set bs&
endfunc
func Test_prop_clear() func Test_prop_clear()
new new
call AddPropTypes() call AddPropTypes()

View File

@@ -8,18 +8,15 @@
*/ */
/* /*
* Text properties implementation. * Text properties implementation. See ":help text-properties".
*
* Text properties are attached to the text. They move with the text when
* text is inserted/deleted.
*
* Text properties have a user specified ID number, which can be unique.
* Text properties have a type, which can be used to specify highlighting.
* *
* TODO: * TODO:
* - When using 'cursorline' attributes should be merged. (#3912) * - When using 'cursorline' attributes should be merged. (#3912)
* - Adjust text property column and length when text is inserted/deleted. * - Adjust text property column and length when text is inserted/deleted.
* -> splitting a line can create a zero-length property. Don't highlight it
* and extend it when inserting text.
* -> a :substitute with a multi-line match * -> a :substitute with a multi-line match
* -> join two lines, also with BS in Insert mode
* -> search for changed_bytes() from misc1.c * -> search for changed_bytes() from misc1.c
* - Perhaps we only need TP_FLAG_CONT_NEXT and can drop TP_FLAG_CONT_PREV? * - 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 global_proptypes, to quickly lookup a prop type by ID
@@ -28,8 +25,6 @@
* the index, like DB_MARKED? * the index, like DB_MARKED?
* - Also test line2byte() with many lines, so that ml_updatechunk() is taken * - Also test line2byte() with many lines, so that ml_updatechunk() is taken
* into account. * into account.
* - Add mechanism to keep track of changed lines, so that plugin can update
* text properties in these.
* - Perhaps have a window-local option to disable highlighting from text * - Perhaps have a window-local option to disable highlighting from text
* properties? * properties?
*/ */
@@ -1033,12 +1028,17 @@ adjust_prop_columns(
/* /*
* Adjust text properties for a line that was split in two. * 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 * "lnum_props" is the line that has the properties from before the split.
* below it. "kept" is the number of bytes kept in the first line, while * "lnum_top" is the top line.
* "kept" is the number of bytes kept in the first line, while
* "deleted" is the number of bytes deleted. * "deleted" is the number of bytes deleted.
*/ */
void void
adjust_props_for_split(linenr_T lnum, int kept, int deleted) adjust_props_for_split(
linenr_T lnum_props,
linenr_T lnum_top,
int kept,
int deleted)
{ {
char_u *props; char_u *props;
int count; int count;
@@ -1049,11 +1049,12 @@ adjust_props_for_split(linenr_T lnum, int kept, int deleted)
if (!curbuf->b_has_textprop) if (!curbuf->b_has_textprop)
return; return;
count = get_text_props(curbuf, lnum + 1, &props, FALSE);
// Get the text properties from "lnum_props".
count = get_text_props(curbuf, lnum_props, &props, FALSE);
ga_init2(&prevprop, sizeof(textprop_T), 10); ga_init2(&prevprop, sizeof(textprop_T), 10);
ga_init2(&nextprop, 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. // Keep the relevant ones in the first line, reducing the length if needed.
// Copy the ones that include the split to the second line. // Copy the ones that include the split to the second line.
// Move the ones after the split to the second line. // Move the ones after the split to the second line.
@@ -1089,10 +1090,11 @@ adjust_props_for_split(linenr_T lnum, int kept, int deleted)
} }
} }
set_text_props(lnum, prevprop.ga_data, prevprop.ga_len * sizeof(textprop_T)); set_text_props(lnum_top, prevprop.ga_data,
prevprop.ga_len * sizeof(textprop_T));
ga_clear(&prevprop); ga_clear(&prevprop);
set_text_props(lnum_top + 1, nextprop.ga_data,
set_text_props(lnum + 1, nextprop.ga_data, nextprop.ga_len * sizeof(textprop_T)); nextprop.ga_len * sizeof(textprop_T));
ga_clear(&nextprop); ga_clear(&nextprop);
} }

View File

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