Patch 8.2.3356
Problem: Adding many text properties requires a lot of function calls.
Solution: Add the prop_add_list() function. (Yegappan Lakshmanan,
closes #8751)
Files: runtime/doc/eval.txt, runtime/doc/textprop.txt,
runtime/doc/usr_41.txt, src/evalfunc.c, src/proto/textprop.pro,
src/testdir/test_textprop.vim, src/testdir/test_vim9_builtin.vim,
src/textprop.c
*** ../vim-8.2.3355/runtime/doc/eval.txt 2021-08-10 10:23:22.280476685
+0200
--- runtime/doc/eval.txt 2021-08-16 21:33:59.131967420 +0200
***************
*** 2784,2790 ****
prompt_setcallback({buf}, {expr}) none set prompt callback function
prompt_setinterrupt({buf}, {text}) none set prompt interrupt function
prompt_setprompt({buf}, {text}) none set prompt text
! prop_add({lnum}, {col}, {props}) none add a text property
prop_clear({lnum} [, {lnum-end} [, {props}]])
none remove all text properties
prop_find({props} [, {direction}])
--- 2801,2809 ----
prompt_setcallback({buf}, {expr}) none set prompt callback function
prompt_setinterrupt({buf}, {text}) none set prompt interrupt function
prompt_setprompt({buf}, {text}) none set prompt text
! prop_add({lnum}, {col}, {props}) none add one text property
! prop_add_list({props}, [[{lnum}, {col}, {end-lnum}, {end-col}], ...])
! none add multiple text properties
prop_clear({lnum} [, {lnum-end} [, {props}]])
none remove all text properties
prop_find({props} [, {direction}])
*** ../vim-8.2.3355/runtime/doc/textprop.txt 2021-07-28 13:30:12.208929917
+0200
--- runtime/doc/textprop.txt 2021-08-16 21:34:57.767789811 +0200
***************
*** 108,113 ****
--- 108,116 ----
Manipulating text properties:
prop_add({lnum}, {col}, {props}) add a text property
+ prop_add_list({props}, [[{lnum}, {col}, {end-lnum}, {end-col}], ...])
+ add a text property at multiple
+ positions.
prop_clear({lnum} [, {lnum-end} [, {bufnr}]])
remove all text properties
prop_find({props} [, {direction}]) search for a text property
***************
*** 126,132 ****
length length of text in bytes, can only be used
for a property that does not continue in
another line; can be zero
! end_lnum line number for the end of text
end_col column just after the text; not used when
"length" is present; when {col} and "end_col"
are equal, and "end_lnum" is omitted or equal
--- 129,135 ----
length length of text in bytes, can only be used
for a property that does not continue in
another line; can be zero
! end_lnum line number for the end of text (inclusive)
end_col column just after the text; not used when
"length" is present; when {col} and "end_col"
are equal, and "end_lnum" is omitted or equal
***************
*** 158,163 ****
--- 161,195 ----
Can also be used as a |method|: >
GetLnum()->prop_add(col, props)
+ *prop_add_list()*
+ prop_add_list({props}, [[{lnum}, {col}, {end-lnum}, {end-col}], ...])
+ Similar to prop_add(), but attaches a text property at
+ multiple positions in a buffer.
+
+ {props} is a dictionary with these fields:
+ bufnr buffer to add the property to; when omitted
+ the current buffer is used
+ id user defined ID for the property; must be a
+ number; when omitted zero is used
+ type name of the text property type
+ All fields except "type" are optional.
+
+ The second argument is a List of Lists where each list
+ specifies the starting and ending position of the text. The
+ first two items {lnum} and {col} specify the starting position
+ of the text where the property will be attached and the last
+ two items {end-lnum} and {end-col} specify the position just
+ after the text.
+
+ Example:
+ call prop_add_list(#{type: 'MyProp', id: 2},
+ \ [[1, 4, 1, 7],
+ \ [1, 15, 1, 20],
+ \ [2, 30, 3, 30]]
+
+ Can also be used as a |method|: >
+ GetProp()->prop_add_list([[1, 1, 1, 2], [1, 4, 1, 8]])
+
prop_clear({lnum} [, {lnum-end} [, {props}]]) *prop_clear()*
Remove all text properties from line {lnum}.
*** ../vim-8.2.3355/runtime/doc/usr_41.txt 2021-08-08 14:41:48.719930705
+0200
--- runtime/doc/usr_41.txt 2021-08-16 21:28:45.284918529 +0200
***************
*** 1153,1158 ****
--- 1161,1167 ----
Text Properties: *text-property-functions*
prop_add() attach a property at a position
+ prop_add_list() attach a property at multiple positions
prop_clear() remove all properties from a line or lines
prop_find() search for a property
prop_list() return a list of all properties in a line
*** ../vim-8.2.3355/src/evalfunc.c 2021-08-13 17:48:19.178894940 +0200
--- src/evalfunc.c 2021-08-16 21:28:45.288918517 +0200
***************
*** 708,713 ****
--- 708,714 ----
static argcheck_T arg2_buffer_string[] = {arg_buffer, arg_string};
static argcheck_T arg2_chan_or_job_dict[] = {arg_chan_or_job, arg_dict_any};
static argcheck_T arg2_chan_or_job_string[] = {arg_chan_or_job, arg_string};
+ static argcheck_T arg2_dict_any_list_any[] = {arg_dict_any, arg_list_any};
static argcheck_T arg2_dict_any_string_or_nr[] = {arg_dict_any,
arg_string_or_nr};
static argcheck_T arg2_dict_string[] = {arg_dict_any, arg_string};
static argcheck_T arg2_float_or_nr[] = {arg_float_or_nr, arg_float_or_nr};
***************
*** 1740,1745 ****
--- 1741,1748 ----
ret_void, JOB_FUNC(f_prompt_setprompt)},
{"prop_add", 3, 3, FEARG_1, arg3_number_number_dict,
ret_void, PROP_FUNC(f_prop_add)},
+ {"prop_add_list", 2, 2, FEARG_1, arg2_dict_any_list_any,
+ ret_void, PROP_FUNC(f_prop_add_list)},
{"prop_clear", 1, 3, FEARG_1, arg3_number_number_dict,
ret_void, PROP_FUNC(f_prop_clear)},
{"prop_find", 1, 2, FEARG_1, arg2_dict_string,
*** ../vim-8.2.3355/src/proto/textprop.pro 2020-05-30 15:31:57.858700863
+0200
--- src/proto/textprop.pro 2021-08-16 21:28:45.288918517 +0200
***************
*** 1,6 ****
--- 1,7 ----
/* textprop.c */
int find_prop_type_id(char_u *name, buf_T *buf);
void f_prop_add(typval_T *argvars, typval_T *rettv);
+ void f_prop_add_list(typval_T *argvars, typval_T *rettv);
void prop_add_common(linenr_T start_lnum, colnr_T start_col, dict_T *dict,
buf_T *default_buf, typval_T *dict_arg);
int get_text_props(buf_T *buf, linenr_T lnum, char_u **props, int
will_change);
int count_props(linenr_T lnum, int only_starting);
*** ../vim-8.2.3355/src/testdir/test_textprop.vim 2021-08-15
15:04:37.188080291 +0200
--- src/testdir/test_textprop.vim 2021-08-16 21:28:45.288918517 +0200
***************
*** 339,344 ****
--- 339,379 ----
bwipe!
endfunc
+ " Test for the prop_add_list() function
+ func Test_prop_add_list()
+ new
+ call AddPropTypes()
+ call setline(1, ['one one one', 'two two two', 'six six six', 'ten ten
ten'])
+ call prop_add_list(#{type: 'one', id: 2},
+ \ [[1, 1, 1, 3], [2, 5, 2, 7], [3, 6, 4, 6]])
+ call assert_equal([#{id: 2, col: 1, type_bufnr: 0, end: 1, type: 'one',
+ \ length: 2, start: 1}], prop_list(1))
+ call assert_equal([#{id: 2, col: 5, type_bufnr: 0, end: 1, type: 'one',
+ \ length: 2, start: 1}], prop_list(2))
+ call assert_equal([#{id: 2, col: 6, type_bufnr: 0, end: 0, type: 'one',
+ \ length: 7, start: 1}], prop_list(3))
+ call assert_equal([#{id: 2, col: 1, type_bufnr: 0, end: 1, type: 'one',
+ \ length: 5, start: 0}], prop_list(4))
+ call assert_fails('call prop_add_list([1, 2], [[1, 1, 3]])', 'E1206:')
+ call assert_fails('call prop_add_list({}, {})', 'E1211:')
+ call assert_fails('call prop_add_list({}, [[1, 1, 3]])', 'E965:')
+ call assert_fails('call prop_add_list(#{type: "abc"}, [[1, 1, 1, 3]])',
'E971:')
+ call assert_fails('call prop_add_list(#{type: "one"}, [[]])', 'E474:')
+ call assert_fails('call prop_add_list(#{type: "one"}, [[1, 1, 1, 1], {}])',
'E714:')
+ call assert_fails('call prop_add_list(#{type: "one"}, [[1, 1, "a"]])',
'E474:')
+ call assert_fails('call prop_add_list(#{type: "one"}, [[2, 2]])', 'E474:')
+ call assert_fails('call prop_add_list(#{type: "one"}, [[1, 1, 2], [2,
2]])', 'E474:')
+ call assert_fails('call prop_add_list(#{type: "one"}, [[1, 1, 1, 2], [4, 1,
5, 2]])', 'E966:')
+ call assert_fails('call prop_add_list(#{type: "one"}, [[3, 1, 1, 2]])',
'E966:')
+ call assert_fails('call prop_add_list(#{type: "one"}, [[2, 2, 2, 2], [3,
20, 3, 22]])', 'E964:')
+ call assert_fails('eval #{type: "one"}->prop_add_list([[2, 2, 2, 2], [3,
20, 3, 22]])', 'E964:')
+ call assert_fails('call prop_add_list(test_null_dict(), [[2, 2, 2]])',
'E965:')
+ call assert_fails('call prop_add_list(#{type: "one"}, test_null_list())',
'E714:')
+ call assert_fails('call prop_add_list(#{type: "one"}, [test_null_list()])',
'E714:')
+ call DeletePropTypes()
+ bw!
+ endfunc
+
func Test_prop_remove()
new
call AddPropTypes()
*** ../vim-8.2.3355/src/testdir/test_vim9_builtin.vim 2021-08-09
22:22:23.164468820 +0200
--- src/testdir/test_vim9_builtin.vim 2021-08-16 21:28:45.288918517 +0200
***************
*** 2364,2369 ****
--- 2364,2374 ----
CheckDefAndScriptFailure2(['prop_add(1, 2, [])'], 'E1013: Argument 3: type
mismatch, expected dict<any> but got list<unknown>', 'E1206: Dictionary
required for argument 3')
enddef
+ def Test_prop_add_list()
+ CheckDefAndScriptFailure2(['prop_add_list([], [])'], 'E1013: Argument 1:
type mismatch, expected dict<any> but got list<unknown>', 'E1206: Dictionary
required for argument 1')
+ CheckDefAndScriptFailure2(['prop_add_list({}, {})'], 'E1013: Argument 2:
type mismatch, expected list<any> but got dict<unknown>', 'E1211: List required
for argument 2')
+ enddef
+
def Test_prop_clear()
CheckDefAndScriptFailure2(['prop_clear("a")'], 'E1013: Argument 1: type
mismatch, expected number but got string', 'E1210: Number required for argument
1')
CheckDefAndScriptFailure2(['prop_clear(1, "b")'], 'E1013: Argument 2: type
mismatch, expected number but got string', 'E1210: Number required for argument
2')
*** ../vim-8.2.3355/src/textprop.c 2021-08-01 21:30:08.893199555 +0200
--- src/textprop.c 2021-08-16 21:28:45.288918517 +0200
***************
*** 183,284 ****
}
/*
! * Shared between prop_add() and popup_create().
! * "dict_arg" is the function argument of a dict containing "bufnr".
! * it is NULL for popup_create().
*/
! void
! prop_add_common(
! linenr_T start_lnum,
! colnr_T start_col,
! dict_T *dict,
! buf_T *default_buf,
! typval_T *dict_arg)
{
- linenr_T lnum;
- linenr_T end_lnum;
- colnr_T end_col;
- char_u *type_name;
proptype_T *type;
! buf_T *buf = default_buf;
! int id = 0;
! char_u *newtext;
int proplen;
- size_t textlen;
char_u *props = NULL;
char_u *newprops;
! textprop_T tmp_prop;
int i;
!
! if (dict == NULL || dict_find(dict, (char_u *)"type", -1) == NULL)
! {
! emsg(_("E965: missing property type name"));
! return;
! }
! type_name = dict_get_string(dict, (char_u *)"type", FALSE);
!
! if (dict_find(dict, (char_u *)"end_lnum", -1) != NULL)
! {
! end_lnum = dict_get_number(dict, (char_u *)"end_lnum");
! if (end_lnum < start_lnum)
! {
! semsg(_(e_invargval), "end_lnum");
! return;
! }
! }
! else
! end_lnum = start_lnum;
!
! if (dict_find(dict, (char_u *)"length", -1) != NULL)
! {
! long length = dict_get_number(dict, (char_u *)"length");
!
! if (length < 0 || end_lnum > start_lnum)
! {
! semsg(_(e_invargval), "length");
! return;
! }
! end_col = start_col + length;
! }
! else if (dict_find(dict, (char_u *)"end_col", -1) != NULL)
! {
! end_col = dict_get_number(dict, (char_u *)"end_col");
! if (end_col <= 0)
! {
! semsg(_(e_invargval), "end_col");
! return;
! }
! }
! else if (start_lnum == end_lnum)
! end_col = start_col;
! else
! end_col = 1;
!
! if (dict_find(dict, (char_u *)"id", -1) != NULL)
! id = dict_get_number(dict, (char_u *)"id");
!
! if (dict_arg != NULL && get_bufnr_from_arg(dict_arg, &buf) == FAIL)
! return;
type = lookup_prop_type(type_name, buf);
if (type == NULL)
! return;
if (start_lnum < 1 || start_lnum > buf->b_ml.ml_line_count)
{
semsg(_(e_invalid_lnum), (long)start_lnum);
! return;
}
if (end_lnum < start_lnum || end_lnum > buf->b_ml.ml_line_count)
{
semsg(_(e_invalid_lnum), (long)end_lnum);
! return;
}
if (buf->b_ml.ml_mfp == NULL)
{
emsg(_("E275: Cannot add text property to unloaded buffer"));
! return;
}
for (lnum = start_lnum; lnum <= end_lnum; ++lnum)
--- 183,231 ----
}
/*
! * Attach a text property 'type_name' to the text starting
! * at [start_lnum, start_col] and ending at [end_lnum, end_col] in
! * the buffer 'buf' and assign identifier 'id'.
*/
! static int
! prop_add_one(
! buf_T *buf,
! char_u *type_name,
! int id,
! linenr_T start_lnum,
! linenr_T end_lnum,
! colnr_T start_col,
! colnr_T end_col)
{
proptype_T *type;
! linenr_T lnum;
int proplen;
char_u *props = NULL;
char_u *newprops;
! size_t textlen;
! char_u *newtext;
int i;
! textprop_T tmp_prop;
type = lookup_prop_type(type_name, buf);
if (type == NULL)
! return FAIL;
if (start_lnum < 1 || start_lnum > buf->b_ml.ml_line_count)
{
semsg(_(e_invalid_lnum), (long)start_lnum);
! return FAIL;
}
if (end_lnum < start_lnum || end_lnum > buf->b_ml.ml_line_count)
{
semsg(_(e_invalid_lnum), (long)end_lnum);
! return FAIL;
}
if (buf->b_ml.ml_mfp == NULL)
{
emsg(_("E275: Cannot add text property to unloaded buffer"));
! return FAIL;
}
for (lnum = start_lnum; lnum <= end_lnum; ++lnum)
***************
*** 297,303 ****
if (col - 1 > (colnr_T)textlen)
{
semsg(_(e_invalid_col), (long)start_col);
! return;
}
if (lnum == end_lnum)
--- 244,250 ----
if (col - 1 > (colnr_T)textlen)
{
semsg(_(e_invalid_col), (long)start_col);
! return FAIL;
}
if (lnum == end_lnum)
***************
*** 312,318 ****
// Allocate the new line with space for the new property.
newtext = alloc(buf->b_ml.ml_line_len + sizeof(textprop_T));
if (newtext == NULL)
! return;
// Copy the text, including terminating NUL.
mch_memmove(newtext, buf->b_ml.ml_line_ptr, textlen);
--- 259,265 ----
// Allocate the new line with space for the new property.
newtext = alloc(buf->b_ml.ml_line_len + sizeof(textprop_T));
if (newtext == NULL)
! return FAIL;
// Copy the text, including terminating NUL.
mch_memmove(newtext, buf->b_ml.ml_line_ptr, textlen);
***************
*** 351,358 ****
buf->b_ml.ml_flags |= ML_LINE_DIRTY;
}
- buf->b_has_textprop = TRUE; // this is never reset
changed_lines_buf(buf, start_lnum, end_lnum + 1, 0);
redraw_buf_later(buf, VALID);
}
--- 298,453 ----
buf->b_ml.ml_flags |= ML_LINE_DIRTY;
}
changed_lines_buf(buf, start_lnum, end_lnum + 1, 0);
+ return OK;
+ }
+
+ /*
+ * prop_add_list()
+ * First argument specifies the text property:
+ * {'type': <str>, 'id': <num>, 'bufnr': <num>}
+ * Second argument is a List where each item is a List with the following
+ * entries: [lnum, start_col, end_col]
+ */
+ void
+ f_prop_add_list(typval_T *argvars, typval_T *rettv UNUSED)
+ {
+ dict_T *dict;
+ char_u *type_name;
+ buf_T *buf = curbuf;
+ int id = 0;
+ listitem_T *li;
+ list_T *pos_list;
+ linenr_T start_lnum;
+ colnr_T start_col;
+ linenr_T end_lnum;
+ colnr_T end_col;
+ int error = FALSE;
+
+ if (check_for_dict_arg(argvars, 0) == FAIL
+ || check_for_list_arg(argvars, 1) == FAIL)
+ return;
+
+ if (argvars[1].vval.v_list == NULL)
+ {
+ emsg(_(e_listreq));
+ return;
+ }
+
+ dict = argvars[0].vval.v_dict;
+ if (dict == NULL || dict_find(dict, (char_u *)"type", -1) == NULL)
+ {
+ emsg(_("E965: missing property type name"));
+ return;
+ }
+ type_name = dict_get_string(dict, (char_u *)"type", FALSE);
+
+ if (dict_find(dict, (char_u *)"id", -1) != NULL)
+ id = dict_get_number(dict, (char_u *)"id");
+
+ if (get_bufnr_from_arg(&argvars[0], &buf) == FAIL)
+ return;
+
+ FOR_ALL_LIST_ITEMS(argvars[1].vval.v_list, li)
+ {
+ if (li->li_tv.v_type != VAR_LIST || li->li_tv.vval.v_list == NULL)
+ {
+ emsg(_(e_listreq));
+ return;
+ }
+
+ pos_list = li->li_tv.vval.v_list;
+ start_lnum = list_find_nr(pos_list, 0L, &error);
+ start_col = list_find_nr(pos_list, 1L, &error);
+ end_lnum = list_find_nr(pos_list, 2L, &error);
+ end_col = list_find_nr(pos_list, 3L, &error);
+ if (error || start_lnum <= 0 || start_col <= 0
+ || end_lnum <= 0 || end_col <= 0)
+ {
+ emsg(_(e_invarg));
+ return;
+ }
+ if (prop_add_one(buf, type_name, id, start_lnum, end_lnum,
+ start_col, end_col) == FAIL)
+ return;
+ }
+
+ buf->b_has_textprop = TRUE; // this is never reset
+ redraw_buf_later(buf, VALID);
+ }
+
+ /*
+ * Shared between prop_add() and popup_create().
+ * "dict_arg" is the function argument of a dict containing "bufnr".
+ * it is NULL for popup_create().
+ */
+ void
+ prop_add_common(
+ linenr_T start_lnum,
+ colnr_T start_col,
+ dict_T *dict,
+ buf_T *default_buf,
+ typval_T *dict_arg)
+ {
+ linenr_T end_lnum;
+ colnr_T end_col;
+ char_u *type_name;
+ buf_T *buf = default_buf;
+ int id = 0;
+
+ if (dict == NULL || dict_find(dict, (char_u *)"type", -1) == NULL)
+ {
+ emsg(_("E965: missing property type name"));
+ return;
+ }
+ type_name = dict_get_string(dict, (char_u *)"type", FALSE);
+
+ if (dict_find(dict, (char_u *)"end_lnum", -1) != NULL)
+ {
+ end_lnum = dict_get_number(dict, (char_u *)"end_lnum");
+ if (end_lnum < start_lnum)
+ {
+ semsg(_(e_invargval), "end_lnum");
+ return;
+ }
+ }
+ else
+ end_lnum = start_lnum;
+
+ if (dict_find(dict, (char_u *)"length", -1) != NULL)
+ {
+ long length = dict_get_number(dict, (char_u *)"length");
+
+ if (length < 0 || end_lnum > start_lnum)
+ {
+ semsg(_(e_invargval), "length");
+ return;
+ }
+ end_col = start_col + length;
+ }
+ else if (dict_find(dict, (char_u *)"end_col", -1) != NULL)
+ {
+ end_col = dict_get_number(dict, (char_u *)"end_col");
+ if (end_col <= 0)
+ {
+ semsg(_(e_invargval), "end_col");
+ return;
+ }
+ }
+ else if (start_lnum == end_lnum)
+ end_col = start_col;
+ else
+ end_col = 1;
+
+ if (dict_find(dict, (char_u *)"id", -1) != NULL)
+ id = dict_get_number(dict, (char_u *)"id");
+
+ if (dict_arg != NULL && get_bufnr_from_arg(dict_arg, &buf) == FAIL)
+ return;
+
+ prop_add_one(buf, type_name, id, start_lnum, end_lnum, start_col,
end_col);
+
+ buf->b_has_textprop = TRUE; // this is never reset
redraw_buf_later(buf, VALID);
}
*** ../vim-8.2.3355/src/version.c 2021-08-16 21:15:28.215345122 +0200
--- src/version.c 2021-08-16 21:36:23.647529755 +0200
***************
*** 757,758 ****
--- 757,760 ----
{ /* Add new patch number below this line */
+ /**/
+ 3356,
/**/
--
Q: Why does /dev/null accept only integers?
A: You can't sink a float.
/// 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/202108161939.17GJdhRp173589%40masaka.moolenaar.net.