forked from aniani/vim
patch 8.2.5030: autocmd_add() can only handle one event and pattern
Problem: autocmd_add() can only handle one event and pattern. Solution: Support a list of events and patterns. (Yegappan Lakshmanan, closes #10483)
This commit is contained in:
committed by
Bram Moolenaar
parent
cfe456543e
commit
e0ff3a7de6
@@ -938,7 +938,8 @@ autocmd_add({acmds}) *autocmd_add()*
|
|||||||
item is ignored.
|
item is ignored.
|
||||||
cmd Ex command to execute for this autocmd event
|
cmd Ex command to execute for this autocmd event
|
||||||
event autocmd event name. Refer to |autocmd-events|.
|
event autocmd event name. Refer to |autocmd-events|.
|
||||||
TODO: currently only accepts one event.
|
This can be either a String with a single
|
||||||
|
event name or a List of event names.
|
||||||
group autocmd group name. Refer to |autocmd-groups|.
|
group autocmd group name. Refer to |autocmd-groups|.
|
||||||
If this group doesn't exist then it is
|
If this group doesn't exist then it is
|
||||||
created. If not specified or empty, then the
|
created. If not specified or empty, then the
|
||||||
@@ -950,7 +951,9 @@ autocmd_add({acmds}) *autocmd_add()*
|
|||||||
|autocmd-once|.
|
|autocmd-once|.
|
||||||
pattern autocmd pattern string. Refer to
|
pattern autocmd pattern string. Refer to
|
||||||
|autocmd-patterns|. If "bufnr" item is
|
|autocmd-patterns|. If "bufnr" item is
|
||||||
present, then this item is ignored.
|
present, then this item is ignored. This can
|
||||||
|
be a String with a single pattern or a List of
|
||||||
|
patterns.
|
||||||
replace boolean flag, set to v:true to remove all the
|
replace boolean flag, set to v:true to remove all the
|
||||||
commands associated with the specified autocmd
|
commands associated with the specified autocmd
|
||||||
event and group and add the {cmd}. This is
|
event and group and add the {cmd}. This is
|
||||||
|
177
src/autocmd.c
177
src/autocmd.c
@@ -2754,16 +2754,22 @@ theend:
|
|||||||
static void
|
static void
|
||||||
autocmd_add_or_delete(typval_T *argvars, typval_T *rettv, int delete)
|
autocmd_add_or_delete(typval_T *argvars, typval_T *rettv, int delete)
|
||||||
{
|
{
|
||||||
list_T *event_list;
|
list_T *aucmd_list;
|
||||||
listitem_T *li;
|
listitem_T *li;
|
||||||
dict_T *event_dict;
|
dict_T *event_dict;
|
||||||
|
dictitem_T *di;
|
||||||
char_u *event_name = NULL;
|
char_u *event_name = NULL;
|
||||||
|
list_T *event_list;
|
||||||
|
listitem_T *eli;
|
||||||
event_T event;
|
event_T event;
|
||||||
char_u *group_name = NULL;
|
char_u *group_name = NULL;
|
||||||
int group;
|
int group;
|
||||||
char_u *pat = NULL;
|
char_u *pat = NULL;
|
||||||
|
list_T *pat_list;
|
||||||
|
listitem_T *pli;
|
||||||
char_u *cmd = NULL;
|
char_u *cmd = NULL;
|
||||||
char_u *end;
|
char_u *end;
|
||||||
|
char_u *p;
|
||||||
int once;
|
int once;
|
||||||
int nested;
|
int nested;
|
||||||
int replace; // replace the cmd for a group/event
|
int replace; // replace the cmd for a group/event
|
||||||
@@ -2776,16 +2782,18 @@ autocmd_add_or_delete(typval_T *argvars, typval_T *rettv, int delete)
|
|||||||
if (check_for_list_arg(argvars, 0) == FAIL)
|
if (check_for_list_arg(argvars, 0) == FAIL)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
event_list = argvars[0].vval.v_list;
|
aucmd_list = argvars[0].vval.v_list;
|
||||||
if (event_list == NULL)
|
if (aucmd_list == NULL)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
FOR_ALL_LIST_ITEMS(event_list, li)
|
FOR_ALL_LIST_ITEMS(aucmd_list, li)
|
||||||
{
|
{
|
||||||
VIM_CLEAR(event_name);
|
|
||||||
VIM_CLEAR(group_name);
|
VIM_CLEAR(group_name);
|
||||||
VIM_CLEAR(pat);
|
|
||||||
VIM_CLEAR(cmd);
|
VIM_CLEAR(cmd);
|
||||||
|
event_name = NULL;
|
||||||
|
event_list = NULL;
|
||||||
|
pat = NULL;
|
||||||
|
pat_list = NULL;
|
||||||
|
|
||||||
if (li->li_tv.v_type != VAR_DICT)
|
if (li->li_tv.v_type != VAR_DICT)
|
||||||
continue;
|
continue;
|
||||||
@@ -2794,29 +2802,31 @@ autocmd_add_or_delete(typval_T *argvars, typval_T *rettv, int delete)
|
|||||||
if (event_dict == NULL)
|
if (event_dict == NULL)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
event_name = dict_get_string(event_dict, (char_u *)"event", TRUE);
|
di = dict_find(event_dict, (char_u *)"event", -1);
|
||||||
if (event_name == NULL)
|
if (di != NULL)
|
||||||
{
|
{
|
||||||
if (delete)
|
if (di->di_tv.v_type == VAR_STRING)
|
||||||
// if the event name is not specified, delete all the events
|
{
|
||||||
event = NUM_EVENTS;
|
event_name = di->di_tv.vval.v_string;
|
||||||
else
|
if (event_name == NULL)
|
||||||
continue;
|
{
|
||||||
}
|
emsg(_(e_string_required));
|
||||||
else
|
continue;
|
||||||
{
|
}
|
||||||
if (delete && event_name[0] == '*' && event_name[1] == NUL)
|
}
|
||||||
// if the event name is '*', delete all the events
|
else if (di->di_tv.v_type == VAR_LIST)
|
||||||
event = NUM_EVENTS;
|
{
|
||||||
|
event_list = di->di_tv.vval.v_list;
|
||||||
|
if (event_list == NULL)
|
||||||
|
{
|
||||||
|
emsg(_(e_list_required));
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
event = event_name2nr(event_name, &end);
|
emsg(_(e_string_or_list_expected));
|
||||||
if (event == NUM_EVENTS)
|
continue;
|
||||||
{
|
|
||||||
semsg(_(e_no_such_event_str), event_name);
|
|
||||||
retval = VVAL_FALSE;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2859,21 +2869,40 @@ autocmd_add_or_delete(typval_T *argvars, typval_T *rettv, int delete)
|
|||||||
if (bnum == -1)
|
if (bnum == -1)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
pat = alloc(128 + 1);
|
vim_snprintf((char *)IObuff, IOSIZE, "<buffer=%d>", (int)bnum);
|
||||||
if (pat == NULL)
|
pat = IObuff;
|
||||||
continue;
|
|
||||||
vim_snprintf((char *)pat, 128, "<buffer=%d>", (int)bnum);
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
pat = dict_get_string(event_dict, (char_u *)"pattern", TRUE);
|
di = dict_find(event_dict, (char_u *)"pattern", -1);
|
||||||
if (pat == NULL)
|
if (di != NULL)
|
||||||
{
|
{
|
||||||
if (delete)
|
if (di->di_tv.v_type == VAR_STRING)
|
||||||
pat = vim_strsave((char_u *)"");
|
{
|
||||||
|
pat = di->di_tv.vval.v_string;
|
||||||
|
if (pat == NULL)
|
||||||
|
{
|
||||||
|
emsg(_(e_string_required));
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (di->di_tv.v_type == VAR_LIST)
|
||||||
|
{
|
||||||
|
pat_list = di->di_tv.vval.v_list;
|
||||||
|
if (pat_list == NULL)
|
||||||
|
{
|
||||||
|
emsg(_(e_list_required));
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
else
|
else
|
||||||
|
{
|
||||||
|
emsg(_(e_string_or_list_expected));
|
||||||
continue;
|
continue;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
else if (delete)
|
||||||
|
pat = (char_u *)"";
|
||||||
}
|
}
|
||||||
|
|
||||||
once = dict_get_bool(event_dict, (char_u *)"once", FALSE);
|
once = dict_get_bool(event_dict, (char_u *)"once", FALSE);
|
||||||
@@ -2891,9 +2920,10 @@ autocmd_add_or_delete(typval_T *argvars, typval_T *rettv, int delete)
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (event == NUM_EVENTS)
|
if (delete && (event_name == NULL
|
||||||
|
|| (event_name[0] == '*' && event_name[1] == NUL)))
|
||||||
{
|
{
|
||||||
// event is '*', apply for all the events
|
// if the event name is not specified or '*', delete all the events
|
||||||
for (event = (event_T)0; (int)event < NUM_EVENTS;
|
for (event = (event_T)0; (int)event < NUM_EVENTS;
|
||||||
event = (event_T)((int)event + 1))
|
event = (event_T)((int)event + 1))
|
||||||
{
|
{
|
||||||
@@ -2907,11 +2937,76 @@ autocmd_add_or_delete(typval_T *argvars, typval_T *rettv, int delete)
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (do_autocmd_event(event, pat, once, nested, cmd,
|
eli = NULL;
|
||||||
delete | replace, group, 0) == FAIL)
|
end = NULL;
|
||||||
|
while (TRUE)
|
||||||
{
|
{
|
||||||
retval = VVAL_FALSE;
|
if (event_list != NULL)
|
||||||
break;
|
{
|
||||||
|
if (eli == NULL)
|
||||||
|
eli = event_list->lv_first;
|
||||||
|
else
|
||||||
|
eli = eli->li_next;
|
||||||
|
if (eli == NULL)
|
||||||
|
break;
|
||||||
|
if (eli->li_tv.v_type != VAR_STRING
|
||||||
|
|| eli->li_tv.vval.v_string == NULL)
|
||||||
|
{
|
||||||
|
emsg(_(e_string_required));
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
p = eli->li_tv.vval.v_string;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (end == NULL)
|
||||||
|
p = end = event_name;
|
||||||
|
if (end == NULL || *end == NUL)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (p == NULL)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
event = event_name2nr(p, &end);
|
||||||
|
if (event == NUM_EVENTS || *end != NUL)
|
||||||
|
{
|
||||||
|
semsg(_(e_no_such_event_str), p);
|
||||||
|
retval = VVAL_FALSE;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (pat != NULL)
|
||||||
|
{
|
||||||
|
if (do_autocmd_event(event, pat, once, nested, cmd,
|
||||||
|
delete | replace, group, 0) == FAIL)
|
||||||
|
{
|
||||||
|
retval = VVAL_FALSE;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (pat_list != NULL)
|
||||||
|
{
|
||||||
|
FOR_ALL_LIST_ITEMS(pat_list, pli)
|
||||||
|
{
|
||||||
|
if (pli->li_tv.v_type != VAR_STRING
|
||||||
|
|| pli->li_tv.vval.v_string == NULL)
|
||||||
|
{
|
||||||
|
emsg(_(e_string_required));
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (do_autocmd_event(event,
|
||||||
|
pli->li_tv.vval.v_string, once, nested,
|
||||||
|
cmd, delete | replace, group, 0) ==
|
||||||
|
FAIL)
|
||||||
|
{
|
||||||
|
retval = VVAL_FALSE;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (retval == VVAL_FALSE)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (event_name != NULL)
|
||||||
|
p = end;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2925,9 +3020,7 @@ autocmd_add_or_delete(typval_T *argvars, typval_T *rettv, int delete)
|
|||||||
au_del_group(group_name);
|
au_del_group(group_name);
|
||||||
}
|
}
|
||||||
|
|
||||||
VIM_CLEAR(event_name);
|
|
||||||
VIM_CLEAR(group_name);
|
VIM_CLEAR(group_name);
|
||||||
VIM_CLEAR(pat);
|
|
||||||
VIM_CLEAR(cmd);
|
VIM_CLEAR(cmd);
|
||||||
|
|
||||||
current_augroup = save_augroup;
|
current_augroup = save_augroup;
|
||||||
|
@@ -1184,7 +1184,7 @@ EXTERN char e_invalid_argument_str[]
|
|||||||
INIT(= N_("E475: Invalid argument: %s"));
|
INIT(= N_("E475: Invalid argument: %s"));
|
||||||
EXTERN char e_invalid_value_for_argument_str[]
|
EXTERN char e_invalid_value_for_argument_str[]
|
||||||
INIT(= N_("E475: Invalid value for argument %s"));
|
INIT(= N_("E475: Invalid value for argument %s"));
|
||||||
#if defined(FEAT_JOB_CHANNEL) || defined(FEAT_PROP_POPUP)
|
#if defined(FEAT_JOB_CHANNEL) || defined(FEAT_PROP_POPUP) || defined(FEAT_EVAL)
|
||||||
EXTERN char e_invalid_value_for_argument_str_str[]
|
EXTERN char e_invalid_value_for_argument_str_str[]
|
||||||
INIT(= N_("E475: Invalid value for argument %s: %s"));
|
INIT(= N_("E475: Invalid value for argument %s: %s"));
|
||||||
#endif
|
#endif
|
||||||
@@ -3280,7 +3280,7 @@ EXTERN char e_atom_engine_must_be_at_start_of_pattern[]
|
|||||||
INIT(= N_("E1281: Atom '\\%%#=%c' must be at the start of the pattern"));
|
INIT(= N_("E1281: Atom '\\%%#=%c' must be at the start of the pattern"));
|
||||||
#ifdef FEAT_EVAL
|
#ifdef FEAT_EVAL
|
||||||
EXTERN char e_bitshift_ops_must_be_number[]
|
EXTERN char e_bitshift_ops_must_be_number[]
|
||||||
INIT(= N_("E1282: bitshift operands must be numbers"));
|
INIT(= N_("E1282: Bitshift operands must be numbers"));
|
||||||
EXTERN char e_bitshift_ops_must_be_postive[]
|
EXTERN char e_bitshift_ops_must_be_postive[]
|
||||||
INIT(= N_("E1283: bitshift amount must be a positive number"));
|
INIT(= N_("E1283: Bitshift amount must be a positive number"));
|
||||||
#endif
|
#endif
|
||||||
|
@@ -3429,6 +3429,83 @@ func Test_autocmd_add()
|
|||||||
\ cmd: 'echo "bufadd"'}]
|
\ cmd: 'echo "bufadd"'}]
|
||||||
call assert_fails('call autocmd_add(l)', 'E216:')
|
call assert_fails('call autocmd_add(l)', 'E216:')
|
||||||
|
|
||||||
|
" Test for using a list of events and patterns
|
||||||
|
call autocmd_delete([#{group: 'TestAcSet'}])
|
||||||
|
let l = [#{group: 'TestAcSet', event: ['BufEnter', 'BufLeave'],
|
||||||
|
\ pattern: ['*.py', '*.sh'], cmd: 'echo "bufcmds"'}]
|
||||||
|
call autocmd_add(l)
|
||||||
|
call assert_equal([
|
||||||
|
\ #{cmd: 'echo "bufcmds"', group: 'TestAcSet', pattern: '*.py',
|
||||||
|
\ nested: v:false, once: v:false, event: 'BufEnter'},
|
||||||
|
\ #{cmd: 'echo "bufcmds"', group: 'TestAcSet', pattern: '*.sh',
|
||||||
|
\ nested: v:false, once: v:false, event: 'BufEnter'},
|
||||||
|
\ #{cmd: 'echo "bufcmds"', group: 'TestAcSet', pattern: '*.py',
|
||||||
|
\ nested: v:false, once: v:false, event: 'BufLeave'},
|
||||||
|
\ #{cmd: 'echo "bufcmds"', group: 'TestAcSet', pattern: '*.sh',
|
||||||
|
\ nested: v:false, once: v:false, event: 'BufLeave'}],
|
||||||
|
\ autocmd_get(#{group: 'TestAcSet'}))
|
||||||
|
|
||||||
|
" Test for invalid values for 'event' item
|
||||||
|
call autocmd_delete([#{group: 'TestAcSet'}])
|
||||||
|
let l = [#{group: 'TestAcSet', event: test_null_string(),
|
||||||
|
\ pattern: "*.py", cmd: 'echo "bufcmds"'}]
|
||||||
|
call assert_fails('call autocmd_add(l)', 'E928:')
|
||||||
|
let l = [#{group: 'TestAcSet', event: test_null_list(),
|
||||||
|
\ pattern: "*.py", cmd: 'echo "bufcmds"'}]
|
||||||
|
call assert_fails('call autocmd_add(l)', 'E714:')
|
||||||
|
let l = [#{group: 'TestAcSet', event: {},
|
||||||
|
\ pattern: "*.py", cmd: 'echo "bufcmds"'}]
|
||||||
|
call assert_fails('call autocmd_add(l)', 'E777:')
|
||||||
|
let l = [#{group: 'TestAcSet', event: [{}],
|
||||||
|
\ pattern: "*.py", cmd: 'echo "bufcmds"'}]
|
||||||
|
call assert_fails('call autocmd_add(l)', 'E928:')
|
||||||
|
let l = [#{group: 'TestAcSet', event: [test_null_string()],
|
||||||
|
\ pattern: "*.py", cmd: 'echo "bufcmds"'}]
|
||||||
|
call assert_fails('call autocmd_add(l)', 'E928:')
|
||||||
|
let l = [#{group: 'TestAcSet', event: 'BufEnter,BufLeave',
|
||||||
|
\ pattern: '*.py', cmd: 'echo "bufcmds"'}]
|
||||||
|
call assert_fails('call autocmd_add(l)', 'E216:')
|
||||||
|
let l = [#{group: 'TestAcSet', event: [],
|
||||||
|
\ pattern: "*.py", cmd: 'echo "bufcmds"'}]
|
||||||
|
call autocmd_add(l)
|
||||||
|
let l = [#{group: 'TestAcSet', event: [""],
|
||||||
|
\ pattern: "*.py", cmd: 'echo "bufcmds"'}]
|
||||||
|
call assert_fails('call autocmd_add(l)', 'E216:')
|
||||||
|
let l = [#{group: 'TestAcSet', event: "",
|
||||||
|
\ pattern: "*.py", cmd: 'echo "bufcmds"'}]
|
||||||
|
call autocmd_add(l)
|
||||||
|
call assert_equal([], autocmd_get(#{group: 'TestAcSet'}))
|
||||||
|
|
||||||
|
" Test for invalid values for 'pattern' item
|
||||||
|
let l = [#{group: 'TestAcSet', event: "BufEnter",
|
||||||
|
\ pattern: test_null_string(), cmd: 'echo "bufcmds"'}]
|
||||||
|
let l = [#{group: 'TestAcSet', event: "BufEnter",
|
||||||
|
\ pattern: test_null_list(), cmd: 'echo "bufcmds"'}]
|
||||||
|
call assert_fails('call autocmd_add(l)', 'E714:')
|
||||||
|
let l = [#{group: 'TestAcSet', event: "BufEnter",
|
||||||
|
\ pattern: {}, cmd: 'echo "bufcmds"'}]
|
||||||
|
call assert_fails('call autocmd_add(l)', 'E777:')
|
||||||
|
let l = [#{group: 'TestAcSet', event: "BufEnter",
|
||||||
|
\ pattern: [{}], cmd: 'echo "bufcmds"'}]
|
||||||
|
call assert_fails('call autocmd_add(l)', 'E928:')
|
||||||
|
let l = [#{group: 'TestAcSet', event: "BufEnter",
|
||||||
|
\ pattern: [test_null_string()], cmd: 'echo "bufcmds"'}]
|
||||||
|
call assert_fails('call autocmd_add(l)', 'E928:')
|
||||||
|
let l = [#{group: 'TestAcSet', event: "BufEnter",
|
||||||
|
\ pattern: [], cmd: 'echo "bufcmds"'}]
|
||||||
|
call autocmd_add(l)
|
||||||
|
let l = [#{group: 'TestAcSet', event: "BufEnter",
|
||||||
|
\ pattern: [""], cmd: 'echo "bufcmds"'}]
|
||||||
|
call autocmd_add(l)
|
||||||
|
let l = [#{group: 'TestAcSet', event: "BufEnter",
|
||||||
|
\ pattern: "", cmd: 'echo "bufcmds"'}]
|
||||||
|
call autocmd_add(l)
|
||||||
|
call assert_equal([], autocmd_get(#{group: 'TestAcSet'}))
|
||||||
|
|
||||||
|
let l = [#{group: 'TestAcSet', event: 'BufEnter,abc,BufLeave',
|
||||||
|
\ pattern: '*.py', cmd: 'echo "bufcmds"'}]
|
||||||
|
call assert_fails('call autocmd_add(l)', 'E216:')
|
||||||
|
|
||||||
call assert_fails("call autocmd_add({})", 'E1211:')
|
call assert_fails("call autocmd_add({})", 'E1211:')
|
||||||
call assert_equal(v:false, autocmd_add(test_null_list()))
|
call assert_equal(v:false, autocmd_add(test_null_list()))
|
||||||
call assert_true(autocmd_add([[]]))
|
call assert_true(autocmd_add([[]]))
|
||||||
|
@@ -734,6 +734,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 */
|
||||||
|
/**/
|
||||||
|
5030,
|
||||||
/**/
|
/**/
|
||||||
5029,
|
5029,
|
||||||
/**/
|
/**/
|
||||||
|
Reference in New Issue
Block a user