Patch 9.0.0993
Problem:    Display errors when adding or removing text property type.
Solution:   Perform a full redraw.  Only use text properties for which the
            type is defined. (closes #11655)
Files:      src/textprop.c, src/proto/textprop.pro, src/charset.c,
            src/move.c, src/proto/move.pro, src/testdir/test_vim9_builtin.vim,
            src/testdir/test_textprop.vim,
            src/testdir/dumps/Test_prop_delete_updates_1.dump,
            src/testdir/dumps/Test_prop_delete_updates_2.dump,
            src/testdir/dumps/Test_prop_delete_updates_3.dump


*** ../vim-9.0.0992/src/textprop.c      2022-11-25 16:31:46.968606662 +0000
--- src/textprop.c      2022-12-02 20:22:01.233082242 +0000
***************
*** 653,659 ****
      for (i = 0; i < count; ++i)
      {
        mch_memmove(&prop, props + i * sizeof(prop), sizeof(prop));
!       if (prop.tp_col == MAXCOL)
        {
            if ((prop.tp_flags & TP_FLAG_ALIGN_BELOW)
                    || (next_right_goes_below
--- 653,659 ----
      for (i = 0; i < count; ++i)
      {
        mch_memmove(&prop, props + i * sizeof(prop), sizeof(prop));
!       if (prop.tp_col == MAXCOL && text_prop_type_valid(buf, &prop))
        {
            if ((prop.tp_flags & TP_FLAG_ALIGN_BELOW)
                    || (next_right_goes_below
***************
*** 697,703 ****
        // previous line, or when not in the last line and it is virtual text
        // after the line.
        if ((only_starting && (prop.tp_flags & TP_FLAG_CONT_PREV))
!               || (!last_line && prop.tp_col == MAXCOL))
            --result;
      }
      return result;
--- 697,704 ----
        // previous line, or when not in the last line and it is virtual text
        // after the line.
        if ((only_starting && (prop.tp_flags & TP_FLAG_CONT_PREV))
!               || (!last_line && prop.tp_col == MAXCOL)
!               || !text_prop_type_valid(curbuf, &prop))
            --result;
      }
      return result;
***************
*** 801,820 ****
   * Returns FAIL when not found.
   */
      int
! find_visible_prop(win_T *wp, int type_id, int id, textprop_T *prop,
!                                                         linenr_T *found_lnum)
! {
!     linenr_T          lnum;
!     char_u            *props;
!     int                       count;
!     int                       i;
  
      // w_botline may not have been updated yet.
      validate_botline_win(wp);
!     for (lnum = wp->w_topline; lnum < wp->w_botline; ++lnum)
      {
!       count = get_text_props(wp->w_buffer, lnum, &props, FALSE);
!       for (i = 0; i < count; ++i)
        {
            mch_memmove(prop, props + i * sizeof(textprop_T),
                                                           sizeof(textprop_T));
--- 802,825 ----
   * Returns FAIL when not found.
   */
      int
! find_visible_prop(
!       win_T       *wp,
!       int         type_id,
!       int         id,
!       textprop_T  *prop,
!       linenr_T    *found_lnum)
! {
!     // return when "type_id" no longer exists
!     if (text_prop_type_by_id(wp->w_buffer, type_id) == NULL)
!       return FAIL;
  
      // w_botline may not have been updated yet.
      validate_botline_win(wp);
!     for (linenr_T lnum = wp->w_topline; lnum < wp->w_botline; ++lnum)
      {
!       char_u  *props;
!       int     count = get_text_props(wp->w_buffer, lnum, &props, FALSE);
!       for (int i = 0; i < count; ++i)
        {
            mch_memmove(prop, props + i * sizeof(textprop_T),
                                                           sizeof(textprop_T));
***************
*** 986,991 ****
--- 991,1005 ----
  }
  
  /*
+  * Return TRUE if "prop" is a valid text property type.
+  */
+     int
+ text_prop_type_valid(buf_T *buf, textprop_T *prop)
+ {
+     return text_prop_type_by_id(buf, prop->tp_type) != NULL;
+ }
+ 
+ /*
   * prop_clear({lnum} [, {lnum_end} [, {bufnr}]])
   */
      void
***************
*** 1745,1751 ****
      name = tv_get_string(&argvars[0]);
      if (*name == NUL)
      {
!       emsg(_(e_invalid_argument));
        return;
      }
  
--- 1759,1765 ----
      name = tv_get_string(&argvars[0]);
      if (*name == NUL)
      {
!       semsg(_(e_invalid_argument_str), "\"\"");
        return;
      }
  
***************
*** 1898,1904 ****
      name = tv_get_string(&argvars[0]);
      if (*name == NUL)
      {
!       emsg(_(e_invalid_argument));
        return;
      }
  
--- 1912,1918 ----
      name = tv_get_string(&argvars[0]);
      if (*name == NUL)
      {
!       semsg(_(e_invalid_argument_str), "\"\"");
        return;
      }
  
***************
*** 1926,1931 ****
--- 1940,1949 ----
        }
        hash_remove(ht, hi, "prop type delete");
        vim_free(prop);
+ 
+       // currently visibile text properties will disappear
+       redraw_all_later(UPD_CLEAR);
+       changed_window_setting_buf(buf == NULL ? curbuf : buf);
      }
  }
  
***************
*** 1945,1951 ****
      name = tv_get_string(&argvars[0]);
      if (*name == NUL)
      {
!       emsg(_(e_invalid_argument));
        return;
      }
      if (rettv_dict_alloc(rettv) == OK)
--- 1963,1969 ----
      name = tv_get_string(&argvars[0]);
      if (*name == NUL)
      {
!       semsg(_(e_invalid_argument_str), "\"\"");
        return;
      }
      if (rettv_dict_alloc(rettv) == OK)
*** ../vim-9.0.0992/src/proto/textprop.pro      2022-09-14 22:13:06.069843985 
+0100
--- src/proto/textprop.pro      2022-12-02 20:08:24.045664198 +0000
***************
*** 10,15 ****
--- 10,16 ----
  int find_visible_prop(win_T *wp, int type_id, int id, textprop_T *prop, 
linenr_T *found_lnum);
  void add_text_props(linenr_T lnum, textprop_T *text_props, int 
text_prop_count);
  proptype_T *text_prop_type_by_id(buf_T *buf, int id);
+ int text_prop_type_valid(buf_T *buf, textprop_T *prop);
  void f_prop_clear(typval_T *argvars, typval_T *rettv);
  void f_prop_find(typval_T *argvars, typval_T *rettv);
  void f_prop_list(typval_T *argvars, typval_T *rettv);
*** ../vim-9.0.0992/src/charset.c       2022-11-02 13:30:37.530314524 +0000
--- src/charset.c       2022-12-02 20:12:22.093484473 +0000
***************
*** 986,996 ****
                mch_memmove(cts->cts_text_props + count, prop_start,
                                                   count * sizeof(textprop_T));
                for (i = 0; i < count; ++i)
!                   if (cts->cts_text_props[i + count].tp_id < 0)
                    {
                        cts->cts_has_prop_with_text = TRUE;
                        break;
                    }
                if (!cts->cts_has_prop_with_text)
                {
                    // won't use the text properties, free them
--- 986,1000 ----
                mch_memmove(cts->cts_text_props + count, prop_start,
                                                   count * sizeof(textprop_T));
                for (i = 0; i < count; ++i)
!               {
!                   textprop_T *tp = cts->cts_text_props + i + count;
!                   if (tp->tp_id < 0
!                                    && text_prop_type_valid(wp->w_buffer, tp))
                    {
                        cts->cts_has_prop_with_text = TRUE;
                        break;
                    }
+               }
                if (!cts->cts_has_prop_with_text)
                {
                    // won't use the text properties, free them
*** ../vim-9.0.0992/src/move.c  2022-11-19 12:24:39.758174328 +0000
--- src/move.c  2022-12-02 20:21:21.569107904 +0000
***************
*** 646,651 ****
--- 646,665 ----
  }
  
  /*
+  * Call changed_window_setting_win() for every window containing "buf".
+  */
+     void
+ changed_window_setting_buf(buf_T *buf)
+ {
+     tabpage_T *tp;
+     win_T     *wp;
+ 
+     FOR_ALL_TAB_WINDOWS(tp, wp)
+       if (wp->w_buffer == buf)
+           changed_window_setting_win(wp);
+ }
+ 
+ /*
   * Set wp->w_topline to a certain number.
   */
      void
*** ../vim-9.0.0992/src/proto/move.pro  2022-10-12 19:53:10.617726846 +0100
--- src/proto/move.pro  2022-12-02 20:21:49.321089936 +0000
***************
*** 7,12 ****
--- 7,13 ----
  void check_cursor_moved(win_T *wp);
  void changed_window_setting(void);
  void changed_window_setting_win(win_T *wp);
+ void changed_window_setting_buf(buf_T *buf);
  void set_topline(win_T *wp, linenr_T lnum);
  void changed_cline_bef_curs(void);
  void changed_cline_bef_curs_win(win_T *wp);
*** ../vim-9.0.0992/src/testdir/test_vim9_builtin.vim   2022-11-21 
19:56:59.403412744 +0000
--- src/testdir/test_vim9_builtin.vim   2022-12-02 19:38:15.346611169 +0000
***************
*** 3158,3170 ****
  def Test_prop_type_add()
    v9.CheckDefAndScriptFailure(['prop_type_add({"a": 10}, "b")'], ['E1013: 
Argument 1: type mismatch, expected string but got dict<number>', 'E1174: 
String required for argument 1'])
    v9.CheckDefAndScriptFailure(['prop_type_add("a", "b")'], ['E1013: Argument 
2: type mismatch, expected dict<any> but got string', 'E1206: Dictionary 
required for argument 2'])
!   assert_fails("prop_type_add('', {highlight: 'Search'})", 'E474:')
  enddef
  
  def Test_prop_type_change()
    v9.CheckDefAndScriptFailure(['prop_type_change({"a": 10}, "b")'], ['E1013: 
Argument 1: type mismatch, expected string but got dict<number>', 'E1174: 
String required for argument 1'])
    v9.CheckDefAndScriptFailure(['prop_type_change("a", "b")'], ['E1013: 
Argument 2: type mismatch, expected dict<any> but got string', 'E1206: 
Dictionary required for argument 2'])
!   assert_fails("prop_type_change('', {highlight: 'Search'})", 'E474:')
  enddef
  
  def Test_prop_type_delete()
--- 3158,3170 ----
  def Test_prop_type_add()
    v9.CheckDefAndScriptFailure(['prop_type_add({"a": 10}, "b")'], ['E1013: 
Argument 1: type mismatch, expected string but got dict<number>', 'E1174: 
String required for argument 1'])
    v9.CheckDefAndScriptFailure(['prop_type_add("a", "b")'], ['E1013: Argument 
2: type mismatch, expected dict<any> but got string', 'E1206: Dictionary 
required for argument 2'])
!   assert_fails("prop_type_add('', {highlight: 'Search'})", 'E475:')
  enddef
  
  def Test_prop_type_change()
    v9.CheckDefAndScriptFailure(['prop_type_change({"a": 10}, "b")'], ['E1013: 
Argument 1: type mismatch, expected string but got dict<number>', 'E1174: 
String required for argument 1'])
    v9.CheckDefAndScriptFailure(['prop_type_change("a", "b")'], ['E1013: 
Argument 2: type mismatch, expected dict<any> but got string', 'E1206: 
Dictionary required for argument 2'])
!   assert_fails("prop_type_change('', {highlight: 'Search'})", 'E475:')
  enddef
  
  def Test_prop_type_delete()
*** ../vim-9.0.0992/src/testdir/test_textprop.vim       2022-12-01 
18:37:34.490938220 +0000
--- src/testdir/test_textprop.vim       2022-12-02 20:43:27.448285615 +0000
***************
*** 1700,1706 ****
    call assert_fails("call prop_type_delete([])", 'E730:')
    call assert_fails("call prop_type_delete('xyz', [])", 'E715:')
    call assert_fails("call prop_type_get([])", 'E730:')
!   call assert_fails("call prop_type_get('', [])", 'E474:')
    call assert_fails("call prop_type_list([])", 'E715:')
    call assert_fails("call prop_type_add('yyy', 'not_a_dict')", 'E715:')
    call assert_fails("call prop_add(1, 5, {'type':'missing_type', 
'length':1})", 'E971:')
--- 1700,1706 ----
    call assert_fails("call prop_type_delete([])", 'E730:')
    call assert_fails("call prop_type_delete('xyz', [])", 'E715:')
    call assert_fails("call prop_type_get([])", 'E730:')
!   call assert_fails("call prop_type_get('', [])", 'E475:')
    call assert_fails("call prop_type_list([])", 'E715:')
    call assert_fails("call prop_type_add('yyy', 'not_a_dict')", 'E715:')
    call assert_fails("call prop_add(1, 5, {'type':'missing_type', 
'length':1})", 'E971:')
***************
*** 3627,3631 ****
--- 3627,3669 ----
    bwipe!
  enddef
  
+ func Test_text_prop_delete_updates()
+   CheckRunVimInTerminal
+ 
+   let lines =<< trim END
+       vim9script
+ 
+       setline(1, ['some text', 'more text', 'the end'])
+       prop_type_add('test', {highlight: 'DiffChange'})
+       prop_add(1, 0, {
+           type: 'test',
+           text: 'The quick brown fox jumps over the lazy dog',
+           text_align: 'below',
+           text_padding_left: 3,
+       })
+       prop_add(1, 0, {
+           type: 'test',
+           text: 'The quick brown fox jumps over the lazy dog',
+           text_align: 'below',
+           text_padding_left: 5,
+       })
+ 
+       normal! G
+   END
+   call writefile(lines, 'XtextPropDelete', 'D')
+   let buf = RunVimInTerminal('-S XtextPropDelete', #{rows: 10, cols: 60})
+   call VerifyScreenDump(buf, 'Test_prop_delete_updates_1', {})
+ 
+   " Check that after deleting the text prop type the text properties using
+   " this type no longer show and are not counted for cursor positioning.
+   call term_sendkeys(buf, ":call prop_type_delete('test')\<CR>")
+   call VerifyScreenDump(buf, 'Test_prop_delete_updates_2', {})
+ 
+   call term_sendkeys(buf, "ggj")
+   call VerifyScreenDump(buf, 'Test_prop_delete_updates_3', {})
+ 
+   call StopVimInTerminal(buf)
+ endfunc
+ 
  
  " vim: shiftwidth=2 sts=2 expandtab
*** ../vim-9.0.0992/src/testdir/dumps/Test_prop_delete_updates_1.dump   
2022-12-02 20:45:10.684102746 +0000
--- src/testdir/dumps/Test_prop_delete_updates_1.dump   2022-12-02 
20:43:38.308265337 +0000
***************
*** 0 ****
--- 1,10 ----
+ |s+0&#ffffff0|o|m|e| |t|e|x|t| @50
+ @3|T+0&#ffd7ff255|h|e| |q|u|i|c|k| |b|r|o|w|n| |f|o|x| |j|u|m|p|s| |o|v|e|r| 
|t|h|e| |l|a|z|y| |d|o|g| +0&#ffffff0@13
+ @5|T+0&#ffd7ff255|h|e| |q|u|i|c|k| |b|r|o|w|n| |f|o|x| |j|u|m|p|s| |o|v|e|r| 
|t|h|e| |l|a|z|y| |d|o|g| +0&#ffffff0@11
+ |m|o|r|e| |t|e|x|t| @50
+ >t|h|e| |e|n|d| @52
+ |~+0#4040ff13&| @58
+ |~| @58
+ |~| @58
+ |~| @58
+ | +0#0000000&@41|3|,|1| @10|A|l@1| 
*** ../vim-9.0.0992/src/testdir/dumps/Test_prop_delete_updates_2.dump   
2022-12-02 20:45:10.688102739 +0000
--- src/testdir/dumps/Test_prop_delete_updates_2.dump   2022-12-02 
20:43:39.456263207 +0000
***************
*** 0 ****
--- 1,10 ----
+ |s+0&#ffffff0|o|m|e| |t|e|x|t| @50
+ |m|o|r|e| |t|e|x|t| @50
+ >t|h|e| |e|n|d| @52
+ |~+0#4040ff13&| @58
+ |~| @58
+ |~| @58
+ |~| @58
+ |~| @58
+ |~| @58
+ | +0#0000000&@41|3|,|1| @10|A|l@1| 
*** ../vim-9.0.0992/src/testdir/dumps/Test_prop_delete_updates_3.dump   
2022-12-02 20:45:10.692102732 +0000
--- src/testdir/dumps/Test_prop_delete_updates_3.dump   2022-12-02 
20:43:40.600261086 +0000
***************
*** 0 ****
--- 1,10 ----
+ |s+0&#ffffff0|o|m|e| |t|e|x|t| @50
+ >m|o|r|e| |t|e|x|t| @50
+ |t|h|e| |e|n|d| @52
+ |~+0#4040ff13&| @58
+ |~| @58
+ |~| @58
+ |~| @58
+ |~| @58
+ |~| @58
+ | +0#0000000&@41|2|,|1| @10|A|l@1| 
*** ../vim-9.0.0992/src/version.c       2022-12-02 18:12:01.022476815 +0000
--- src/version.c       2022-12-02 19:35:59.130667883 +0000
***************
*** 697,698 ****
--- 697,700 ----
  {   /* Add new patch number below this line */
+ /**/
+     993,
  /**/

-- 
hundred-and-one symptoms of being an internet addict:
212. Your Internet group window has more icons than your Accessories window.

 /// Bram Moolenaar -- [email protected] -- http://www.Moolenaar.net   \\\
///                                                                      \\\
\\\        sponsor Vim, vote for features -- http://www.Vim.org/sponsor/ ///
 \\\            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/20221202204650.9131E1C5967%40moolenaar.net.

Raspunde prin e-mail lui