mirror of
https://github.com/vim/vim
synced 2025-03-16 06:47:52 +01:00
patch 8.2.4981: it is not possible to manipulate autocommands
Problem: It is not possible to manipulate autocommands. Solution: Add functions to add, get and set autocommands. (Yegappan Lakshmanan, closes #10291)
This commit is contained in:
parent
aaadb5b6f7
commit
1755a91851
9 changed files with 801 additions and 1 deletions
|
@ -82,6 +82,9 @@ triggered.
|
|||
/<start
|
||||
}
|
||||
|
||||
The |autocmd_add()| function can be used to add a list of autocmds and autocmd
|
||||
groups from a Vim script.
|
||||
|
||||
Note: The ":autocmd" command can only be followed by another command when the
|
||||
'|' appears where the pattern is expected. This works: >
|
||||
:augroup mine | au! BufRead | augroup END
|
||||
|
@ -146,6 +149,9 @@ prompt. When one command outputs two messages this can happen anyway.
|
|||
==============================================================================
|
||||
3. Removing autocommands *autocmd-remove*
|
||||
|
||||
In addition to the below described commands, the |autocmd_delete()| function can
|
||||
be used to remove a list of autocmds and autocmd groups from a Vim script.
|
||||
|
||||
:au[tocmd]! [group] {event} {aupat} [++once] [++nested] {cmd}
|
||||
Remove all autocommands associated with {event} and
|
||||
{aupat}, and add the command {cmd}.
|
||||
|
@ -198,6 +204,9 @@ argument behavior differs from that for defining and removing autocommands.
|
|||
In order to list buffer-local autocommands, use a pattern in the form <buffer>
|
||||
or <buffer=N>. See |autocmd-buflocal|.
|
||||
|
||||
The |autocmd_get()| function can be used from a Vim script to get a list of
|
||||
autocmds.
|
||||
|
||||
*:autocmd-verbose*
|
||||
When 'verbose' is non-zero, listing an autocommand will also display where it
|
||||
was last defined. Example: >
|
||||
|
|
|
@ -60,6 +60,9 @@ assert_report({msg}) Number report a test failure
|
|||
assert_true({actual} [, {msg}]) Number assert {actual} is true
|
||||
atan({expr}) Float arc tangent of {expr}
|
||||
atan2({expr1}, {expr2}) Float arc tangent of {expr1} / {expr2}
|
||||
autocmd_add({acmds}) Bool add a list of autocmds and groups
|
||||
autocmd_delete({acmds}) Bool delete a list of autocmds and groups
|
||||
autocmd_get([{opts}]) List return a list of autocmds
|
||||
balloon_gettext() String current text in the balloon
|
||||
balloon_show({expr}) none show {expr} inside the balloon
|
||||
balloon_split({msg}) List split {msg} as used for a balloon
|
||||
|
@ -922,6 +925,145 @@ atan2({expr1}, {expr2}) *atan2()*
|
|||
<
|
||||
{only available when compiled with the |+float| feature}
|
||||
|
||||
|
||||
autocmd_add({acmds}) *autocmd_add()*
|
||||
Adds a List of autocmds and autocmd groups.
|
||||
|
||||
The {acmds} argument is a List where each item is a Dict with
|
||||
the following optional items:
|
||||
bufnr buffer number to add a buffer-local autocmd.
|
||||
If this item is specified, then the "pattern"
|
||||
item is ignored.
|
||||
cmd Ex command to execute for this autocmd event
|
||||
event autocmd event name. Refer to |autocmd-events|.
|
||||
group autocmd group name. Refer to |autocmd-groups|.
|
||||
If this group doesn't exist then it is
|
||||
created. If not specified or empty, then the
|
||||
default group is used.
|
||||
nested set to v:true to add a nested autocmd.
|
||||
Refer to |autocmd-nested|.
|
||||
once set to v:true to add a autocmd which executes
|
||||
only once. Refer to |autocmd-once|.
|
||||
pattern autocmd pattern string. Refer to
|
||||
|autocmd-patterns|. If "bufnr" item is
|
||||
present, then this item is ignored.
|
||||
|
||||
Returns v:true on success and v:false on failure.
|
||||
Examples: >
|
||||
" Create a buffer-local autocmd for buffer 5
|
||||
let acmd = {}
|
||||
let acmd.group = 'MyGroup'
|
||||
let acmd.event = 'BufEnter'
|
||||
let acmd.bufnr = 5
|
||||
let acmd.cmd = 'call BufEnterFunc()'
|
||||
call autocmd_add([acmd])
|
||||
|
||||
Can also be used as a |method|: >
|
||||
GetAutocmdList()->autocmd_add()
|
||||
<
|
||||
autocmd_delete({acmds}) *autocmd_delete()*
|
||||
Deletes a List of autocmds and autocmd groups.
|
||||
|
||||
The {acmds} argument is a List where each item is a Dict with
|
||||
the following optional items:
|
||||
bufnr buffer number to delete a buffer-local autocmd.
|
||||
If this item is specified, then the "pattern"
|
||||
item is ignored.
|
||||
cmd Ex command for this autocmd event
|
||||
event autocmd event name. Refer to |autocmd-events|.
|
||||
If '*' then all the autocmd events in this
|
||||
group are deleted.
|
||||
group autocmd group name. Refer to |autocmd-groups|.
|
||||
If not specified or empty, then the default
|
||||
group is used.
|
||||
nested set to v:true for a nested autocmd.
|
||||
Refer to |autocmd-nested|.
|
||||
once set to v:true for an autocmd which executes
|
||||
only once. Refer to |autocmd-once|.
|
||||
pattern autocmd pattern string. Refer to
|
||||
|autocmd-patterns|. If "bufnr" item is
|
||||
present, then this item is ignored.
|
||||
|
||||
If only {group} is specified in a {acmds} entry and {event},
|
||||
{pattern} and {cmd} are not specified, then that autocmd group
|
||||
is deleted.
|
||||
|
||||
Returns v:true on success and v:false on failure.
|
||||
Examples: >
|
||||
" :autocmd! BufLeave *.vim
|
||||
let acmd = #{event: 'BufLeave', pattern: '*.vim'}
|
||||
call autocmd_delete([acmd]})
|
||||
" :autocmd! MyGroup1 BufLeave
|
||||
let acmd = #{group: 'MyGroup1', event: 'BufLeave'}
|
||||
call autocmd_delete([acmd])
|
||||
" :autocmd! MyGroup2 BufEnter *.c
|
||||
let acmd = #{group: 'MyGroup2', event: 'BufEnter',
|
||||
\ pattern: '*.c'}
|
||||
" :autocmd! MyGroup2 * *.c
|
||||
let acmd = #{group: 'MyGroup2', event: '*',
|
||||
\ pattern: '*.c'}
|
||||
call autocmd_delete([acmd])
|
||||
" :autocmd! MyGroup3
|
||||
let acmd = #{group: 'MyGroup3'}
|
||||
call autocmd_delete([acmd])
|
||||
<
|
||||
Can also be used as a |method|: >
|
||||
GetAutocmdList()->autocmd_delete()
|
||||
|
||||
autocmd_get([{opts}]) *autocmd_get()*
|
||||
Returns a |List| of autocmds. If {opts} is not supplied, then
|
||||
returns the autocmds for all the events in all the groups.
|
||||
|
||||
The optional {opts} Dict argument supports the following
|
||||
items:
|
||||
group Autocmd group name. If specified, returns only
|
||||
the autocmds defined in this group. If the
|
||||
specified group doesn't exist, results in an
|
||||
error message. If set to an empty string,
|
||||
then the default autocmd group is used.
|
||||
event Autocmd event name. If specified, returns only
|
||||
the autocmds defined for this event. If set
|
||||
to "*", then returns autocmds for all the
|
||||
events. If the specified event doesn't exist,
|
||||
results in an error message.
|
||||
pattern Autocmd pattern. If specified, returns only
|
||||
the autocmds defined for this pattern.
|
||||
A combination of the above three times can be supplied in
|
||||
{opts}.
|
||||
|
||||
Each Dict in the returned List contains the following items:
|
||||
bufnr For buffer-local autocmds, buffer number where
|
||||
the autocmd is defined.
|
||||
cmd Command executed for this autocmd.
|
||||
event Autocmd event name.
|
||||
group Autocmd group name.
|
||||
nested Set to v:true for a nested autocmd. See
|
||||
|autocmd-nested|.
|
||||
once Set to v:true, if the autocmd will be executed
|
||||
only once. See |autocmd-once|.
|
||||
pattern Autocmd pattern. For a buffer-local
|
||||
autocmd, this will be of the form "<buffer=n>".
|
||||
If there are multiple commands for an autocmd event in a
|
||||
group, then separate items are returned for each command.
|
||||
|
||||
Examples: >
|
||||
" :autocmd MyGroup
|
||||
echo autocmd_get(#{group: 'Mygroup'})
|
||||
" :autocmd G BufUnload
|
||||
echo autocmd_get(#{group: 'G', event: 'BufUnload'})
|
||||
" :autocmd G * *.ts
|
||||
let acmd = #{group: 'G', event: '*', pattern: '*.ts'}
|
||||
echo autocmd_get(acmd)
|
||||
" :autocmd Syntax
|
||||
echo autocmd_get(#{event: 'Syntax'})
|
||||
" :autocmd G BufEnter *.ts
|
||||
let acmd = #{group: 'G', event: 'BufEnter',
|
||||
\ pattern: '*.ts'}
|
||||
echo autocmd_get(acmd)
|
||||
<
|
||||
Can also be used as a |method|: >
|
||||
Getopts()->autocmd_get()
|
||||
<
|
||||
balloon_gettext() *balloon_gettext()*
|
||||
Return the current text in the balloon. Only for the string,
|
||||
not used for the List.
|
||||
|
|
|
@ -925,6 +925,11 @@ Date and Time: *date-functions* *time-functions*
|
|||
reltimestr() convert reltime() result to a string
|
||||
reltimefloat() convert reltime() result to a Float
|
||||
|
||||
Autocmds: *autocmd-functions*
|
||||
autocmd_add() add a list of autocmds and groups
|
||||
autocmd_delete() delete a list of autocmds and groups
|
||||
autocmd_get() return a list of autocmds
|
||||
|
||||
*buffer-functions* *window-functions* *arg-functions*
|
||||
Buffers, windows and the argument list:
|
||||
argc() number of entries in the argument list
|
||||
|
|
353
src/autocmd.c
353
src/autocmd.c
|
@ -2562,7 +2562,7 @@ get_augroup_name(expand_T *xp UNUSED, int idx)
|
|||
{
|
||||
if (idx == augroups.ga_len) // add "END" add the end
|
||||
return (char_u *)"END";
|
||||
if (idx >= augroups.ga_len) // end of list
|
||||
if (idx < 0 || idx >= augroups.ga_len) // end of list
|
||||
return NULL;
|
||||
if (AUGROUP_NAME(idx) == NULL || AUGROUP_NAME(idx) == get_deleted_augroup())
|
||||
// skip deleted entries
|
||||
|
@ -2747,4 +2747,355 @@ theend:
|
|||
vim_free(arg_save);
|
||||
return retval;
|
||||
}
|
||||
|
||||
/*
|
||||
* autocmd_add() and autocmd_delete() functions
|
||||
*/
|
||||
static void
|
||||
autocmd_add_or_delete(typval_T *argvars, typval_T *rettv, int delete)
|
||||
{
|
||||
list_T *event_list;
|
||||
listitem_T *li;
|
||||
dict_T *event_dict;
|
||||
char_u *event_name = NULL;
|
||||
event_T event;
|
||||
char_u *group_name = NULL;
|
||||
int group;
|
||||
char_u *pat = NULL;
|
||||
char_u *cmd = NULL;
|
||||
char_u *end;
|
||||
int once;
|
||||
int nested;
|
||||
int retval = VVAL_TRUE;
|
||||
int save_augroup = current_augroup;
|
||||
|
||||
rettv->v_type = VAR_BOOL;
|
||||
rettv->vval.v_number = VVAL_FALSE;
|
||||
|
||||
if (check_for_list_arg(argvars, 0) == FAIL)
|
||||
return;
|
||||
|
||||
event_list = argvars[0].vval.v_list;
|
||||
if (event_list == NULL)
|
||||
return;
|
||||
|
||||
FOR_ALL_LIST_ITEMS(event_list, li)
|
||||
{
|
||||
VIM_CLEAR(event_name);
|
||||
VIM_CLEAR(group_name);
|
||||
VIM_CLEAR(pat);
|
||||
VIM_CLEAR(cmd);
|
||||
|
||||
if (li->li_tv.v_type != VAR_DICT)
|
||||
continue;
|
||||
|
||||
event_dict = li->li_tv.vval.v_dict;
|
||||
if (event_dict == NULL)
|
||||
continue;
|
||||
|
||||
event_name = dict_get_string(event_dict, (char_u *)"event", TRUE);
|
||||
if (event_name == NULL)
|
||||
{
|
||||
if (delete)
|
||||
// if the event name is not specified, delete all the events
|
||||
event = NUM_EVENTS;
|
||||
else
|
||||
continue;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (delete && event_name[0] == '*' && event_name[1] == NUL)
|
||||
// if the event name is '*', delete all the events
|
||||
event = NUM_EVENTS;
|
||||
else
|
||||
{
|
||||
event = event_name2nr(event_name, &end);
|
||||
if (event == NUM_EVENTS)
|
||||
{
|
||||
semsg(_(e_no_such_event_str), event_name);
|
||||
retval = VVAL_FALSE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
group_name = dict_get_string(event_dict, (char_u *)"group", TRUE);
|
||||
if (group_name == NULL || *group_name == NUL)
|
||||
// if the autocmd group name is not specified, then use the current
|
||||
// autocmd group
|
||||
group = current_augroup;
|
||||
else
|
||||
{
|
||||
group = au_find_group(group_name);
|
||||
if (group == AUGROUP_ERROR)
|
||||
{
|
||||
if (delete)
|
||||
{
|
||||
semsg(_(e_no_such_group_str), group_name);
|
||||
retval = VVAL_FALSE;
|
||||
break;
|
||||
}
|
||||
// group is not found, create it now
|
||||
group = au_new_group(group_name);
|
||||
if (group == AUGROUP_ERROR)
|
||||
{
|
||||
semsg(_(e_no_such_group_str), group_name);
|
||||
retval = VVAL_FALSE;
|
||||
break;
|
||||
}
|
||||
|
||||
current_augroup = group;
|
||||
}
|
||||
}
|
||||
|
||||
// if a buffer number is specified, then generate a pattern of the form
|
||||
// "<buffer=n>. Otherwise, use the pattern supplied by the user.
|
||||
if (dict_has_key(event_dict, "bufnr"))
|
||||
{
|
||||
varnumber_T bnum;
|
||||
|
||||
bnum = dict_get_number_def(event_dict, (char_u *)"bufnr", -1);
|
||||
if (bnum == -1)
|
||||
continue;
|
||||
|
||||
pat = alloc(128 + 1);
|
||||
if (pat == NULL)
|
||||
continue;
|
||||
vim_snprintf((char *)pat, 128, "<buffer=%d>", (int)bnum);
|
||||
}
|
||||
else
|
||||
{
|
||||
pat = dict_get_string(event_dict, (char_u *)"pattern", TRUE);
|
||||
if (pat == NULL)
|
||||
{
|
||||
if (delete)
|
||||
pat = vim_strsave((char_u *)"");
|
||||
else
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
once = dict_get_bool(event_dict, (char_u *)"once", FALSE);
|
||||
nested = dict_get_bool(event_dict, (char_u *)"nested", FALSE);
|
||||
|
||||
cmd = dict_get_string(event_dict, (char_u *)"cmd", TRUE);
|
||||
if (cmd == NULL)
|
||||
{
|
||||
if (delete)
|
||||
cmd = vim_strsave((char_u *)"");
|
||||
else
|
||||
continue;
|
||||
}
|
||||
|
||||
if (event == NUM_EVENTS)
|
||||
{
|
||||
// event is '*', apply for all the events
|
||||
for (event = (event_T)0; (int)event < NUM_EVENTS;
|
||||
event = (event_T)((int)event + 1))
|
||||
{
|
||||
if (do_autocmd_event(event, pat, once, nested, cmd, delete,
|
||||
group, 0) == FAIL)
|
||||
{
|
||||
retval = VVAL_FALSE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (do_autocmd_event(event, pat, once, nested, cmd, delete, group,
|
||||
0) == FAIL)
|
||||
{
|
||||
retval = VVAL_FALSE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// if only the autocmd group name is specified for delete and the
|
||||
// autocmd event, pattern and cmd are not specified, then delete the
|
||||
// autocmd group.
|
||||
if (delete && group_name != NULL &&
|
||||
(event_name == NULL || event_name[0] == NUL)
|
||||
&& (pat == NULL || pat[0] == NUL)
|
||||
&& (cmd == NULL || cmd[0] == NUL))
|
||||
au_del_group(group_name);
|
||||
}
|
||||
|
||||
VIM_CLEAR(event_name);
|
||||
VIM_CLEAR(group_name);
|
||||
VIM_CLEAR(pat);
|
||||
VIM_CLEAR(cmd);
|
||||
|
||||
current_augroup = save_augroup;
|
||||
rettv->vval.v_number = retval;
|
||||
}
|
||||
|
||||
/*
|
||||
* autocmd_add() function
|
||||
*/
|
||||
void
|
||||
f_autocmd_add(typval_T *argvars, typval_T *rettv)
|
||||
{
|
||||
autocmd_add_or_delete(argvars, rettv, FALSE);
|
||||
}
|
||||
|
||||
/*
|
||||
* autocmd_delete() function
|
||||
*/
|
||||
void
|
||||
f_autocmd_delete(typval_T *argvars, typval_T *rettv)
|
||||
{
|
||||
autocmd_add_or_delete(argvars, rettv, TRUE);
|
||||
}
|
||||
|
||||
/*
|
||||
* autocmd_get() function
|
||||
* Returns a List of autocmds.
|
||||
*/
|
||||
void
|
||||
f_autocmd_get(typval_T *argvars, typval_T *rettv)
|
||||
{
|
||||
event_T event_arg = NUM_EVENTS;
|
||||
event_T event;
|
||||
AutoPat *ap;
|
||||
AutoCmd *ac;
|
||||
list_T *event_list;
|
||||
dict_T *event_dict;
|
||||
char_u *event_name = NULL;
|
||||
char_u *pat = NULL;
|
||||
char_u *name = NULL;
|
||||
int group = AUGROUP_ALL;
|
||||
|
||||
if (check_for_opt_dict_arg(argvars, 0) == FAIL)
|
||||
return;
|
||||
|
||||
if (argvars[0].v_type == VAR_DICT)
|
||||
{
|
||||
// return only the autocmds in the specified group
|
||||
if (dict_has_key(argvars[0].vval.v_dict, "group"))
|
||||
{
|
||||
name = dict_get_string(argvars[0].vval.v_dict,
|
||||
(char_u *)"group", TRUE);
|
||||
if (name == NULL)
|
||||
return;
|
||||
|
||||
if (*name == NUL)
|
||||
group = AUGROUP_DEFAULT;
|
||||
else
|
||||
{
|
||||
group = au_find_group(name);
|
||||
if (group == AUGROUP_ERROR)
|
||||
{
|
||||
semsg(_(e_no_such_group_str), name);
|
||||
vim_free(name);
|
||||
return;
|
||||
}
|
||||
}
|
||||
vim_free(name);
|
||||
}
|
||||
|
||||
// return only the autocmds for the specified event
|
||||
if (dict_has_key(argvars[0].vval.v_dict, "event"))
|
||||
{
|
||||
int i;
|
||||
|
||||
name = dict_get_string(argvars[0].vval.v_dict,
|
||||
(char_u *)"event", TRUE);
|
||||
if (name == NULL)
|
||||
return;
|
||||
|
||||
if (name[0] == '*' && name[1] == NUL)
|
||||
event_arg = NUM_EVENTS;
|
||||
else
|
||||
{
|
||||
for (i = 0; event_names[i].name != NULL; i++)
|
||||
if (STRICMP(event_names[i].name, name) == 0)
|
||||
break;
|
||||
if (event_names[i].name == NULL)
|
||||
{
|
||||
semsg(_(e_no_such_event_str), name);
|
||||
vim_free(name);
|
||||
return;
|
||||
}
|
||||
event_arg = event_names[i].event;
|
||||
}
|
||||
vim_free(name);
|
||||
}
|
||||
|
||||
// return only the autocmds for the specified pattern
|
||||
if (dict_has_key(argvars[0].vval.v_dict, "pattern"))
|
||||
{
|
||||
pat = dict_get_string(argvars[0].vval.v_dict,
|
||||
(char_u *)"pattern", TRUE);
|
||||
if (pat == NULL)
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (rettv_list_alloc(rettv) == FAIL)
|
||||
return;
|
||||
event_list = rettv->vval.v_list;
|
||||
|
||||
// iterate through all the autocmd events
|
||||
for (event = (event_T)0; (int)event < NUM_EVENTS;
|
||||
event = (event_T)((int)event + 1))
|
||||
{
|
||||
if (event_arg != NUM_EVENTS && event != event_arg)
|
||||
continue;
|
||||
|
||||
event_name = event_nr2name(event);
|
||||
|
||||
// iterate through all the patterns for this autocmd event
|
||||
FOR_ALL_AUTOCMD_PATTERNS(event, ap)
|
||||
{
|
||||
char_u *group_name;
|
||||
|
||||
if (group != AUGROUP_ALL && group != ap->group)
|
||||
continue;
|
||||
|
||||
if (pat != NULL && STRCMP(pat, ap->pat) != 0)
|
||||
continue;
|
||||
|
||||
group_name = get_augroup_name(NULL, ap->group);
|
||||
|
||||
// iterate through all the commands for this pattern and add one
|
||||
// item for each cmd.
|
||||
for (ac = ap->cmds; ac != NULL; ac = ac->next)
|
||||
{
|
||||
event_dict = dict_alloc();
|
||||
if (event_dict == NULL)
|
||||
return;
|
||||
|
||||
if (list_append_dict(event_list, event_dict) == FAIL)
|
||||
return;
|
||||
|
||||
if (dict_add_string(event_dict, "event", event_name) == FAIL)
|
||||
return;
|
||||
|
||||
if (dict_add_string(event_dict, "group", group_name == NULL
|
||||
? (char_u *)"" : group_name) == FAIL)
|
||||
return;
|
||||
|
||||
if (ap->buflocal_nr != 0)
|
||||
if (dict_add_number(event_dict, "bufnr", ap->buflocal_nr)
|
||||
== FAIL)
|
||||
return;
|
||||
|
||||
if (dict_add_string(event_dict, "pattern", ap->pat) == FAIL)
|
||||
return;
|
||||
|
||||
if (dict_add_string(event_dict, "cmd", ac->cmd) == FAIL)
|
||||
return;
|
||||
|
||||
if (dict_add_bool(event_dict, "once", ac->once) == FAIL)
|
||||
return;
|
||||
if (dict_add_bool(event_dict, "nested", ac->nested) == FAIL)
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
vim_free(pat);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
@ -1587,6 +1587,12 @@ static funcentry_T global_functions[] =
|
|||
ret_float, FLOAT_FUNC(f_atan)},
|
||||
{"atan2", 2, 2, FEARG_1, arg2_float_or_nr,
|
||||
ret_float, FLOAT_FUNC(f_atan2)},
|
||||
{"autocmd_add", 1, 1, FEARG_1, arg1_list_any,
|
||||
ret_number_bool, f_autocmd_add},
|
||||
{"autocmd_delete", 1, 1, FEARG_1, arg1_list_any,
|
||||
ret_number_bool, f_autocmd_delete},
|
||||
{"autocmd_get", 0, 1, FEARG_1, arg1_dict_any,
|
||||
ret_list_dict_any, f_autocmd_get},
|
||||
{"balloon_gettext", 0, 0, 0, NULL,
|
||||
ret_string,
|
||||
#ifdef FEAT_BEVAL
|
||||
|
|
|
@ -38,4 +38,7 @@ char_u *set_context_in_autocmd(expand_T *xp, char_u *arg, int doautocmd);
|
|||
char_u *get_event_name(expand_T *xp, int idx);
|
||||
int autocmd_supported(char_u *name);
|
||||
int au_exists(char_u *arg);
|
||||
void f_autocmd_add(typval_T *argvars, typval_T *rettv);
|
||||
void f_autocmd_delete(typval_T *argvars, typval_T *rettv);
|
||||
void f_autocmd_get(typval_T *argvars, typval_T *rettv);
|
||||
/* vim: set ft=c : */
|
||||
|
|
|
@ -3210,4 +3210,274 @@ func Test_noname_autocmd()
|
|||
augroup! test_noname_autocmd_group
|
||||
endfunc
|
||||
|
||||
" Test for the autocmd_get() function
|
||||
func Test_autocmd_get()
|
||||
augroup TestAutoCmdFns
|
||||
au!
|
||||
autocmd BufAdd *.vim echo "bufadd-vim"
|
||||
autocmd BufAdd *.py echo "bufadd-py"
|
||||
autocmd BufHidden *.vim echo "bufhidden"
|
||||
augroup END
|
||||
augroup TestAutoCmdFns2
|
||||
autocmd BufAdd *.vim echo "bufadd-vim-2"
|
||||
autocmd BufRead *.a1b2c3 echo "bufadd-vim-2"
|
||||
augroup END
|
||||
|
||||
let l = autocmd_get()
|
||||
call assert_true(l->len() > 0)
|
||||
|
||||
" Test for getting all the autocmds in a group
|
||||
let expected = [
|
||||
\ #{cmd: 'echo "bufadd-vim"', group: 'TestAutoCmdFns',
|
||||
\ pattern: '*.vim', nested: v:false, once: v:false,
|
||||
\ event: 'BufAdd'},
|
||||
\ #{cmd: 'echo "bufadd-py"', group: 'TestAutoCmdFns',
|
||||
\ pattern: '*.py', nested: v:false, once: v:false,
|
||||
\ event: 'BufAdd'},
|
||||
\ #{cmd: 'echo "bufhidden"', group: 'TestAutoCmdFns',
|
||||
\ pattern: '*.vim', nested: v:false,
|
||||
\ once: v:false, event: 'BufHidden'}]
|
||||
call assert_equal(expected, autocmd_get(#{group: 'TestAutoCmdFns'}))
|
||||
|
||||
" Test for getting autocmds for all the patterns in a group
|
||||
call assert_equal(expected, autocmd_get(#{group: 'TestAutoCmdFns',
|
||||
\ event: '*'}))
|
||||
|
||||
" Test for getting autocmds for an event in a group
|
||||
let expected = [
|
||||
\ #{cmd: 'echo "bufadd-vim"', group: 'TestAutoCmdFns',
|
||||
\ pattern: '*.vim', nested: v:false, once: v:false,
|
||||
\ event: 'BufAdd'},
|
||||
\ #{cmd: 'echo "bufadd-py"', group: 'TestAutoCmdFns',
|
||||
\ pattern: '*.py', nested: v:false, once: v:false,
|
||||
\ event: 'BufAdd'}]
|
||||
call assert_equal(expected, autocmd_get(#{group: 'TestAutoCmdFns',
|
||||
\ event: 'BufAdd'}))
|
||||
|
||||
" Test for getting the autocmds for all the events in a group for particular
|
||||
" pattern
|
||||
call assert_equal([{'cmd': 'echo "bufadd-py"', 'group': 'TestAutoCmdFns',
|
||||
\ 'pattern': '*.py', 'nested': v:false, 'once': v:false,
|
||||
\ 'event': 'BufAdd'}],
|
||||
\ autocmd_get(#{group: 'TestAutoCmdFns', event: '*', pattern: '*.py'}))
|
||||
|
||||
" Test for getting the autocmds for an events in a group for particular
|
||||
" pattern
|
||||
let l = autocmd_get(#{group: 'TestAutoCmdFns', event: 'BufAdd',
|
||||
\ pattern: '*.vim'})
|
||||
call assert_equal([
|
||||
\ #{cmd: 'echo "bufadd-vim"', group: 'TestAutoCmdFns',
|
||||
\ pattern: '*.vim', nested: v:false, once: v:false,
|
||||
\ event: 'BufAdd'}], l)
|
||||
|
||||
" Test for getting the autocmds for a pattern in a group
|
||||
let l = autocmd_get(#{group: 'TestAutoCmdFns', pattern: '*.vim'})
|
||||
call assert_equal([
|
||||
\ #{cmd: 'echo "bufadd-vim"', group: 'TestAutoCmdFns',
|
||||
\ pattern: '*.vim', nested: v:false, once: v:false,
|
||||
\ event: 'BufAdd'},
|
||||
\ #{cmd: 'echo "bufhidden"', group: 'TestAutoCmdFns',
|
||||
\ pattern: '*.vim', nested: v:false,
|
||||
\ once: v:false, event: 'BufHidden'}], l)
|
||||
|
||||
" Test for getting the autocmds for a pattern in all the groups
|
||||
let l = autocmd_get(#{pattern: '*.a1b2c3'})
|
||||
call assert_equal([{'cmd': 'echo "bufadd-vim-2"', 'group': 'TestAutoCmdFns2',
|
||||
\ 'pattern': '*.a1b2c3', 'nested': v:false, 'once': v:false,
|
||||
\ 'event': 'BufRead'}], l)
|
||||
|
||||
" Test for getting autocmds for a pattern without any autocmds
|
||||
call assert_equal([], autocmd_get(#{group: 'TestAutoCmdFns',
|
||||
\ pattern: '*.abc'}))
|
||||
call assert_equal([], autocmd_get(#{group: 'TestAutoCmdFns',
|
||||
\ event: 'BufAdd', pattern: '*.abc'}))
|
||||
call assert_equal([], autocmd_get(#{group: 'TestAutoCmdFns',
|
||||
\ event: 'BufWipeout'}))
|
||||
call assert_fails("call autocmd_get(#{group: 'abc', event: 'BufAdd'})",
|
||||
\ 'E367:')
|
||||
let cmd = "echo autocmd_get(#{group: 'TestAutoCmdFns', event: 'abc'})"
|
||||
call assert_fails(cmd, 'E216:')
|
||||
call assert_fails("call autocmd_get(#{group: 'abc'})", 'E367:')
|
||||
call assert_fails("echo autocmd_get(#{event: 'abc'})", 'E216:')
|
||||
|
||||
augroup TestAutoCmdFns
|
||||
au!
|
||||
augroup END
|
||||
call assert_equal([], autocmd_get(#{group: 'TestAutoCmdFns'}))
|
||||
|
||||
" Test for nested and once autocmds
|
||||
augroup TestAutoCmdFns
|
||||
au!
|
||||
autocmd VimSuspend * ++nested echo "suspend"
|
||||
autocmd VimResume * ++once echo "resume"
|
||||
augroup END
|
||||
|
||||
let expected = [
|
||||
\ {'cmd': 'echo "suspend"', 'group': 'TestAutoCmdFns', 'pattern': '*',
|
||||
\ 'nested': v:true, 'once': v:false, 'event': 'VimSuspend'},
|
||||
\ {'cmd': 'echo "resume"', 'group': 'TestAutoCmdFns', 'pattern': '*',
|
||||
\ 'nested': v:false, 'once': v:true, 'event': 'VimResume'}]
|
||||
call assert_equal(expected, autocmd_get(#{group: 'TestAutoCmdFns'}))
|
||||
|
||||
" Test for buffer-local autocmd
|
||||
augroup TestAutoCmdFns
|
||||
au!
|
||||
autocmd TextYankPost <buffer> echo "textyankpost"
|
||||
augroup END
|
||||
|
||||
let expected = [
|
||||
\ {'cmd': 'echo "textyankpost"', 'group': 'TestAutoCmdFns',
|
||||
\ 'pattern': '<buffer=' .. bufnr() .. '>', 'nested': v:false,
|
||||
\ 'once': v:false, 'bufnr': bufnr(), 'event': 'TextYankPost'}]
|
||||
call assert_equal(expected, autocmd_get(#{group: 'TestAutoCmdFns'}))
|
||||
|
||||
augroup TestAutoCmdFns
|
||||
au!
|
||||
augroup END
|
||||
augroup! TestAutoCmdFns
|
||||
augroup TestAutoCmdFns2
|
||||
au!
|
||||
augroup END
|
||||
augroup! TestAutoCmdFns2
|
||||
|
||||
call assert_fails("echo autocmd_get(#{group: []})", 'E730:')
|
||||
call assert_fails("echo autocmd_get(#{event: {}})", 'E731:')
|
||||
call assert_fails("echo autocmd_get([])", 'E1206:')
|
||||
endfunc
|
||||
|
||||
" Test for the autocmd_add() function
|
||||
func Test_autocmd_add()
|
||||
" Define a single autocmd in a group
|
||||
call autocmd_add([#{group: 'TestAcSet', event: 'BufAdd', pattern: '*.sh',
|
||||
\ cmd: 'echo "bufadd"', once: v:true, nested: v:true}])
|
||||
call assert_equal([#{cmd: 'echo "bufadd"', group: 'TestAcSet',
|
||||
\ pattern: '*.sh', nested: v:true, once: v:true,
|
||||
\ event: 'BufAdd'}], autocmd_get(#{group: 'TestAcSet'}))
|
||||
|
||||
" Define two autocmds in the same group
|
||||
call autocmd_delete([#{group: 'TestAcSet'}])
|
||||
call autocmd_add([#{group: 'TestAcSet', event: 'BufAdd', pattern: '*.sh',
|
||||
\ cmd: 'echo "bufadd"'},
|
||||
\ #{group: 'TestAcSet', event: 'BufEnter', pattern: '*.sh',
|
||||
\ cmd: 'echo "bufenter"'}])
|
||||
call assert_equal([
|
||||
\ #{cmd: 'echo "bufadd"', group: 'TestAcSet', pattern: '*.sh',
|
||||
\ nested: v:false, once: v:false, event: 'BufAdd'},
|
||||
\ #{cmd: 'echo "bufenter"', group: 'TestAcSet', pattern: '*.sh',
|
||||
\ nested: v:false, once: v:false, event: 'BufEnter'}],
|
||||
\ autocmd_get(#{group: 'TestAcSet'}))
|
||||
|
||||
" Define a buffer-local autocmd
|
||||
call autocmd_delete([#{group: 'TestAcSet'}])
|
||||
call autocmd_add([#{group: 'TestAcSet', event: 'CursorHold',
|
||||
\ bufnr: bufnr(), cmd: 'echo "cursorhold"'}])
|
||||
call assert_equal([
|
||||
\ #{cmd: 'echo "cursorhold"', group: 'TestAcSet',
|
||||
\ pattern: '<buffer=' .. bufnr() .. '>', nested: v:false,
|
||||
\ once: v:false, bufnr: bufnr(), event: 'CursorHold'}],
|
||||
\ autocmd_get(#{group: 'TestAcSet'}))
|
||||
|
||||
" Use an invalid buffer number
|
||||
call autocmd_delete([#{group: 'TestAcSet'}])
|
||||
call autocmd_add([#{group: 'TestAcSet', event: 'BufEnter',
|
||||
\ bufnr: -1, cmd: 'echo "bufenter"'}])
|
||||
let l = [#{group: 'TestAcSet', event: 'BufAdd', bufnr: 9999,
|
||||
\ cmd: 'echo "bufadd"'}]
|
||||
call assert_fails("echo autocmd_add(l)", 'E680:')
|
||||
let l = [#{group: 'TestAcSet', event: 'BufRead', bufnr: [],
|
||||
\ cmd: 'echo "bufread"'}]
|
||||
call assert_fails("echo autocmd_add(l)", 'E745:')
|
||||
call assert_equal([], autocmd_get(#{group: 'TestAcSet'}))
|
||||
|
||||
" Add two commands to the same group, event and pattern
|
||||
call autocmd_delete([#{group: 'TestAcSet'}])
|
||||
call autocmd_add([#{group: 'TestAcSet', event: 'BufUnload',
|
||||
\ pattern: 'abc', cmd: 'echo "cmd1"'}])
|
||||
call autocmd_add([#{group: 'TestAcSet', event: 'BufUnload',
|
||||
\ pattern: 'abc', cmd: 'echo "cmd2"'}])
|
||||
call assert_equal([
|
||||
\ #{cmd: 'echo "cmd1"', group: 'TestAcSet', pattern: 'abc',
|
||||
\ nested: v:false, once: v:false, event: 'BufUnload'},
|
||||
\ #{cmd: 'echo "cmd2"', group: 'TestAcSet', pattern: 'abc',
|
||||
\ nested: v:false, once: v:false, event: 'BufUnload'}],
|
||||
\ autocmd_get(#{group: 'TestAcSet'}))
|
||||
|
||||
" When adding a new autocmd, if the autocmd 'group' is not specified, then
|
||||
" the current autocmd group should be used.
|
||||
call autocmd_delete([#{group: 'TestAcSet'}])
|
||||
augroup TestAcSet
|
||||
call autocmd_add([#{event: 'BufHidden', pattern: 'abc', cmd: 'echo "abc"'}])
|
||||
augroup END
|
||||
call assert_equal([
|
||||
\ #{cmd: 'echo "abc"', group: 'TestAcSet', pattern: 'abc',
|
||||
\ nested: v:false, once: v:false, event: 'BufHidden'}],
|
||||
\ autocmd_get(#{group: 'TestAcSet'}))
|
||||
|
||||
let l = [#{group: 'TestAcSet', event: 'abc', pattern: '*.sh',
|
||||
\ cmd: 'echo "bufadd"'}]
|
||||
call assert_fails('call autocmd_add(l)', 'E216:')
|
||||
|
||||
call assert_fails("call autocmd_add({})", 'E1211:')
|
||||
call assert_equal(v:false, autocmd_add(test_null_list()))
|
||||
call assert_true(autocmd_add([[]]))
|
||||
call assert_true(autocmd_add([test_null_dict()]))
|
||||
|
||||
augroup TestAcSet
|
||||
au!
|
||||
augroup END
|
||||
|
||||
call autocmd_add([#{group: 'TestAcSet'}])
|
||||
call autocmd_add([#{group: 'TestAcSet', event: 'BufAdd'}])
|
||||
call autocmd_add([#{group: 'TestAcSet', pat: '*.sh'}])
|
||||
call autocmd_add([#{group: 'TestAcSet', cmd: 'echo "a"'}])
|
||||
call autocmd_add([#{group: 'TestAcSet', event: 'BufAdd', pat: '*.sh'}])
|
||||
call autocmd_add([#{group: 'TestAcSet', event: 'BufAdd', cmd: 'echo "a"'}])
|
||||
call autocmd_add([#{group: 'TestAcSet', pat: '*.sh', cmd: 'echo "a"'}])
|
||||
call assert_equal([], autocmd_get(#{group: 'TestAcSet'}))
|
||||
|
||||
augroup! TestAcSet
|
||||
endfunc
|
||||
|
||||
" Test for deleting autocmd events and groups
|
||||
func Test_autocmd_delete()
|
||||
" Delete an event in an autocmd group
|
||||
augroup TestAcSet
|
||||
au!
|
||||
au BufAdd *.sh echo "bufadd"
|
||||
au BufEnter *.sh echo "bufenter"
|
||||
augroup END
|
||||
call autocmd_delete([#{group: 'TestAcSet', event: 'BufAdd'}])
|
||||
call assert_equal([#{cmd: 'echo "bufenter"', group: 'TestAcSet',
|
||||
\ pattern: '*.sh', nested: v:false, once: v:false,
|
||||
\ event: 'BufEnter'}], autocmd_get(#{group: 'TestAcSet'}))
|
||||
|
||||
" Delete all the events in an autocmd group
|
||||
augroup TestAcSet
|
||||
au BufAdd *.sh echo "bufadd"
|
||||
augroup END
|
||||
call autocmd_delete([#{group: 'TestAcSet', event: '*'}])
|
||||
call assert_equal([], autocmd_get(#{group: 'TestAcSet'}))
|
||||
|
||||
" Delete a non-existing autocmd group
|
||||
call assert_fails("call autocmd_delete([#{group: 'abc'}])", 'E367:')
|
||||
" Delete a non-existing autocmd event
|
||||
let l = [#{group: 'TestAcSet', event: 'abc'}]
|
||||
call assert_fails("call autocmd_delete(l)", 'E216:')
|
||||
" Delete a non-existing autocmd pattern
|
||||
let l = [#{group: 'TestAcSet', event: 'BufAdd', pat: 'abc'}]
|
||||
call assert_true(autocmd_delete(l))
|
||||
|
||||
" Delete an autocmd group
|
||||
augroup TestAcSet
|
||||
au!
|
||||
au BufAdd *.sh echo "bufadd"
|
||||
au BufEnter *.sh echo "bufenter"
|
||||
augroup END
|
||||
call autocmd_delete([#{group: 'TestAcSet'}])
|
||||
call assert_fails("call autocmd_get(#{group: 'TestAcSet'})", 'E367:')
|
||||
|
||||
call assert_true(autocmd_delete([[]]))
|
||||
call assert_true(autocmd_delete([test_null_dict()]))
|
||||
endfunc
|
||||
|
||||
" vim: shiftwidth=2 sts=2 expandtab
|
||||
|
|
|
@ -304,6 +304,18 @@ def Test_assert_report()
|
|||
v9.CheckDefAndScriptFailure(['assert_report([1, 2])'], ['E1013: Argument 1: type mismatch, expected string but got list<number>', 'E1174: String required for argument 1'])
|
||||
enddef
|
||||
|
||||
def Test_autocmd_add()
|
||||
v9.CheckDefAndScriptFailure(['autocmd_add({})'], ['E1013: Argument 1: type mismatch, expected list<any> but got dict<unknown>', 'E1211: List required for argument 1'])
|
||||
enddef
|
||||
|
||||
def Test_autocmd_delete()
|
||||
v9.CheckDefAndScriptFailure(['autocmd_delete({})'], ['E1013: Argument 1: type mismatch, expected list<any> but got dict<unknown>', 'E1211: List required for argument 1'])
|
||||
enddef
|
||||
|
||||
def Test_autocmd_get()
|
||||
v9.CheckDefAndScriptFailure(['autocmd_get(10)'], ['E1013: Argument 1: type mismatch, expected dict<any> but got number', 'E1206: Dictionary required for argument 1'])
|
||||
enddef
|
||||
|
||||
def Test_balloon_show()
|
||||
CheckGui
|
||||
CheckFeature balloon_eval
|
||||
|
|
|
@ -746,6 +746,8 @@ static char *(features[]) =
|
|||
|
||||
static int included_patches[] =
|
||||
{ /* Add new patch number below this line */
|
||||
/**/
|
||||
4981,
|
||||
/**/
|
||||
4980,
|
||||
/**/
|
||||
|
|
Loading…
Add table
Reference in a new issue