summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorYegappan Lakshmanan <yegappan@yahoo.com>2022-05-27 18:05:33 +0100
committerBram Moolenaar <Bram@vim.org>2022-05-27 18:05:33 +0100
commite0ff3a7de6030b73d94121626deb8229e66e82b2 (patch)
treead08f28abf01c743f8bae5892920c6c45603c00a
parentcfe456543e840d133399551f8626d985e1fb1958 (diff)
patch 8.2.5030: autocmd_add() can only handle one event and patternv8.2.5030
Problem: autocmd_add() can only handle one event and pattern. Solution: Support a list of events and patterns. (Yegappan Lakshmanan, closes #10483)
-rw-r--r--runtime/doc/builtin.txt7
-rw-r--r--src/autocmd.c175
-rw-r--r--src/errors.h6
-rw-r--r--src/testdir/test_autocmd.vim77
-rw-r--r--src/version.c2
5 files changed, 221 insertions, 46 deletions
diff --git a/runtime/doc/builtin.txt b/runtime/doc/builtin.txt
index 0aa2effcd0..371670ceba 100644
--- a/runtime/doc/builtin.txt
+++ b/runtime/doc/builtin.txt
@@ -938,7 +938,8 @@ autocmd_add({acmds}) *autocmd_add()*
item is ignored.
cmd Ex command to execute for this autocmd event
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|.
If this group doesn't exist then it is
created. If not specified or empty, then the
@@ -950,7 +951,9 @@ autocmd_add({acmds}) *autocmd_add()*
|autocmd-once|.
pattern autocmd pattern string. Refer to
|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
commands associated with the specified autocmd
event and group and add the {cmd}. This is
diff --git a/src/autocmd.c b/src/autocmd.c
index c9733ba5d3..06cd028501 100644
--- a/src/autocmd.c
+++ b/src/autocmd.c
@@ -2754,16 +2754,22 @@ theend:
static void
autocmd_add_or_delete(typval_T *argvars, typval_T *rettv, int delete)
{
- list_T *event_list;
+ list_T *aucmd_list;
listitem_T *li;
dict_T *event_dict;
+ dictitem_T *di;
char_u *event_name = NULL;
+ list_T *event_list;
+ listitem_T *eli;
event_T event;
char_u *group_name = NULL;
int group;
char_u *pat = NULL;
+ list_T *pat_list;
+ listitem_T *pli;
char_u *cmd = NULL;
char_u *end;
+ char_u *p;
int once;
int nested;
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)
return;
- event_list = argvars[0].vval.v_list;
- if (event_list == NULL)
+ aucmd_list = argvars[0].vval.v_list;
+ if (aucmd_list == NULL)
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(pat);
VIM_CLEAR(cmd);
+ event_name = NULL;
+ event_list = NULL;
+ pat = NULL;
+ pat_list = NULL;
if (li->li_tv.v_type != VAR_DICT)
continue;
@@ -2794,30 +2802,32 @@ autocmd_add_or_delete(typval_T *argvars, typval_T *rettv, int delete)
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
+ di = dict_find(event_dict, (char_u *)"event", -1);
+ if (di != NULL)
{
- if (delete && event_name[0] == '*' && event_name[1] == NUL)
- // if the event name is '*', delete all the events
- event = NUM_EVENTS;
- else
+ if (di->di_tv.v_type == VAR_STRING)
{
- event = event_name2nr(event_name, &end);
- if (event == NUM_EVENTS)
+ event_name = di->di_tv.vval.v_string;
+ if (event_name == NULL)
{
- semsg(_(e_no_such_event_str), event_name);
- retval = VVAL_FALSE;
- break;
+ emsg(_(e_string_required));
+ continue;
+ }
+ }
+ else if (di->di_tv.v_type == VAR_LIST)
+ {
+ event_list = di->di_tv.vval.v_list;
+ if (event_list == NULL)
+ {
+ emsg(_(e_list_required));
+ continue;
}
}
+ else
+ {
+ emsg(_(e_string_or_list_expected));
+ continue;
+ }
}
group_name = dict_get_string(event_dict, (char_u *)"group", TRUE);
@@ -2859,21 +2869,40 @@ autocmd_add_or_delete(typval_T *argvars, typval_T *rettv, int delete)
if (bnum == -1)
continue;
- pat = alloc(128 + 1);
- if (pat == NULL)
- continue;
- vim_snprintf((char *)pat, 128, "<buffer=%d>", (int)bnum);
+ vim_snprintf((char *)IObuff, IOSIZE, "<buffer=%d>", (int)bnum);
+ pat = IObuff;
}
else
{
- pat = dict_get_string(event_dict, (char_u *)"pattern", TRUE);
- if (pat == NULL)
+ di = dict_find(event_dict, (char_u *)"pattern", -1);
+ if (di != NULL)
{
- if (delete)
- pat = vim_strsave((char_u *)"");
+ if (di->di_tv.v_type == VAR_STRING)
+ {
+ 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
+ {
+ emsg(_(e_string_or_list_expected));
continue;
+ }
}
+ else if (delete)
+ pat = (char_u *)"";
}
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;
}
- 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;
event = (event_T)((int)event + 1))
{
@@ -2907,11 +2937,76 @@ autocmd_add_or_delete(typval_T *argvars, typval_T *rettv, int delete)
}
else
{
- if (do_autocmd_event(event, pat, once, nested, cmd,
- delete | replace, group, 0) == FAIL)
+ eli = NULL;
+ end = NULL;
+ while (TRUE)
{
- retval = VVAL_FALSE;
- break;
+ if (event_list != NULL)
+ {
+ 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);
}
- VIM_CLEAR(event_name);
VIM_CLEAR(group_name);
- VIM_CLEAR(pat);
VIM_CLEAR(cmd);
current_augroup = save_augroup;
diff --git a/src/errors.h b/src/errors.h
index 4e02986a77..9bdc77d90d 100644
--- a/src/errors.h
+++ b/src/errors.h
@@ -1184,7 +1184,7 @@ EXTERN char e_invalid_argument_str[]
INIT(= N_("E475: Invalid argument: %s"));
EXTERN char e_invalid_value_for_argument_str[]
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[]
INIT(= N_("E475: Invalid value for argument %s: %s"));
#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"));
#ifdef FEAT_EVAL
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[]
- INIT(= N_("E1283: bitshift amount must be a positive number"));
+ INIT(= N_("E1283: Bitshift amount must be a positive number"));
#endif
diff --git a/src/testdir/test_autocmd.vim b/src/testdir/test_autocmd.vim
index e3df115a6d..0aaa968c88 100644
--- a/src/testdir/test_autocmd.vim
+++ b/src/testdir/test_autocmd.vim
@@ -3429,6 +3429,83 @@ func Test_autocmd_add()
\ cmd: 'echo "bufadd"'}]
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_equal(v:false, autocmd_add(test_null_list()))
call assert_true(autocmd_add([[]]))
diff --git a/src/version.c b/src/version.c
index cc9cb49b49..cc3542a314 100644
--- a/src/version.c
+++ b/src/version.c
@@ -735,6 +735,8 @@ static char *(features[]) =
static int included_patches[] =
{ /* Add new patch number below this line */
/**/
+ 5030,
+/**/
5029,
/**/
5028,