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 -- [email protected] -- 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    ///

-- 
-- 
You received this message from the "vim_dev" maillist.
Do not top-post! Type your reply below the text you are replying to.
For more information, visit http://www.vim.org/maillist.php

--- 
You received this message because you are subscribed to the Google Groups 
"vim_dev" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
To view this discussion on the web visit 
https://groups.google.com/d/msgid/vim_dev/201905152045.x4FKjrgr006368%40masaka.moolenaar.net.
For more options, visit https://groups.google.com/d/optout.

Raspunde prin e-mail lui