0
0
mirror of https://github.com/vim/vim.git synced 2025-07-26 11:04:33 -04:00

patch 8.1.1682: placing a larger number of signs is slow

Problem:    Placing a larger number of signs is slow.
Solution:   Add functions for dealing with a list of signs. (Yegappan
            Lakshmanan, closes #4636)
This commit is contained in:
Bram Moolenaar 2019-07-13 21:21:40 +02:00
parent 0fb286e82d
commit 809ce4d317
7 changed files with 619 additions and 142 deletions

View File

@ -1,4 +1,4 @@
*eval.txt* For Vim version 8.1. Last change: 2019 Jul 04
*eval.txt* For Vim version 8.1. Last change: 2019 Jul 13
VIM REFERENCE MANUAL by Bram Moolenaar
@ -2660,6 +2660,7 @@ shellescape({string} [, {special}])
command argument
shiftwidth([{col}]) Number effective value of 'shiftwidth'
sign_define({name} [, {dict}]) Number define or update a sign
sign_define({list}) List define or update a list of signs
sign_getdefined([{name}]) List get a list of defined signs
sign_getplaced([{expr} [, {dict}]])
List get a list of placed signs
@ -2667,9 +2668,12 @@ sign_jump({id}, {group}, {expr})
Number jump to a sign
sign_place({id}, {group}, {name}, {expr} [, {dict}])
Number place a sign
sign_placelist({list}) List place a list of signs
sign_undefine([{name}]) Number undefine a sign
sign_undefine({list}) List undefine a list of signs
sign_unplace({group} [, {dict}])
Number unplace a sign
sign_unplacelist({list}) List unplace a list of signs
simplify({filename}) String simplify filename as much as possible
sin({expr}) Float sine of {expr}
sinh({expr}) Float hyperbolic sine of {expr}
@ -6494,6 +6498,8 @@ listener_flush([{buf}]) *listener_flush()*
listener_remove({id}) *listener_remove()*
Remove a listener previously added with listener_add().
Returns zero when {id} could not be found, one when {id} was
removed.
localtime() *localtime()*
Return the current time, measured as seconds since 1st Jan
@ -8624,6 +8630,7 @@ shiftwidth([{col}]) *shiftwidth()*
no {col} argument is given, column 1 will be assumed.
sign_define({name} [, {dict}]) *sign_define()*
sign_define({list})
Define a new sign named {name} or modify the attributes of an
existing sign. This is similar to the |:sign-define| command.
@ -8643,11 +8650,25 @@ sign_define({name} [, {dict}]) *sign_define()*
If the sign named {name} already exists, then the attributes
of the sign are updated.
Returns 0 on success and -1 on failure.
The one argument {list} can be used to define a list of signs.
Each list item is a dictionary with the above items in {dict}
and a 'name' item for the sign name.
Returns 0 on success and -1 on failure. When the one argument
{list} is used, then returns a List of values one for each
defined sign.
Examples: >
call sign_define("mySign", {"text" : "=>", "texthl" :
\ "Error", "linehl" : "Search"})
call sign_define("mySign", {
\ "text" : "=>",
\ "texthl" : "Error",
\ "linehl" : "Search"})
call sign_define([
\ {'name' : 'sign1',
\ 'text' : '=>'},
\ {'name' : 'sign2',
\ 'text' : '!!'}
\ ])
<
sign_getdefined([{name}]) *sign_getdefined()*
Get a list of defined signs and their attributes.
@ -8800,18 +8821,86 @@ sign_place({id}, {group}, {name}, {expr} [, {dict}])
" at line 40 in buffer json.c with priority 90
call sign_place(10, 'g3', 'sign4', 'json.c',
\ {'lnum' : 40, 'priority' : 90})
<
*sign_placelist()*
sign_placelist({list})
Place one or more signs. This is similar to the
|sign_place()| function. The {list} argument specifies the
List of signs to place. Each list item is a dict with the
following sign attributes:
buffer buffer name or number. For the accepted
values, see |bufname()|.
group sign group. {group} functions as a namespace
for {id}, thus two groups can use the same
IDs. If not specified or set to an empty
string, then the global group is used. See
|sign-group| for more information.
id sign identifier. If not specified or zero,
then a new unique identifier is allocated.
Otherwise the specified number is used. See
|sign-identifier| for more information.
lnum line number in the buffer {expr} where the
sign is to be placed. For the accepted values,
see |line()|.
name name of the sign to place. See |sign_define()|
for more information.
priority priority of the sign. When multiple signs are
placed on a line, the sign with the highest
priority is used. If not specified, the
default value of 10 is used. See
|sign-priority| for more information.
If {id} refers to an existing sign, then the existing sign is
modified to use the specified {name} and/or {priority}.
Returns a List of sign identifiers. If failed to place a
sign, the corresponding list item is set to -1.
Examples: >
" Place sign s1 with id 5 at line 20 and id 10 at line
" 30 in buffer a.c
let [n1, n2] = sign_place([
\ {'id' : 5,
\ 'name' : 's1',
\ 'buffer' : 'a.c',
\ 'lnum' : 20},
\ {'id' : 10,
\ 'name' : 's1',
\ 'buffer' : 'a.c',
\ 'lnum' : 30}
\ ])
" Place sign s1 in buffer a.c at line 40 and 50
" with auto-generated identifiers
let [n1, n2] = sign_place([
\ {'name' : 's1',
\ 'buffer' : 'a.c',
\ 'lnum' : 40},
\ {'name' : 's1',
\ 'buffer' : 'a.c',
\ 'lnum' : 50}
\ ])
<
sign_undefine([{name}]) *sign_undefine()*
sign_undefine({list})
Deletes a previously defined sign {name}. This is similar to
the |:sign-undefine| command. If {name} is not supplied, then
deletes all the defined signs.
Returns 0 on success and -1 on failure.
The one argument {list} can be used to undefine a list of
signs. Each list item is the name of a sign.
Returns 0 on success and -1 on failure. For the one argument
{list} call, returns a list of values one for each undefined
sign.
Examples: >
" Delete a sign named mySign
call sign_undefine("mySign")
" Delete signs 'sign1' and 'sign2'
call sign_undefine(["sign1", "sign2"])
" Delete all the signs
call sign_undefine()
<
@ -8857,6 +8946,32 @@ sign_unplace({group} [, {dict}]) *sign_unplace()*
" Remove all the placed signs from all the buffers
call sign_unplace('*')
<
sign_unplacelist({list}) *sign_unplacelist()*
Remove previously placed signs from one or more buffers. This
is similar to the |sign_unplace()| function.
The {list} argument specifies the List of signs to remove.
Each list item is a dict with the following sign attributes:
buffer buffer name or number. For the accepted
values, see |bufname()|. If not specified,
then the specified sign is removed from all
the buffers.
group sign group name. If not specified or set to an
empty string, then the global sign group is
used. If set to '*', then all the groups
including the global group are used.
id sign identifier. If not specified, then all
the signs in the specified group are removed.
Returns a List where an entry is set to 0 if the corresponding
sign was successfully removed or -1 on failure.
Example: >
" Remove sign with id 10 from buffer a.vim and sign
" with id 20 from buffer b.vim
call sign_unplace([{'id' : 10, 'buffer' : "a.vim"},
\ {'id' : 20, 'buffer' : 'b.vim'}])
<
simplify({filename}) *simplify()*
Simplify the file name as much as possible without changing
the meaning. Shortcuts (on MS-Windows) or symbolic links (on
@ -9917,8 +10032,8 @@ timer_stop({timer}) *timer_stop()*
timer_stopall() *timer_stopall()*
Stop all timers. The timer callbacks will no longer be
invoked. Useful if some timers is misbehaving. If there are
no timers there is no error.
invoked. Useful if a timer is misbehaving. If there are no
timers there is no error.
{only available when compiled with the |+timers| feature}

View File

@ -1015,8 +1015,10 @@ Signs: *sign-functions*
sign_getplaced() get a list of placed signs
sign_jump() jump to a sign
sign_place() place a sign
sign_placelist() place a list of signs
sign_undefine() undefine a sign
sign_unplace() unplace a sign
sign_unplacelist() unplace a list of signs
Terminal window: *terminal-functions*
term_start() open a terminal window and run a job

View File

@ -888,8 +888,10 @@ static struct fst
{"sign_getplaced", 0, 2, f_sign_getplaced},
{"sign_jump", 3, 3, f_sign_jump},
{"sign_place", 4, 5, f_sign_place},
{"sign_placelist", 1, 1, f_sign_placelist},
{"sign_undefine", 0, 1, f_sign_undefine},
{"sign_unplace", 1, 2, f_sign_unplace},
{"sign_unplacelist", 1, 2, f_sign_unplacelist},
#endif
{"simplify", 1, 1, f_simplify},
#ifdef FEAT_FLOAT

View File

@ -22,6 +22,8 @@ void f_sign_getdefined(typval_T *argvars, typval_T *rettv);
void f_sign_getplaced(typval_T *argvars, typval_T *rettv);
void f_sign_jump(typval_T *argvars, typval_T *rettv);
void f_sign_place(typval_T *argvars, typval_T *rettv);
void f_sign_placelist(typval_T *argvars, typval_T *rettv);
void f_sign_undefine(typval_T *argvars, typval_T *rettv);
void f_sign_unplace(typval_T *argvars, typval_T *rettv);
void f_sign_unplacelist(typval_T *argvars, typval_T *rettv);
/* vim: set ft=c : */

View File

@ -442,7 +442,8 @@ buf_change_sign_type(
buf_T *buf, // buffer to store sign in
int markId, // sign ID
char_u *group, // sign group
int typenr) // typenr of sign we are adding
int typenr, // typenr of sign we are adding
int prio) // sign priority
{
signlist_T *sign; // a sign in the signlist
@ -451,6 +452,8 @@ buf_change_sign_type(
if (sign->id == markId && sign_in_group(sign, group))
{
sign->typenr = typenr;
sign->priority = prio;
sign_sort_by_prio_on_line(buf, sign);
return sign->lnum;
}
}
@ -1104,8 +1107,9 @@ sign_place(
// place a sign
buf_addsign(buf, *sign_id, sign_group, prio, lnum, sp->sn_typenr);
else
// ":sign place {id} file={fname}": change sign type
lnum = buf_change_sign_type(buf, *sign_id, sign_group, sp->sn_typenr);
// ":sign place {id} file={fname}": change sign type and/or priority
lnum = buf_change_sign_type(buf, *sign_id, sign_group, sp->sn_typenr,
prio);
if (lnum > 0)
{
redraw_buf_line_later(buf, lnum);
@ -2095,6 +2099,72 @@ set_context_in_sign_cmd(expand_T *xp, char_u *arg)
}
# endif
/*
* Define a sign using the attributes in 'dict'. Returns 0 on success and -1 on
* failure.
*/
static int
sign_define_from_dict(char_u *name_arg, dict_T *dict)
{
char_u *name = NULL;
char_u *icon = NULL;
char_u *linehl = NULL;
char_u *text = NULL;
char_u *texthl = NULL;
int retval = -1;
if (name_arg == NULL)
{
if (dict == NULL)
return -1;
name = dict_get_string(dict, (char_u *)"name", TRUE);
}
else
name = vim_strsave(name_arg);
if (name == NULL || name[0] == NUL)
goto cleanup;
if (dict != NULL)
{
icon = dict_get_string(dict, (char_u *)"icon", TRUE);
linehl = dict_get_string(dict, (char_u *)"linehl", TRUE);
text = dict_get_string(dict, (char_u *)"text", TRUE);
texthl = dict_get_string(dict, (char_u *)"texthl", TRUE);
}
if (sign_define_by_name(name, icon, linehl, text, texthl) == OK)
retval = 0;
cleanup:
vim_free(name);
vim_free(icon);
vim_free(linehl);
vim_free(text);
vim_free(texthl);
return retval;
}
/*
* Define multiple signs using attributes from list 'l' and store the return
* values in 'retlist'.
*/
static void
sign_define_multiple(list_T *l, list_T *retlist)
{
listitem_T *li;
int retval;
for (li = l->lv_first; li != NULL; li = li->li_next)
{
retval = -1;
if (li->li_tv.v_type == VAR_DICT)
retval = sign_define_from_dict(NULL, li->li_tv.vval.v_dict);
else
emsg(_(e_dictreq));
list_append_number(retlist, retval);
}
}
/*
* "sign_define()" function
*/
@ -2102,45 +2172,32 @@ set_context_in_sign_cmd(expand_T *xp, char_u *arg)
f_sign_define(typval_T *argvars, typval_T *rettv)
{
char_u *name;
dict_T *dict;
char_u *icon = NULL;
char_u *linehl = NULL;
char_u *text = NULL;
char_u *texthl = NULL;
if (argvars[0].v_type == VAR_LIST && argvars[1].v_type == VAR_UNKNOWN)
{
// Define multiple signs
if (rettv_list_alloc(rettv) != OK)
return;
sign_define_multiple(argvars[0].vval.v_list, rettv->vval.v_list);
return;
}
// Define a single sign
rettv->vval.v_number = -1;
name = tv_get_string_chk(&argvars[0]);
if (name == NULL)
return;
if (argvars[1].v_type != VAR_UNKNOWN)
if (argvars[1].v_type != VAR_UNKNOWN && argvars[1].v_type != VAR_DICT)
{
if (argvars[1].v_type != VAR_DICT)
{
emsg(_(e_dictreq));
return;
}
// sign attributes
dict = argvars[1].vval.v_dict;
if (dict_find(dict, (char_u *)"icon", -1) != NULL)
icon = dict_get_string(dict, (char_u *)"icon", TRUE);
if (dict_find(dict, (char_u *)"linehl", -1) != NULL)
linehl = dict_get_string(dict, (char_u *)"linehl", TRUE);
if (dict_find(dict, (char_u *)"text", -1) != NULL)
text = dict_get_string(dict, (char_u *)"text", TRUE);
if (dict_find(dict, (char_u *)"texthl", -1) != NULL)
texthl = dict_get_string(dict, (char_u *)"texthl", TRUE);
emsg(_(e_dictreq));
return;
}
if (sign_define_by_name(name, icon, linehl, text, texthl) == OK)
rettv->vval.v_number = 0;
vim_free(icon);
vim_free(linehl);
vim_free(text);
vim_free(texthl);
rettv->vval.v_number = sign_define_from_dict(name,
argvars[1].v_type == VAR_DICT ? argvars[1].vval.v_dict : NULL);
}
/*
@ -2268,88 +2325,197 @@ cleanup:
vim_free(sign_group);
}
/*
* Place a new sign using the values specified in dict 'dict'. Returns the sign
* identifier if successfully placed, otherwise returns 0.
*/
static int
sign_place_from_dict(
typval_T *id_tv,
typval_T *group_tv,
typval_T *name_tv,
typval_T *buf_tv,
dict_T *dict)
{
int sign_id = 0;
char_u *group = NULL;
char_u *sign_name = NULL;
buf_T *buf = NULL;
dictitem_T *di;
linenr_T lnum = 0;
int prio = SIGN_DEF_PRIO;
int notanum = FALSE;
int ret_sign_id = -1;
// sign identifier
if (id_tv == NULL)
{
di = dict_find(dict, (char_u *)"id", -1);
if (di != NULL)
id_tv = &di->di_tv;
}
if (id_tv == NULL)
sign_id = 0;
else
{
sign_id = tv_get_number_chk(id_tv, &notanum);
if (notanum)
return -1;
if (sign_id < 0)
{
emsg(_(e_invarg));
return -1;
}
}
// sign group
if (group_tv == NULL)
{
di = dict_find(dict, (char_u *)"group", -1);
if (di != NULL)
group_tv = &di->di_tv;
}
if (group_tv == NULL)
group = NULL; // global group
else
{
group = tv_get_string_chk(group_tv);
if (group == NULL)
goto cleanup;
if (group[0] == '\0') // global sign group
group = NULL;
else
{
group = vim_strsave(group);
if (group == NULL)
return -1;
}
}
// sign name
if (name_tv == NULL)
{
di = dict_find(dict, (char_u *)"name", -1);
if (di != NULL)
name_tv = &di->di_tv;
}
if (name_tv == NULL)
goto cleanup;
sign_name = tv_get_string_chk(name_tv);
if (sign_name == NULL)
goto cleanup;
// buffer to place the sign
if (buf_tv == NULL)
{
di = dict_find(dict, (char_u *)"buffer", -1);
if (di != NULL)
buf_tv = &di->di_tv;
}
if (buf_tv == NULL)
goto cleanup;
buf = get_buf_arg(buf_tv);
if (buf == NULL)
goto cleanup;
// line number of the sign
di = dict_find(dict, (char_u *)"lnum", -1);
if (di != NULL)
{
lnum = (int)tv_get_number_chk(&di->di_tv, &notanum);
if (notanum)
goto cleanup;
}
// sign priority
di = dict_find(dict, (char_u *)"priority", -1);
if (di != NULL)
{
prio = (int)tv_get_number_chk(&di->di_tv, &notanum);
if (notanum)
goto cleanup;
}
if (sign_place(&sign_id, group, sign_name, buf, lnum, prio) == OK)
ret_sign_id = sign_id;
cleanup:
vim_free(group);
return ret_sign_id;
}
/*
* "sign_place()" function
*/
void
f_sign_place(typval_T *argvars, typval_T *rettv)
{
int sign_id;
char_u *group = NULL;
char_u *sign_name;
buf_T *buf;
dict_T *dict;
dictitem_T *di;
linenr_T lnum = 0;
int prio = SIGN_DEF_PRIO;
int notanum = FALSE;
dict_T *dict = NULL;
rettv->vval.v_number = -1;
// Sign identifier
sign_id = (int)tv_get_number_chk(&argvars[0], &notanum);
if (notanum)
return;
if (sign_id < 0)
if (argvars[4].v_type != VAR_UNKNOWN
&& (argvars[4].v_type != VAR_DICT
|| ((dict = argvars[4].vval.v_dict) == NULL)))
{
emsg(_(e_invarg));
emsg(_(e_dictreq));
return;
}
// Sign group
group = tv_get_string_chk(&argvars[1]);
if (group == NULL)
rettv->vval.v_number = sign_place_from_dict(&argvars[0], &argvars[1],
&argvars[2], &argvars[3], dict);
}
/*
* "sign_placelist()" function. Place multiple signs.
*/
void
f_sign_placelist(typval_T *argvars, typval_T *rettv)
{
listitem_T *li;
int sign_id;
if (rettv_list_alloc(rettv) != OK)
return;
if (group[0] == '\0')
group = NULL; // global sign group
else
if (argvars[0].v_type != VAR_LIST)
{
group = vim_strsave(group);
if (group == NULL)
return;
emsg(_(e_listreq));
return;
}
// Sign name
sign_name = tv_get_string_chk(&argvars[2]);
if (sign_name == NULL)
goto cleanup;
// Buffer to place the sign
buf = get_buf_arg(&argvars[3]);
if (buf == NULL)
goto cleanup;
if (argvars[4].v_type != VAR_UNKNOWN)
// Process the List of sign attributes
for (li = argvars[0].vval.v_list->lv_first; li != NULL; li = li->li_next)
{
if (argvars[4].v_type != VAR_DICT ||
((dict = argvars[4].vval.v_dict) == NULL))
{
sign_id = -1;
if (li->li_tv.v_type == VAR_DICT)
sign_id = sign_place_from_dict(NULL, NULL, NULL, NULL,
li->li_tv.vval.v_dict);
else
emsg(_(e_dictreq));
goto cleanup;
}
// Line number where the sign is to be placed
if ((di = dict_find(dict, (char_u *)"lnum", -1)) != NULL)
{
(void)tv_get_number_chk(&di->di_tv, &notanum);
if (notanum)
goto cleanup;
lnum = tv_get_lnum(&di->di_tv);
}
if ((di = dict_find(dict, (char_u *)"priority", -1)) != NULL)
{
// Sign priority
prio = (int)tv_get_number_chk(&di->di_tv, &notanum);
if (notanum)
goto cleanup;
}
list_append_number(rettv->vval.v_list, sign_id);
}
}
if (sign_place(&sign_id, group, sign_name, buf, lnum, prio) == OK)
rettv->vval.v_number = sign_id;
/*
* Undefine multiple signs
*/
static void
sign_undefine_multiple(list_T *l, list_T *retlist)
{
char_u *name;
listitem_T *li;
int retval;
cleanup:
vim_free(group);
for (li = l->lv_first; li != NULL; li = li->li_next)
{
retval = -1;
name = tv_get_string_chk(&li->li_tv);
if (name != NULL && (sign_undefine_by_name(name) == OK))
retval = 0;
list_append_number(retlist, retval);
}
}
/*
@ -2360,6 +2526,16 @@ f_sign_undefine(typval_T *argvars, typval_T *rettv)
{
char_u *name;
if (argvars[0].v_type == VAR_LIST && argvars[1].v_type == VAR_UNKNOWN)
{
// Undefine multiple signs
if (rettv_list_alloc(rettv) != OK)
return;
sign_undefine_multiple(argvars[0].vval.v_list, rettv->vval.v_list);
return;
}
rettv->vval.v_number = -1;
if (argvars[0].v_type == VAR_UNKNOWN)
@ -2380,17 +2556,79 @@ f_sign_undefine(typval_T *argvars, typval_T *rettv)
}
}
/*
* Unplace the sign with attributes specified in 'dict'. Returns 0 on success
* and -1 on failure.
*/
static int
sign_unplace_from_dict(typval_T *group_tv, dict_T *dict)
{
dictitem_T *di;
int sign_id = 0;
buf_T *buf = NULL;
char_u *group = NULL;
int retval = -1;
// sign group
if (group_tv != NULL)
group = tv_get_string(group_tv);
else
group = dict_get_string(dict, (char_u *)"group", FALSE);
if (group != NULL)
{
if (group[0] == '\0') // global sign group
group = NULL;
else
{
group = vim_strsave(group);
if (group == NULL)
return -1;
}
}
if (dict != NULL)
{
if ((di = dict_find(dict, (char_u *)"buffer", -1)) != NULL)
{
buf = get_buf_arg(&di->di_tv);
if (buf == NULL)
goto cleanup;
}
if (dict_find(dict, (char_u *)"id", -1) != NULL)
{
sign_id = dict_get_number(dict, (char_u *)"id");
if (sign_id <= 0)
{
emsg(_(e_invarg));
goto cleanup;
}
}
}
if (buf == NULL)
{
// Delete the sign in all the buffers
retval = 0;
FOR_ALL_BUFFERS(buf)
if (sign_unplace(sign_id, group, buf, 0) != OK)
retval = -1;
}
else if (sign_unplace(sign_id, group, buf, 0) == OK)
retval = 0;
cleanup:
vim_free(group);
return retval;
}
/*
* "sign_unplace()" function
*/
void
f_sign_unplace(typval_T *argvars, typval_T *rettv)
{
dict_T *dict;
dictitem_T *di;
int sign_id = 0;
buf_T *buf = NULL;
char_u *group = NULL;
dict_T *dict = NULL;
rettv->vval.v_number = -1;
@ -2400,50 +2638,46 @@ f_sign_unplace(typval_T *argvars, typval_T *rettv)
return;
}
group = tv_get_string(&argvars[0]);
if (group[0] == '\0')
group = NULL; // global sign group
else
{
group = vim_strsave(group);
if (group == NULL)
return;
}
if (argvars[1].v_type != VAR_UNKNOWN)
{
if (argvars[1].v_type != VAR_DICT)
{
emsg(_(e_dictreq));
goto cleanup;
return;
}
dict = argvars[1].vval.v_dict;
if ((di = dict_find(dict, (char_u *)"buffer", -1)) != NULL)
{
buf = get_buf_arg(&di->di_tv);
if (buf == NULL)
goto cleanup;
}
if (dict_find(dict, (char_u *)"id", -1) != NULL)
sign_id = dict_get_number(dict, (char_u *)"id");
}
if (buf == NULL)
rettv->vval.v_number = sign_unplace_from_dict(&argvars[0], dict);
}
/*
* "sign_unplacelist()" function
*/
void
f_sign_unplacelist(typval_T *argvars, typval_T *rettv)
{
listitem_T *li;
int retval;
if (rettv_list_alloc(rettv) != OK)
return;
if (argvars[0].v_type != VAR_LIST)
{
// Delete the sign in all the buffers
FOR_ALL_BUFFERS(buf)
if (sign_unplace(sign_id, group, buf, 0) == OK)
rettv->vval.v_number = 0;
}
else
{
if (sign_unplace(sign_id, group, buf, 0) == OK)
rettv->vval.v_number = 0;
emsg(_(e_listreq));
return;
}
cleanup:
vim_free(group);
for (li = argvars[0].vval.v_list->lv_first; li != NULL; li = li->li_next)
{
retval = -1;
if (li->li_tv.v_type == VAR_DICT)
retval = sign_unplace_from_dict(NULL, li->li_tv.vval.v_dict);
else
emsg(_(e_dictreq));
list_append_number(rettv->vval.v_list, retval);
}
}
#endif /* FEAT_SIGNS */

View File

@ -412,7 +412,7 @@ func Test_sign_funcs()
" Tests for invalid arguments to sign_define()
call assert_fails('call sign_define("sign4", {"text" : "===>"})', 'E239:')
call assert_fails('call sign_define("sign5", {"text" : ""})', 'E239:')
call assert_fails('call sign_define([])', 'E730:')
call assert_fails('call sign_define({})', 'E731:')
call assert_fails('call sign_define("sign6", [])', 'E715:')
" Tests for sign_getdefined()
@ -441,7 +441,7 @@ func Test_sign_funcs()
call assert_fails('call sign_place([], "", "mySign", 1)', 'E745:')
call assert_fails('call sign_place(5, "", "mySign", -1)', 'E158:')
call assert_fails('call sign_place(-1, "", "sign1", "Xsign", [])',
\ 'E474:')
\ 'E715:')
call assert_fails('call sign_place(-1, "", "sign1", "Xsign",
\ {"lnum" : 30})', 'E474:')
call assert_fails('call sign_place(10, "", "xsign1x", "Xsign",
@ -501,11 +501,21 @@ func Test_sign_funcs()
\ {'id' : 20, 'buffer' : 200})", 'E158:')
call assert_fails("call sign_unplace('g1', 'mySign')", 'E715:')
call sign_unplace('*')
" Test for modifying a placed sign
call assert_equal(15, sign_place(15, '', 'sign1', 'Xsign', {'lnum' : 20}))
call assert_equal(15, sign_place(15, '', 'sign2', 'Xsign'))
call assert_equal([{'bufnr' : bufnr(''), 'signs' :
\ [{'id' : 15, 'group' : '', 'lnum' : 20, 'name' : 'sign2',
\ 'priority' : 10}]}],
\ sign_getplaced())
" Tests for sign_undefine()
call assert_equal(0, sign_undefine("sign1"))
call assert_equal([], sign_getdefined("sign1"))
call assert_fails('call sign_undefine("none")', 'E155:')
call assert_fails('call sign_undefine([])', 'E730:')
call assert_fails('call sign_undefine({})', 'E731:')
call delete("Xsign")
call sign_unplace('*')
@ -631,7 +641,7 @@ func Test_sign_group()
call assert_equal([], sign_getplaced(bnum, {'group' : '*'})[0].signs)
" Error case
call assert_fails("call sign_unplace([])", 'E474:')
call assert_fails("call sign_unplace({})", 'E474:')
" Place a sign in the global group and try to delete it using a group
call assert_equal(5, sign_place(5, '', 'sign1', bnum, {'lnum' : 10}))
@ -1117,8 +1127,8 @@ func Test_sign_unplace()
call delete("Xsign2")
endfunc
" Tests for auto-generating the sign identifier
func Test_sign_id_autogen()
" Tests for auto-generating the sign identifier.
func Test_aaa_sign_id_autogen()
enew | only
call sign_unplace('*')
call sign_undefine()
@ -1843,3 +1853,113 @@ func Test_sign_numcol()
set number&
enew! | close
endfunc
" Test for managing multiple signs using the sign functions
func Test_sign_funcs_multi()
call writefile(repeat(["Sun is shining"], 30), "Xsign")
edit Xsign
let bnum = bufnr('')
" Define multiple signs at once
call assert_equal([0, 0, 0, 0], sign_define([
\ {'name' : 'sign1', 'text' : '=>', 'linehl' : 'Search',
\ 'texthl' : 'Search'},
\ {'name' : 'sign2', 'text' : '=>', 'linehl' : 'Search',
\ 'texthl' : 'Search'},
\ {'name' : 'sign3', 'text' : '=>', 'linehl' : 'Search',
\ 'texthl' : 'Search'},
\ {'name' : 'sign4', 'text' : '=>', 'linehl' : 'Search',
\ 'texthl' : 'Search'}]))
" Negative cases for sign_define()
call assert_equal([], sign_define([]))
call assert_equal([-1], sign_define([{}]))
call assert_fails('call sign_define([6])', 'E715:')
call assert_fails('call sign_define(["abc"])', 'E715:')
call assert_fails('call sign_define([[]])', 'E715:')
" Place multiple signs at once with specific sign identifier
let l = sign_placelist([{'id' : 1, 'group' : 'g1', 'name' : 'sign1',
\ 'buffer' : 'Xsign', 'lnum' : 11, 'priority' : 50},
\ {'id' : 2, 'group' : 'g2', 'name' : 'sign2',
\ 'buffer' : 'Xsign', 'lnum' : 11, 'priority' : 100},
\ {'id' : 3, 'group' : '', 'name' : 'sign3',
\ 'buffer' : 'Xsign', 'lnum' : 11}])
call assert_equal([1, 2, 3], l)
let s = sign_getplaced('Xsign', {'group' : '*'})
call assert_equal([
\ {'id' : 2, 'name' : 'sign2', 'lnum' : 11,
\ 'group' : 'g2', 'priority' : 100},
\ {'id' : 1, 'name' : 'sign1', 'lnum' : 11,
\ 'group' : 'g1', 'priority' : 50},
\ {'id' : 3, 'name' : 'sign3', 'lnum' : 11,
\ 'group' : '', 'priority' : 10}], s[0].signs)
call sign_unplace('*')
" Place multiple signs at once with auto-generated sign identifier
call assert_equal([1, 1, 5], sign_placelist([
\ {'group' : 'g1', 'name' : 'sign1',
\ 'buffer' : 'Xsign', 'lnum' : 11},
\ {'group' : 'g2', 'name' : 'sign2',
\ 'buffer' : 'Xsign', 'lnum' : 11},
\ {'group' : '', 'name' : 'sign3',
\ 'buffer' : 'Xsign', 'lnum' : 11}]))
let s = sign_getplaced('Xsign', {'group' : '*'})
call assert_equal([
\ {'id' : 5, 'name' : 'sign3', 'lnum' : 11,
\ 'group' : '', 'priority' : 10},
\ {'id' : 1, 'name' : 'sign2', 'lnum' : 11,
\ 'group' : 'g2', 'priority' : 10},
\ {'id' : 1, 'name' : 'sign1', 'lnum' : 11,
\ 'group' : 'g1', 'priority' : 10}], s[0].signs)
" Change an existing sign without specifying the group
call assert_equal([5], sign_placelist([
\ {'id' : 5, 'name' : 'sign1', 'buffer' : 'Xsign'}]))
let s = sign_getplaced('Xsign', {'id' : 5, 'group' : ''})
call assert_equal([{'id' : 5, 'name' : 'sign1', 'lnum' : 11,
\ 'group' : '', 'priority' : 10}], s[0].signs)
" Place sign without a sign name
call assert_equal([-1], sign_placelist([{'id' : 10, 'buffer' : 'Xsign',
\ 'lnum' : 12, 'group' : ''}]))
" Place sign without a buffer
call assert_equal([-1], sign_placelist([{'id' : 10, 'name' : 'sign1',
\ 'lnum' : 12, 'group' : ''}]))
" Invalid arguments
call assert_equal([], sign_placelist([]))
call assert_fails('call sign_placelist({})', "E714:")
call assert_fails('call sign_placelist([[]])', "E715:")
call assert_fails('call sign_placelist(["abc"])', "E715:")
call assert_fails('call sign_placelist([100])', "E715:")
" Unplace multiple signs
call assert_equal([0, 0, 0], sign_unplacelist([{'id' : 5},
\ {'id' : 1, 'group' : 'g1'}, {'id' : 1, 'group' : 'g2'}]))
" Invalid arguments
call assert_equal([], sign_unplacelist([]))
call assert_fails('call sign_unplacelist({})', "E714:")
call assert_fails('call sign_unplacelist([[]])', "E715:")
call assert_fails('call sign_unplacelist(["abc"])', "E715:")
call assert_fails('call sign_unplacelist([100])', "E715:")
call assert_fails("call sign_unplacelist([{'id' : -1}])", 'E474')
call assert_equal([0, 0, 0, 0],
\ sign_undefine(['sign1', 'sign2', 'sign3', 'sign4']))
call assert_equal([], sign_getdefined())
" Invalid arguments
call assert_equal([], sign_undefine([]))
call assert_fails('call sign_undefine([[]])', 'E730:')
call assert_fails('call sign_undefine([{}])', 'E731:')
call assert_fails('call sign_undefine(["1abc2"])', 'E155:')
call sign_unplace('*')
call sign_undefine()
enew!
call delete("Xsign")
endfunc

View File

@ -777,6 +777,8 @@ static char *(features[]) =
static int included_patches[] =
{ /* Add new patch number below this line */
/**/
1682,
/**/
1681,
/**/