Patch 8.1.1333

15 views
Skip to first unread message

Bram Moolenaar

unread,
May 15, 2019, 4:46:02 PM5/15/19
to vim...@googlegroups.com

Patch 8.1.1333
Problem: Text properties don't always move after changes.
Solution: Update properties before reporting changes to listeners. Move text
property when splitting a line.
Files: src/change.c, src/ex_cmds.c, src/textprop.c,
src/proto/textprop.pro, src/testdir/test_textprop.vim


*** ../vim-8.1.1332/src/change.c 2019-05-14 21:20:32.597441034 +0200
--- src/change.c 2019-05-15 22:14:42.293974215 +0200
***************
*** 641,652 ****
void
inserted_bytes(linenr_T lnum, colnr_T col, int added UNUSED)
{
- changed_bytes(lnum, col);
-
#ifdef FEAT_TEXT_PROP
if (curbuf->b_has_textprop && added != 0)
adjust_prop_columns(lnum, col, added);
#endif
}

/*
--- 641,652 ----
void
inserted_bytes(linenr_T lnum, colnr_T col, int added UNUSED)
{
#ifdef FEAT_TEXT_PROP
if (curbuf->b_has_textprop && added != 0)
adjust_prop_columns(lnum, col, added);
#endif
+
+ changed_bytes(lnum, col);
}

/*
***************
*** 2133,2138 ****
--- 2133,2144 ----
)
mark_adjust(curwin->w_cursor.lnum + 1, (linenr_T)MAXLNUM, 1L, 0L);
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
{
*** ../vim-8.1.1332/src/ex_cmds.c 2019-05-09 15:12:45.168723969 +0200
--- src/ex_cmds.c 2019-05-15 22:02:51.794417449 +0200
***************
*** 5728,5734 ****
last_line = lnum + 1;
}
#ifdef FEAT_TEXT_PROP
! adjust_props_for_split(lnum, plen, 1);
#endif
// all line numbers increase
++sub_firstlnum;
--- 5728,5734 ----
last_line = lnum + 1;
}
#ifdef FEAT_TEXT_PROP
! adjust_props_for_split(lnum + 1, lnum, plen, 1);
#endif
// all line numbers increase
++sub_firstlnum;
*** ../vim-8.1.1332/src/textprop.c 2019-05-05 16:33:44.490168111 +0200
--- src/textprop.c 2019-05-15 22:42:36.048949732 +0200
***************
*** 8,25 ****
*/

/*
! * Text properties implementation.
! *
! * 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:
* - When using 'cursorline' attributes should be merged. (#3912)
* - Adjust text property column and length when text is inserted/deleted.
* -> a :substitute with a multi-line match
* -> search for changed_bytes() from misc1.c
* - 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
--- 8,22 ----
*/

/*
! * Text properties implementation. See ":help text-properties".
*
* TODO:
* - When using 'cursorline' attributes should be merged. (#3912)
* - 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
+ * -> join two lines, also with BS in Insert mode
* -> search for changed_bytes() from misc1.c
* - 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
***************
*** 28,35 ****
* 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, so that plugin can update
- * text properties in these.
* - Perhaps have a window-local option to disable highlighting from text
* properties?
*/
--- 25,30 ----
***************
*** 1033,1044 ****

/*
* 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
! * below it. "kept" is the number of bytes kept in the first line, while
* "deleted" is the number of bytes deleted.
*/
void
! adjust_props_for_split(linenr_T lnum, int kept, int deleted)
{
char_u *props;
int count;
--- 1028,1044 ----

/*
* Adjust text properties for a line that was split in two.
! * "lnum_props" is the line that has the properties from before the split.
! * "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.
*/
void
! adjust_props_for_split(
! linenr_T lnum_props,
! linenr_T lnum_top,
! int kept,
! int deleted)
{
char_u *props;
int count;
***************
*** 1049,1059 ****

if (!curbuf->b_has_textprop)
return;
! count = get_text_props(curbuf, lnum + 1, &props, FALSE);
ga_init2(&prevprop, 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.
// Copy the ones that include the split to the second line.
// Move the ones after the split to the second line.
--- 1049,1060 ----

if (!curbuf->b_has_textprop)
return;
!
! // 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(&nextprop, sizeof(textprop_T), 10);

// Keep the relevant ones in the first line, reducing the length if needed.
// Copy the ones that include the split to the second line.
// Move the ones after the split to the second line.
***************
*** 1089,1098 ****
}
}

! set_text_props(lnum, prevprop.ga_data, prevprop.ga_len * sizeof(textprop_T));
ga_clear(&prevprop);
!
! set_text_props(lnum + 1, nextprop.ga_data, nextprop.ga_len * sizeof(textprop_T));
ga_clear(&nextprop);
}

--- 1090,1100 ----
}
}

! set_text_props(lnum_top, prevprop.ga_data,
! prevprop.ga_len * sizeof(textprop_T));
ga_clear(&prevprop);
! set_text_props(lnum_top + 1, nextprop.ga_data,
! nextprop.ga_len * sizeof(textprop_T));
ga_clear(&nextprop);
}

*** ../vim-8.1.1332/src/proto/textprop.pro 2019-01-04 23:09:45.249360567 +0100
--- src/proto/textprop.pro 2019-05-15 22:05:41.925276920 +0200
***************
*** 14,18 ****
void clear_global_prop_types(void);
void clear_buf_prop_types(buf_T *buf);
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);
/* vim: set ft=c : */
--- 14,18 ----
void clear_global_prop_types(void);
void clear_buf_prop_types(buf_T *buf);
void adjust_prop_columns(linenr_T lnum, colnr_T col, int bytes_added);
! void adjust_props_for_split(linenr_T lnum_props, linenr_T lnum_top, int kept, int deleted);
/* vim: set ft=c : */
*** ../vim-8.1.1332/src/testdir/test_textprop.vim 2019-05-05 15:47:37.825923529 +0200
--- src/testdir/test_textprop.vim 2019-05-15 22:41:42.505209936 +0200
***************
*** 151,156 ****
--- 151,157 ----

func SetupOneLine()
call setline(1, 'xonex xtwoxx')
+ normal gg0
call AddPropTypes()
call prop_add(1, 2, {'length': 3, 'id': 11, 'type': 'one'})
call prop_add(1, 8, {'length': 3, 'id': 12, 'type': 'two'})
***************
*** 271,276 ****
--- 272,337 ----
bwipe!
set bs&
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()
new
*** ../vim-8.1.1332/src/version.c 2019-05-14 21:20:32.597441034 +0200
--- src/version.c 2019-05-15 22:44:49.468290481 +0200
***************
*** 769,770 ****
--- 769,772 ----
{ /* Add new patch number below this line */
+ /**/
+ 1333,
/**/

--
BLACK KNIGHT: I'm invincible!
ARTHUR: You're a looney.
"Monty Python and the Holy Grail" PYTHON (MONTY) PICTURES LTD

/// Bram Moolenaar -- Br...@Moolenaar.net -- http://www.Moolenaar.net \\\
/// sponsor Vim, vote for features -- http://www.Vim.org/sponsor/ \\\
\\\ an exciting new programming language -- http://www.Zimbu.org ///
\\\ help me help AIDS victims -- http://ICCF-Holland.org ///
Reply all
Reply to author
Forward
0 new messages