0
0
mirror of https://github.com/vim/vim.git synced 2025-09-29 04:34:16 -04: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:
Yegappan Lakshmanan
2022-05-19 10:31:47 +01:00
committed by Bram Moolenaar
parent aaadb5b6f7
commit 1755a91851
9 changed files with 801 additions and 1 deletions

View File

@@ -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