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)
diff --git a/src/charset.c b/src/charset.c
index fe1569c..7ae15b3 100644
--- a/src/charset.c
+++ b/src/charset.c
@@ -986,11 +986,15 @@
 		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
diff --git a/src/move.c b/src/move.c
index 4205445..14667f3 100644
--- a/src/move.c
+++ b/src/move.c
@@ -646,6 +646,20 @@
 }
 
 /*
+ * 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
diff --git a/src/proto/move.pro b/src/proto/move.pro
index 07a70d2..00b4d29 100644
--- a/src/proto/move.pro
+++ b/src/proto/move.pro
@@ -7,6 +7,7 @@
 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);
diff --git a/src/proto/textprop.pro b/src/proto/textprop.pro
index aa06e61..4b9a7a4 100644
--- a/src/proto/textprop.pro
+++ b/src/proto/textprop.pro
@@ -10,6 +10,7 @@
 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);
diff --git a/src/testdir/dumps/Test_prop_delete_updates_1.dump b/src/testdir/dumps/Test_prop_delete_updates_1.dump
new file mode 100644
index 0000000..400824f
--- /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| 
diff --git a/src/testdir/dumps/Test_prop_delete_updates_2.dump b/src/testdir/dumps/Test_prop_delete_updates_2.dump
new file mode 100644
index 0000000..e7074f5
--- /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| 
diff --git a/src/testdir/dumps/Test_prop_delete_updates_3.dump b/src/testdir/dumps/Test_prop_delete_updates_3.dump
new file mode 100644
index 0000000..651ed4b
--- /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| 
diff --git a/src/testdir/test_textprop.vim b/src/testdir/test_textprop.vim
index a847091..1d43703 100644
--- a/src/testdir/test_textprop.vim
+++ b/src/testdir/test_textprop.vim
@@ -1700,7 +1700,7 @@
   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 @@
   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
diff --git a/src/testdir/test_vim9_builtin.vim b/src/testdir/test_vim9_builtin.vim
index 005f89c..d85d064 100644
--- a/src/testdir/test_vim9_builtin.vim
+++ b/src/testdir/test_vim9_builtin.vim
@@ -3158,13 +3158,13 @@
 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()
diff --git a/src/textprop.c b/src/textprop.c
index 789ab8f..c1fc34e 100644
--- a/src/textprop.c
+++ b/src/textprop.c
@@ -653,7 +653,7 @@
     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 @@
 	// 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 @@
  * 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 @@
 }
 
 /*
+ * 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 @@
     name = tv_get_string(&argvars[0]);
     if (*name == NUL)
     {
-	emsg(_(e_invalid_argument));
+	semsg(_(e_invalid_argument_str), "\"\"");
 	return;
     }
 
@@ -1898,7 +1912,7 @@
     name = tv_get_string(&argvars[0]);
     if (*name == NUL)
     {
-	emsg(_(e_invalid_argument));
+	semsg(_(e_invalid_argument_str), "\"\"");
 	return;
     }
 
@@ -1926,6 +1940,10 @@
 	}
 	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 @@
     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)
diff --git a/src/version.c b/src/version.c
index e78066e..9fbed7c 100644
--- a/src/version.c
+++ b/src/version.c
@@ -696,6 +696,8 @@
 static int included_patches[] =
 {   /* Add new patch number below this line */
 /**/
+    993,
+/**/
     992,
 /**/
     991,