To: vim_dev@googlegroups.com Subject: Patch 9.0.0993 Fcc: outbox From: Bram Moolenaar Mime-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ------------ 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', 'E1174: String required for argument 1']) v9.CheckDefAndScriptFailure(['prop_type_add("a", "b")'], ['E1013: Argument 2: type mismatch, expected dict 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', 'E1174: String required for argument 1']) v9.CheckDefAndScriptFailure(['prop_type_change("a", "b")'], ['E1013: Argument 2: type mismatch, expected dict 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', 'E1174: String required for argument 1']) v9.CheckDefAndScriptFailure(['prop_type_add("a", "b")'], ['E1013: Argument 2: type mismatch, expected dict 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', 'E1174: String required for argument 1']) v9.CheckDefAndScriptFailure(['prop_type_change("a", "b")'], ['E1013: Argument 2: type mismatch, expected dict 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')\") + 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 -- Bram@Moolenaar.net -- http://www.Moolenaar.net \\\ /// \\\ \\\ sponsor Vim, vote for features -- http://www.Vim.org/sponsor/ /// \\\ help me help AIDS victims -- http://ICCF-Holland.org ///