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)
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
redraw_win_later(wp, UPD_NOT_VALID);
}
+/*
+ * 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 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);
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);
--- /dev/null
+|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|
--- /dev/null
+|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|
--- /dev/null
+|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|
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:')
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
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()
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
// 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;
* 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));
return type;
}
+/*
+ * 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}]])
*/
name = tv_get_string(&argvars[0]);
if (*name == NUL)
{
- emsg(_(e_invalid_argument));
+ semsg(_(e_invalid_argument_str), "\"\"");
return;
}
name = tv_get_string(&argvars[0]);
if (*name == NUL)
{
- emsg(_(e_invalid_argument));
+ semsg(_(e_invalid_argument_str), "\"\"");
return;
}
}
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);
}
}
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)
static int included_patches[] =
{ /* Add new patch number below this line */
+/**/
+ 993,
/**/
992,
/**/