forked from aniani/vim
patch 8.2.3356: adding many text properties requires a lot of function calls
Problem: Adding many text properties requires a lot of function calls. Solution: Add the prop_add_list() function. (Yegappan Lakshmanan, closes #8751)
This commit is contained in:
committed by
Bram Moolenaar
parent
434df7a401
commit
ccfb7c6758
@@ -2801,7 +2801,9 @@ prompt_getprompt({buf}) String get prompt text
|
|||||||
prompt_setcallback({buf}, {expr}) none set prompt callback function
|
prompt_setcallback({buf}, {expr}) none set prompt callback function
|
||||||
prompt_setinterrupt({buf}, {text}) none set prompt interrupt function
|
prompt_setinterrupt({buf}, {text}) none set prompt interrupt function
|
||||||
prompt_setprompt({buf}, {text}) none set prompt text
|
prompt_setprompt({buf}, {text}) none set prompt text
|
||||||
prop_add({lnum}, {col}, {props}) none add a text property
|
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}]])
|
prop_clear({lnum} [, {lnum-end} [, {props}]])
|
||||||
none remove all text properties
|
none remove all text properties
|
||||||
prop_find({props} [, {direction}])
|
prop_find({props} [, {direction}])
|
||||||
|
@@ -108,6 +108,9 @@ prop_type_list([{props}]) get list of property types
|
|||||||
Manipulating text properties:
|
Manipulating text properties:
|
||||||
|
|
||||||
prop_add({lnum}, {col}, {props}) add a text property
|
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}]])
|
prop_clear({lnum} [, {lnum-end} [, {bufnr}]])
|
||||||
remove all text properties
|
remove all text properties
|
||||||
prop_find({props} [, {direction}]) search for a text property
|
prop_find({props} [, {direction}]) search for a text property
|
||||||
@@ -158,6 +161,35 @@ prop_add({lnum}, {col}, {props})
|
|||||||
Can also be used as a |method|: >
|
Can also be used as a |method|: >
|
||||||
GetLnum()->prop_add(col, props)
|
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()*
|
prop_clear({lnum} [, {lnum-end} [, {props}]]) *prop_clear()*
|
||||||
Remove all text properties from line {lnum}.
|
Remove all text properties from line {lnum}.
|
||||||
|
@@ -1161,6 +1161,7 @@ Prompt Buffer: *promptbuffer-functions*
|
|||||||
|
|
||||||
Text Properties: *text-property-functions*
|
Text Properties: *text-property-functions*
|
||||||
prop_add() attach a property at a position
|
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_clear() remove all properties from a line or lines
|
||||||
prop_find() search for a property
|
prop_find() search for a property
|
||||||
prop_list() return a list of all properties in a line
|
prop_list() return a list of all properties in a line
|
||||||
|
@@ -708,6 +708,7 @@ static argcheck_T arg2_buffer_number[] = {arg_buffer, arg_number};
|
|||||||
static argcheck_T arg2_buffer_string[] = {arg_buffer, arg_string};
|
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_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_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_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_dict_string[] = {arg_dict_any, arg_string};
|
||||||
static argcheck_T arg2_float_or_nr[] = {arg_float_or_nr, arg_float_or_nr};
|
static argcheck_T arg2_float_or_nr[] = {arg_float_or_nr, arg_float_or_nr};
|
||||||
@@ -1740,6 +1741,8 @@ static funcentry_T global_functions[] =
|
|||||||
ret_void, JOB_FUNC(f_prompt_setprompt)},
|
ret_void, JOB_FUNC(f_prompt_setprompt)},
|
||||||
{"prop_add", 3, 3, FEARG_1, arg3_number_number_dict,
|
{"prop_add", 3, 3, FEARG_1, arg3_number_number_dict,
|
||||||
ret_void, PROP_FUNC(f_prop_add)},
|
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,
|
{"prop_clear", 1, 3, FEARG_1, arg3_number_number_dict,
|
||||||
ret_void, PROP_FUNC(f_prop_clear)},
|
ret_void, PROP_FUNC(f_prop_clear)},
|
||||||
{"prop_find", 1, 2, FEARG_1, arg2_dict_string,
|
{"prop_find", 1, 2, FEARG_1, arg2_dict_string,
|
||||||
|
@@ -1,6 +1,7 @@
|
|||||||
/* textprop.c */
|
/* textprop.c */
|
||||||
int find_prop_type_id(char_u *name, buf_T *buf);
|
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(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);
|
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 get_text_props(buf_T *buf, linenr_T lnum, char_u **props, int will_change);
|
||||||
int count_props(linenr_T lnum, int only_starting);
|
int count_props(linenr_T lnum, int only_starting);
|
||||||
|
@@ -339,6 +339,41 @@ func Test_prop_add()
|
|||||||
bwipe!
|
bwipe!
|
||||||
endfunc
|
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()
|
func Test_prop_remove()
|
||||||
new
|
new
|
||||||
call AddPropTypes()
|
call AddPropTypes()
|
||||||
|
@@ -2364,6 +2364,11 @@ def Test_prop_add()
|
|||||||
CheckDefAndScriptFailure2(['prop_add(1, 2, [])'], 'E1013: Argument 3: type mismatch, expected dict<any> but got list<unknown>', 'E1206: Dictionary required for argument 3')
|
CheckDefAndScriptFailure2(['prop_add(1, 2, [])'], 'E1013: Argument 3: type mismatch, expected dict<any> but got list<unknown>', 'E1206: Dictionary required for argument 3')
|
||||||
enddef
|
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()
|
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("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')
|
CheckDefAndScriptFailure2(['prop_clear(1, "b")'], 'E1013: Argument 2: type mismatch, expected number but got string', 'E1210: Number required for argument 2')
|
||||||
|
295
src/textprop.c
295
src/textprop.c
@@ -182,6 +182,200 @@ f_prop_add(typval_T *argvars, typval_T *rettv UNUSED)
|
|||||||
curbuf, &argvars[2]);
|
curbuf, &argvars[2]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 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)
|
||||||
|
{
|
||||||
|
colnr_T col; // start column
|
||||||
|
long length; // in bytes
|
||||||
|
|
||||||
|
// Fetch the line to get the ml_line_len field updated.
|
||||||
|
proplen = get_text_props(buf, lnum, &props, TRUE);
|
||||||
|
textlen = buf->b_ml.ml_line_len - proplen * sizeof(textprop_T);
|
||||||
|
|
||||||
|
if (lnum == start_lnum)
|
||||||
|
col = start_col;
|
||||||
|
else
|
||||||
|
col = 1;
|
||||||
|
if (col - 1 > (colnr_T)textlen)
|
||||||
|
{
|
||||||
|
semsg(_(e_invalid_col), (long)start_col);
|
||||||
|
return FAIL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (lnum == end_lnum)
|
||||||
|
length = end_col - col;
|
||||||
|
else
|
||||||
|
length = (int)textlen - col + 1;
|
||||||
|
if (length > (long)textlen)
|
||||||
|
length = (int)textlen; // can include the end-of-line
|
||||||
|
if (length < 0)
|
||||||
|
length = 0; // zero-width property
|
||||||
|
|
||||||
|
// 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);
|
||||||
|
|
||||||
|
// Find the index where to insert the new property.
|
||||||
|
// Since the text properties are not aligned properly when stored with
|
||||||
|
// the text, we need to copy them as bytes before using it as a struct.
|
||||||
|
for (i = 0; i < proplen; ++i)
|
||||||
|
{
|
||||||
|
mch_memmove(&tmp_prop, props + i * sizeof(textprop_T),
|
||||||
|
sizeof(textprop_T));
|
||||||
|
if (tmp_prop.tp_col >= col)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
newprops = newtext + textlen;
|
||||||
|
if (i > 0)
|
||||||
|
mch_memmove(newprops, props, sizeof(textprop_T) * i);
|
||||||
|
|
||||||
|
tmp_prop.tp_col = col;
|
||||||
|
tmp_prop.tp_len = length;
|
||||||
|
tmp_prop.tp_id = id;
|
||||||
|
tmp_prop.tp_type = type->pt_id;
|
||||||
|
tmp_prop.tp_flags = (lnum > start_lnum ? TP_FLAG_CONT_PREV : 0)
|
||||||
|
| (lnum < end_lnum ? TP_FLAG_CONT_NEXT : 0);
|
||||||
|
mch_memmove(newprops + i * sizeof(textprop_T), &tmp_prop,
|
||||||
|
sizeof(textprop_T));
|
||||||
|
|
||||||
|
if (i < proplen)
|
||||||
|
mch_memmove(newprops + (i + 1) * sizeof(textprop_T),
|
||||||
|
props + i * sizeof(textprop_T),
|
||||||
|
sizeof(textprop_T) * (proplen - i));
|
||||||
|
|
||||||
|
if (buf->b_ml.ml_flags & ML_LINE_DIRTY)
|
||||||
|
vim_free(buf->b_ml.ml_line_ptr);
|
||||||
|
buf->b_ml.ml_line_ptr = newtext;
|
||||||
|
buf->b_ml.ml_line_len += sizeof(textprop_T);
|
||||||
|
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().
|
* Shared between prop_add() and popup_create().
|
||||||
* "dict_arg" is the function argument of a dict containing "bufnr".
|
* "dict_arg" is the function argument of a dict containing "bufnr".
|
||||||
@@ -195,20 +389,11 @@ prop_add_common(
|
|||||||
buf_T *default_buf,
|
buf_T *default_buf,
|
||||||
typval_T *dict_arg)
|
typval_T *dict_arg)
|
||||||
{
|
{
|
||||||
linenr_T lnum;
|
|
||||||
linenr_T end_lnum;
|
linenr_T end_lnum;
|
||||||
colnr_T end_col;
|
colnr_T end_col;
|
||||||
char_u *type_name;
|
char_u *type_name;
|
||||||
proptype_T *type;
|
|
||||||
buf_T *buf = default_buf;
|
buf_T *buf = default_buf;
|
||||||
int id = 0;
|
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)
|
if (dict == NULL || dict_find(dict, (char_u *)"type", -1) == NULL)
|
||||||
{
|
{
|
||||||
@@ -260,99 +445,9 @@ prop_add_common(
|
|||||||
if (dict_arg != NULL && get_bufnr_from_arg(dict_arg, &buf) == FAIL)
|
if (dict_arg != NULL && get_bufnr_from_arg(dict_arg, &buf) == FAIL)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
type = lookup_prop_type(type_name, buf);
|
prop_add_one(buf, type_name, id, start_lnum, end_lnum, start_col, end_col);
|
||||||
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)
|
|
||||||
{
|
|
||||||
colnr_T col; // start column
|
|
||||||
long length; // in bytes
|
|
||||||
|
|
||||||
// Fetch the line to get the ml_line_len field updated.
|
|
||||||
proplen = get_text_props(buf, lnum, &props, TRUE);
|
|
||||||
textlen = buf->b_ml.ml_line_len - proplen * sizeof(textprop_T);
|
|
||||||
|
|
||||||
if (lnum == start_lnum)
|
|
||||||
col = start_col;
|
|
||||||
else
|
|
||||||
col = 1;
|
|
||||||
if (col - 1 > (colnr_T)textlen)
|
|
||||||
{
|
|
||||||
semsg(_(e_invalid_col), (long)start_col);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (lnum == end_lnum)
|
|
||||||
length = end_col - col;
|
|
||||||
else
|
|
||||||
length = (int)textlen - col + 1;
|
|
||||||
if (length > (long)textlen)
|
|
||||||
length = (int)textlen; // can include the end-of-line
|
|
||||||
if (length < 0)
|
|
||||||
length = 0; // zero-width property
|
|
||||||
|
|
||||||
// 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);
|
|
||||||
|
|
||||||
// Find the index where to insert the new property.
|
|
||||||
// Since the text properties are not aligned properly when stored with
|
|
||||||
// the text, we need to copy them as bytes before using it as a struct.
|
|
||||||
for (i = 0; i < proplen; ++i)
|
|
||||||
{
|
|
||||||
mch_memmove(&tmp_prop, props + i * sizeof(textprop_T),
|
|
||||||
sizeof(textprop_T));
|
|
||||||
if (tmp_prop.tp_col >= col)
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
newprops = newtext + textlen;
|
|
||||||
if (i > 0)
|
|
||||||
mch_memmove(newprops, props, sizeof(textprop_T) * i);
|
|
||||||
|
|
||||||
tmp_prop.tp_col = col;
|
|
||||||
tmp_prop.tp_len = length;
|
|
||||||
tmp_prop.tp_id = id;
|
|
||||||
tmp_prop.tp_type = type->pt_id;
|
|
||||||
tmp_prop.tp_flags = (lnum > start_lnum ? TP_FLAG_CONT_PREV : 0)
|
|
||||||
| (lnum < end_lnum ? TP_FLAG_CONT_NEXT : 0);
|
|
||||||
mch_memmove(newprops + i * sizeof(textprop_T), &tmp_prop,
|
|
||||||
sizeof(textprop_T));
|
|
||||||
|
|
||||||
if (i < proplen)
|
|
||||||
mch_memmove(newprops + (i + 1) * sizeof(textprop_T),
|
|
||||||
props + i * sizeof(textprop_T),
|
|
||||||
sizeof(textprop_T) * (proplen - i));
|
|
||||||
|
|
||||||
if (buf->b_ml.ml_flags & ML_LINE_DIRTY)
|
|
||||||
vim_free(buf->b_ml.ml_line_ptr);
|
|
||||||
buf->b_ml.ml_line_ptr = newtext;
|
|
||||||
buf->b_ml.ml_line_len += sizeof(textprop_T);
|
|
||||||
buf->b_ml.ml_flags |= ML_LINE_DIRTY;
|
|
||||||
}
|
|
||||||
|
|
||||||
buf->b_has_textprop = TRUE; // this is never reset
|
buf->b_has_textprop = TRUE; // this is never reset
|
||||||
changed_lines_buf(buf, start_lnum, end_lnum + 1, 0);
|
|
||||||
redraw_buf_later(buf, VALID);
|
redraw_buf_later(buf, VALID);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -755,6 +755,8 @@ static char *(features[]) =
|
|||||||
|
|
||||||
static int included_patches[] =
|
static int included_patches[] =
|
||||||
{ /* Add new patch number below this line */
|
{ /* Add new patch number below this line */
|
||||||
|
/**/
|
||||||
|
3356,
|
||||||
/**/
|
/**/
|
||||||
3355,
|
3355,
|
||||||
/**/
|
/**/
|
||||||
|
Reference in New Issue
Block a user