changeset 31319:243c35fad9cb v9.0.0993

patch 9.0.0993: display errors when adding or removing text property type Commit: https://github.com/vim/vim/commit/89469d157aea01513bde826b4519dd6b5fbceae4 Author: Bram Moolenaar <Bram@vim.org> Date: Fri Dec 2 20:46:26 2022 +0000 patch 9.0.0993: display errors when adding or removing text property type 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)
author Bram Moolenaar <Bram@vim.org>
date Fri, 02 Dec 2022 22:00:04 +0100
parents 23d42fb4e938
children 6bba507a9edb
files src/charset.c src/move.c src/proto/move.pro src/proto/textprop.pro 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 src/testdir/test_textprop.vim src/testdir/test_vim9_builtin.vim src/textprop.c src/version.c
diffstat 11 files changed, 126 insertions(+), 18 deletions(-) [+]
line wrap: on
line diff
--- a/src/charset.c
+++ b/src/charset.c
@@ -986,11 +986,15 @@ init_chartabsize_arg(
 		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)
+		{
+		    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
--- a/src/move.c
+++ b/src/move.c
@@ -646,6 +646,20 @@ changed_window_setting_win(win_T *wp)
 }
 
 /*
+ * 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
--- a/src/proto/move.pro
+++ b/src/proto/move.pro
@@ -7,6 +7,7 @@ void update_curswant(void);
 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);
--- a/src/proto/textprop.pro
+++ b/src/proto/textprop.pro
@@ -10,6 +10,7 @@ void sort_text_props(buf_T *buf, textpro
 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);
new file mode 100644
--- /dev/null
+++ b/src/testdir/dumps/Test_prop_delete_updates_1.dump
@@ -0,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| 
new file mode 100644
--- /dev/null
+++ b/src/testdir/dumps/Test_prop_delete_updates_2.dump
@@ -0,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| 
new file mode 100644
--- /dev/null
+++ b/src/testdir/dumps/Test_prop_delete_updates_3.dump
@@ -0,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| 
--- a/src/testdir/test_textprop.vim
+++ b/src/testdir/test_textprop.vim
@@ -1700,7 +1700,7 @@ func Test_prop_func_invalid_args()
   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_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,5 +3627,43 @@ def Test_textprop_in_quickfix_window()
   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
--- a/src/testdir/test_vim9_builtin.vim
+++ b/src/testdir/test_vim9_builtin.vim
@@ -3158,13 +3158,13 @@ enddef
 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:')
+  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'})", 'E474:')
+  assert_fails("prop_type_change('', {highlight: 'Search'})", 'E475:')
 enddef
 
 def Test_prop_type_delete()
--- a/src/textprop.c
+++ b/src/textprop.c
@@ -653,7 +653,7 @@ prop_count_above_below(buf_T *buf, linen
     for (i = 0; i < count; ++i)
     {
 	mch_memmove(&prop, props + i * sizeof(prop), sizeof(prop));
-	if (prop.tp_col == MAXCOL)
+	if (prop.tp_col == MAXCOL && text_prop_type_valid(buf, &prop))
 	{
 	    if ((prop.tp_flags & TP_FLAG_ALIGN_BELOW)
 		    || (next_right_goes_below
@@ -697,7 +697,8 @@ count_props(linenr_T lnum, int only_star
 	// 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))
+		|| (!last_line && prop.tp_col == MAXCOL)
+		|| !text_prop_type_valid(curbuf, &prop))
 	    --result;
     }
     return result;
@@ -801,20 +802,24 @@ sort_text_props(
  * Returns FAIL when not found.
  */
     int
-find_visible_prop(win_T *wp, int type_id, int id, textprop_T *prop,
-							  linenr_T *found_lnum)
+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;
+    // 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 (lnum = wp->w_topline; lnum < wp->w_botline; ++lnum)
+    for (linenr_T 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)
+	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,6 +991,15 @@ text_prop_type_by_id(buf_T *buf, int id)
 }
 
 /*
+ * 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,7 +1759,7 @@ prop_type_set(typval_T *argvars, int add
     name = tv_get_string(&argvars[0]);
     if (*name == NUL)
     {
-	emsg(_(e_invalid_argument));
+	semsg(_(e_invalid_argument_str), "\"\"");
 	return;
     }
 
@@ -1898,7 +1912,7 @@ f_prop_type_delete(typval_T *argvars, ty
     name = tv_get_string(&argvars[0]);
     if (*name == NUL)
     {
-	emsg(_(e_invalid_argument));
+	semsg(_(e_invalid_argument_str), "\"\"");
 	return;
     }
 
@@ -1926,6 +1940,10 @@ f_prop_type_delete(typval_T *argvars, ty
 	}
 	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,7 +1963,7 @@ f_prop_type_get(typval_T *argvars, typva
     name = tv_get_string(&argvars[0]);
     if (*name == NUL)
     {
-	emsg(_(e_invalid_argument));
+	semsg(_(e_invalid_argument_str), "\"\"");
 	return;
     }
     if (rettv_dict_alloc(rettv) == OK)
--- a/src/version.c
+++ b/src/version.c
@@ -696,6 +696,8 @@ static char *(features[]) =
 static int included_patches[] =
 {   /* Add new patch number below this line */
 /**/
+    993,
+/**/
     992,
 /**/
     991,