Patch 8.2.5030

9 views
Skip to first unread message

Bram Moolenaar

unread,
May 27, 2022, 1:06:49 PM5/27/22
to vim...@googlegroups.com

Patch 8.2.5030
Problem: autocmd_add() can only handle one event and pattern.
Solution: Support a list of events and patterns. (Yegappan Lakshmanan,
closes #10483)
Files: runtime/doc/builtin.txt, src/autocmd.c, src/errors.h,
src/testdir/test_autocmd.vim


*** ../vim-8.2.5029/runtime/doc/builtin.txt 2022-05-26 12:10:33.589893490 +0100
--- runtime/doc/builtin.txt 2022-05-27 17:57:45.760052327 +0100
***************
*** 938,944 ****
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.
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
--- 938,945 ----
item is ignored.
cmd Ex command to execute for this autocmd event
event autocmd event name. Refer to |autocmd-events|.
! 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,956 ****
|autocmd-once|.
pattern autocmd pattern string. Refer to
|autocmd-patterns|. If "bufnr" item is
! present, then this item is ignored.
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
--- 951,959 ----
|autocmd-once|.
pattern autocmd pattern string. Refer to
|autocmd-patterns|. If "bufnr" item is
! 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
*** ../vim-8.2.5029/src/autocmd.c 2022-05-24 11:40:07.514685757 +0100
--- src/autocmd.c 2022-05-27 17:57:45.764052324 +0100
***************
*** 2754,2769 ****
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 replace; // replace the cmd for a group/event
--- 2754,2775 ----
static void
autocmd_add_or_delete(typval_T *argvars, typval_T *rettv, int delete)
{
! 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,2791 ****
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;
--- 2782,2799 ----
if (check_for_list_arg(argvars, 0) == FAIL)
return;

! aucmd_list = argvars[0].vval.v_list;
! if (aucmd_list == NULL)
return;

! FOR_ALL_LIST_ITEMS(aucmd_list, li)
{
VIM_CLEAR(group_name);
VIM_CLEAR(cmd);
+ event_name = NULL;
+ event_list = NULL;
+ pat = NULL;
+ pat_list = NULL;

if (li->li_tv.v_type != VAR_DICT)
continue;
***************
*** 2794,2823 ****
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);
--- 2802,2833 ----
if (event_dict == NULL)
continue;

! di = dict_find(event_dict, (char_u *)"event", -1);
! if (di != NULL)
{
! if (di->di_tv.v_type == VAR_STRING)
{
! event_name = di->di_tv.vval.v_string;
! if (event_name == NULL)
{
! 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,2879 ****
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);
--- 2869,2908 ----
if (bnum == -1)
continue;

! vim_snprintf((char *)IObuff, IOSIZE, "<buffer=%d>", (int)bnum);
! pat = IObuff;
}
else
{
! di = dict_find(event_dict, (char_u *)"pattern", -1);
! if (di != NULL)
{
! 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,2899 ****
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))
{
--- 2920,2929 ----
continue;
}

! if (delete && (event_name == NULL
! || (event_name[0] == '*' && event_name[1] == NUL)))
{
! // 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,2917 ****
}
else
{
! if (do_autocmd_event(event, pat, once, nested, cmd,
! delete | replace, group, 0) == FAIL)
{
! retval = VVAL_FALSE;
! break;
}
}

--- 2937,3012 ----
}
else
{
! eli = NULL;
! end = NULL;
! while (TRUE)
{
! 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,2933 ****
au_del_group(group_name);
}

- VIM_CLEAR(event_name);
VIM_CLEAR(group_name);
- VIM_CLEAR(pat);
VIM_CLEAR(cmd);

current_augroup = save_augroup;
--- 3020,3026 ----
*** ../vim-8.2.5029/src/errors.h 2022-05-27 17:26:50.538119977 +0100
--- src/errors.h 2022-05-27 17:57:45.764052324 +0100
***************
*** 1184,1190 ****
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)
EXTERN char e_invalid_value_for_argument_str_str[]
INIT(= N_("E475: Invalid value for argument %s: %s"));
#endif
--- 1184,1190 ----
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) || defined(FEAT_EVAL)
EXTERN char e_invalid_value_for_argument_str_str[]
INIT(= N_("E475: Invalid value for argument %s: %s"));
#endif
***************
*** 3280,3286 ****
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"));
EXTERN char e_bitshift_ops_must_be_postive[]
! INIT(= N_("E1283: bitshift amount must be a positive number"));
#endif
--- 3280,3286 ----
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"));
EXTERN char e_bitshift_ops_must_be_postive[]
! INIT(= N_("E1283: Bitshift amount must be a positive number"));
#endif
*** ../vim-8.2.5029/src/testdir/test_autocmd.vim 2022-05-24 11:40:07.518685751 +0100
--- src/testdir/test_autocmd.vim 2022-05-27 17:57:45.764052324 +0100
***************
*** 3429,3434 ****
--- 3429,3511 ----
\ 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([[]]))
*** ../vim-8.2.5029/src/version.c 2022-05-27 17:26:50.546119970 +0100
--- src/version.c 2022-05-27 18:04:38.939665812 +0100
***************
*** 736,737 ****
--- 736,739 ----
{ /* Add new patch number below this line */
+ /**/
+ 5030,
/**/

--
LAUNCELOT: At last! A call! A cry of distress ...
(he draws his sword, and turns to CONCORDE)
Concorde! Brave, Concorde ... you shall not have died in vain!
CONCORDE: I'm not quite dead, sir ...
"Monty Python and the Holy Grail" PYTHON (MONTY) PICTURES LTD

/// Bram Moolenaar -- Br...@Moolenaar.net -- http://www.Moolenaar.net \\\
/// \\\
\\\ sponsor Vim, vote for features -- http://www.Vim.org/sponsor/ ///
\\\ help me help AIDS victims -- http://ICCF-Holland.org ///

John Marriott

unread,
May 27, 2022, 3:19:54 PM5/27/22
to vim...@googlegroups.com

On 28-May-2022 03:06, Bram Moolenaar wrote:
> Patch 8.2.5030
> Problem: autocmd_add() can only handle one event and pattern.
> Solution: Support a list of events and patterns. (Yegappan Lakshmanan,
> closes #10483)
> Files: runtime/doc/builtin.txt, src/autocmd.c, src/errors.h,
> src/testdir/test_autocmd.vim
>
>
>
After this patch mingw64 (gcc 11.3.0) spits out this error if
FEAT_QUICKFIX is not defined:
<snip>
gcc -c -I. -Iproto -DWIN32 -DWINVER=0x0603 -D_WIN32_WINNT=0x0603
-DHAVE_PATHDEF -DFEAT_NORMAL -DHAVE_STDINT_H -D__USE_MINGW_ANSI_STDIO
-pipe -march=native -Wall -O3 -fomit-frame-pointer -freg-struct-return
-fpie -fPIE -DFEAT_GUI_MSWIN -DFEAT_CLIPBOARD autocmd.c -o
gobjnative/autocmd.o
In file included from autocmd.c:14:
autocmd.c: In function 'autocmd_add_or_delete':
autocmd.c:2828:24: error: 'e_string_or_list_expected' undeclared (first
use in this function)
 2828 |                 emsg(_(e_string_or_list_expected));
      |                        ^~~~~~~~~~~~~~~~~~~~~~~~~
vim.h:564:25: note: in definition of macro '_'
  564 | # define _(x) ((char *)(x))
      |                         ^
autocmd.c:2828:24: note: each undeclared identifier is reported only
once for each function it appears in
 2828 |                 emsg(_(e_string_or_list_expected));
      |                        ^~~~~~~~~~~~~~~~~~~~~~~~~
vim.h:564:25: note: in definition of macro '_'
  564 | # define _(x) ((char *)(x))
      |                         ^
make: *** [Make_cyg_ming.mak:1187: gobjnative/autocmd.o] Error 1
</snip>

The attached patch of errors.h tries to fix it.



After applying this patch, mingw64 then spat out this warning:
<snip>
gcc -c -I. -Iproto -DWIN32 -DWINVER=0x0603 -D_WIN32_WINNT=0x0603
-DHAVE_PATHDEF -DFEAT_NORMAL -DHAVE_STDINT_H -D__USE_MINGW_ANSI_STDIO
-pipe -march=native -Wall -O3 -fomit-frame-pointer -freg-struct-return
-fpie -fPIE -DFEAT_GUI_MSWIN -DFEAT_CLIPBOARD autocmd.c -o
gobjnative/autocmd.o
autocmd.c: In function 'f_autocmd_add':
autocmd.c:2967:20: warning: 'p' may be used uninitialized in this
function [-Wmaybe-uninitialized]
 2967 |                 if (p == NULL)
      |                    ^
autocmd.c:2772:18: note: 'p' was declared here
 2772 |     char_u      *p;
      |                  ^
autocmd.c: In function 'f_autocmd_delete':
autocmd.c:2967:20: warning: 'p' may be used uninitialized in this
function [-Wmaybe-uninitialized]
 2967 |                 if (p == NULL)
      |                    ^
autocmd.c:2772:18: note: 'p' was declared here
 2772 |     char_u      *p;
      |                  ^
</snip>

The attached patch of autocmd.c tries to fix it.

Cheers
John
autocmd.c.8.2.5030.patch
errors.h.8.2.5030.patch

Bram Moolenaar

unread,
May 27, 2022, 4:17:12 PM5/27/22
to vim...@googlegroups.com, John Marriott
Looks good.
Also looks good.

--
FIRST GUARD: Ah! Now ... we're not allowed to ...
SIR LAUNCELOT runs him through, grabs his spear and stabs the other
guard who collapses in a heap. Hiccoughs quietly.
Reply all
Reply to author
Forward
0 new messages