mirror of
https://github.com/vim/vim.git
synced 2025-07-26 11:04:33 -04:00
patch 8.2.3268: cannot use a block with :autocmd like with :command
Problem: Cannot use a block with :autocmd like with :command. Solution: Add support for a {} block after :autocmd. (closes #8620)
This commit is contained in:
parent
6db660bed9
commit
73b8b0ae3a
@ -76,6 +76,12 @@ and in a `:def` function) then {cmd} will be executed as in Vim9
|
|||||||
script. Thus this depends on where the autocmd is defined, not where it is
|
script. Thus this depends on where the autocmd is defined, not where it is
|
||||||
triggered.
|
triggered.
|
||||||
|
|
||||||
|
{cmd} can use a block, like with `:command`, see |:command-repl|. Example: >
|
||||||
|
au BufReadPost *.xml {
|
||||||
|
setlocal matchpairs+=<:>
|
||||||
|
/<start
|
||||||
|
}
|
||||||
|
|
||||||
Note: The ":autocmd" command can only be followed by another command when the
|
Note: The ":autocmd" command can only be followed by another command when the
|
||||||
'|' appears before {cmd}. This works: >
|
'|' appears before {cmd}. This works: >
|
||||||
:augroup mine | au! BufRead | augroup END
|
:augroup mine | au! BufRead | augroup END
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
*map.txt* For Vim version 8.2. Last change: 2021 Jul 28
|
*map.txt* For Vim version 8.2. Last change: 2021 Aug 01
|
||||||
|
|
||||||
|
|
||||||
VIM REFERENCE MANUAL by Bram Moolenaar
|
VIM REFERENCE MANUAL by Bram Moolenaar
|
||||||
@ -1571,7 +1571,7 @@ feature. Use the full name for new scripts.
|
|||||||
|
|
||||||
|
|
||||||
Replacement text ~
|
Replacement text ~
|
||||||
|
*:command-repl*
|
||||||
The {repl} argument is normally one long string, possibly with "|" separated
|
The {repl} argument is normally one long string, possibly with "|" separated
|
||||||
commands. A special case is when the argument is "{", then the following
|
commands. A special case is when the argument is "{", then the following
|
||||||
lines, up to a line starting with "}" are used and |Vim9| syntax applies.
|
lines, up to a line starting with "}" are used and |Vim9| syntax applies.
|
||||||
@ -1580,8 +1580,8 @@ Example: >
|
|||||||
echo 'hello'
|
echo 'hello'
|
||||||
g:calledMyCommand = true
|
g:calledMyCommand = true
|
||||||
}
|
}
|
||||||
No nesting is supported. Using `:normal` directly does not work, you can use
|
No nesting is supported, inline functions cannot be used. Using `:normal`
|
||||||
it indirectly with `:execute`.
|
directly does not work, you can use it indirectly with `:execute`.
|
||||||
|
|
||||||
The replacement text {repl} for a user defined command is scanned for special
|
The replacement text {repl} for a user defined command is scanned for special
|
||||||
escape sequences, using <...> notation. Escape sequences are replaced with
|
escape sequences, using <...> notation. Escape sequences are replaced with
|
||||||
|
@ -258,7 +258,7 @@ static int au_need_clean = FALSE; // need to delete marked patterns
|
|||||||
|
|
||||||
static char_u *event_nr2name(event_T event);
|
static char_u *event_nr2name(event_T event);
|
||||||
static int au_get_grouparg(char_u **argp);
|
static int au_get_grouparg(char_u **argp);
|
||||||
static int do_autocmd_event(event_T event, char_u *pat, int once, int nested, char_u *cmd, int forceit, int group);
|
static int do_autocmd_event(event_T event, char_u *pat, int once, int nested, char_u *cmd, int forceit, int group, int flags);
|
||||||
static int apply_autocmds_group(event_T event, char_u *fname, char_u *fname_io, int force, int group, buf_T *buf, exarg_T *eap);
|
static int apply_autocmds_group(event_T event, char_u *fname, char_u *fname_io, int force, int group, buf_T *buf, exarg_T *eap);
|
||||||
static void auto_next_pat(AutoPatCmd *apc, int stop_at_last);
|
static void auto_next_pat(AutoPatCmd *apc, int stop_at_last);
|
||||||
static int au_find_group(char_u *name);
|
static int au_find_group(char_u *name);
|
||||||
@ -615,7 +615,7 @@ free_all_autocmds(void)
|
|||||||
|
|
||||||
for (current_augroup = -1; current_augroup < augroups.ga_len;
|
for (current_augroup = -1; current_augroup < augroups.ga_len;
|
||||||
++current_augroup)
|
++current_augroup)
|
||||||
do_autocmd((char_u *)"", TRUE);
|
do_autocmd(NULL, (char_u *)"", TRUE);
|
||||||
|
|
||||||
for (i = 0; i < augroups.ga_len; ++i)
|
for (i = 0; i < augroups.ga_len; ++i)
|
||||||
{
|
{
|
||||||
@ -823,20 +823,23 @@ au_event_restore(char_u *old_ei)
|
|||||||
* :autocmd * *.c show all autocommands for *.c files.
|
* :autocmd * *.c show all autocommands for *.c files.
|
||||||
*
|
*
|
||||||
* Mostly a {group} argument can optionally appear before <event>.
|
* Mostly a {group} argument can optionally appear before <event>.
|
||||||
|
* "eap" can be NULL.
|
||||||
*/
|
*/
|
||||||
void
|
void
|
||||||
do_autocmd(char_u *arg_in, int forceit)
|
do_autocmd(exarg_T *eap, char_u *arg_in, int forceit)
|
||||||
{
|
{
|
||||||
char_u *arg = arg_in;
|
char_u *arg = arg_in;
|
||||||
char_u *pat;
|
char_u *pat;
|
||||||
char_u *envpat = NULL;
|
char_u *envpat = NULL;
|
||||||
char_u *cmd;
|
char_u *cmd;
|
||||||
|
int cmd_need_free = FALSE;
|
||||||
event_T event;
|
event_T event;
|
||||||
int need_free = FALSE;
|
char_u *tofree = NULL;
|
||||||
int nested = FALSE;
|
int nested = FALSE;
|
||||||
int once = FALSE;
|
int once = FALSE;
|
||||||
int group;
|
int group;
|
||||||
int i;
|
int i;
|
||||||
|
int flags = 0;
|
||||||
|
|
||||||
if (*arg == '|')
|
if (*arg == '|')
|
||||||
{
|
{
|
||||||
@ -935,10 +938,14 @@ do_autocmd(char_u *arg_in, int forceit)
|
|||||||
*/
|
*/
|
||||||
if (*cmd != NUL)
|
if (*cmd != NUL)
|
||||||
{
|
{
|
||||||
|
if (eap != NULL)
|
||||||
|
// Read a {} block if it follows.
|
||||||
|
cmd = may_get_cmd_block(eap, cmd, &tofree, &flags);
|
||||||
|
|
||||||
cmd = expand_sfile(cmd);
|
cmd = expand_sfile(cmd);
|
||||||
if (cmd == NULL) // some error
|
if (cmd == NULL) // some error
|
||||||
return;
|
return;
|
||||||
need_free = TRUE;
|
cmd_need_free = TRUE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -962,19 +969,20 @@ do_autocmd(char_u *arg_in, int forceit)
|
|||||||
for (event = (event_T)0; (int)event < (int)NUM_EVENTS;
|
for (event = (event_T)0; (int)event < (int)NUM_EVENTS;
|
||||||
event = (event_T)((int)event + 1))
|
event = (event_T)((int)event + 1))
|
||||||
if (do_autocmd_event(event, pat,
|
if (do_autocmd_event(event, pat,
|
||||||
once, nested, cmd, forceit, group) == FAIL)
|
once, nested, cmd, forceit, group, flags) == FAIL)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
while (*arg && *arg != '|' && !VIM_ISWHITE(*arg))
|
while (*arg && *arg != '|' && !VIM_ISWHITE(*arg))
|
||||||
if (do_autocmd_event(event_name2nr(arg, &arg), pat,
|
if (do_autocmd_event(event_name2nr(arg, &arg), pat,
|
||||||
once, nested, cmd, forceit, group) == FAIL)
|
once, nested, cmd, forceit, group, flags) == FAIL)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (need_free)
|
if (cmd_need_free)
|
||||||
vim_free(cmd);
|
vim_free(cmd);
|
||||||
|
vim_free(tofree);
|
||||||
vim_free(envpat);
|
vim_free(envpat);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1024,7 +1032,8 @@ do_autocmd_event(
|
|||||||
int nested,
|
int nested,
|
||||||
char_u *cmd,
|
char_u *cmd,
|
||||||
int forceit,
|
int forceit,
|
||||||
int group)
|
int group,
|
||||||
|
int flags)
|
||||||
{
|
{
|
||||||
AutoPat *ap;
|
AutoPat *ap;
|
||||||
AutoPat **prev_ap;
|
AutoPat **prev_ap;
|
||||||
@ -1251,6 +1260,8 @@ do_autocmd_event(
|
|||||||
return FAIL;
|
return FAIL;
|
||||||
ac->cmd = vim_strsave(cmd);
|
ac->cmd = vim_strsave(cmd);
|
||||||
ac->script_ctx = current_sctx;
|
ac->script_ctx = current_sctx;
|
||||||
|
if (flags & UC_VIM9)
|
||||||
|
ac->script_ctx.sc_version = SCRIPT_VERSION_VIM9;
|
||||||
#ifdef FEAT_EVAL
|
#ifdef FEAT_EVAL
|
||||||
ac->script_ctx.sc_lnum += SOURCING_LNUM;
|
ac->script_ctx.sc_lnum += SOURCING_LNUM;
|
||||||
#endif
|
#endif
|
||||||
|
@ -5203,7 +5203,7 @@ ex_autocmd(exarg_T *eap)
|
|||||||
_(e_command_not_allowed_from_vimrc_in_current_dir_or_tag_search);
|
_(e_command_not_allowed_from_vimrc_in_current_dir_or_tag_search);
|
||||||
}
|
}
|
||||||
else if (eap->cmdidx == CMD_autocmd)
|
else if (eap->cmdidx == CMD_autocmd)
|
||||||
do_autocmd(eap->arg, eap->forceit);
|
do_autocmd(eap, eap->arg, eap->forceit);
|
||||||
else
|
else
|
||||||
do_augroup(eap->arg, eap->forceit);
|
do_augroup(eap->arg, eap->forceit);
|
||||||
}
|
}
|
||||||
|
@ -6,7 +6,7 @@ void free_all_autocmds(void);
|
|||||||
int check_ei(void);
|
int check_ei(void);
|
||||||
char_u *au_event_disable(char *what);
|
char_u *au_event_disable(char *what);
|
||||||
void au_event_restore(char_u *old_ei);
|
void au_event_restore(char_u *old_ei);
|
||||||
void do_autocmd(char_u *arg_in, int forceit);
|
void do_autocmd(exarg_T *eap, char_u *arg_in, int forceit);
|
||||||
int do_doautocmd(char_u *arg, int do_msg, int *did_something);
|
int do_doautocmd(char_u *arg, int do_msg, int *did_something);
|
||||||
void ex_doautoall(exarg_T *eap);
|
void ex_doautoall(exarg_T *eap);
|
||||||
int check_nomodeline(char_u **argp);
|
int check_nomodeline(char_u **argp);
|
||||||
|
@ -10,6 +10,7 @@ char_u *get_user_cmd_complete(expand_T *xp, int idx);
|
|||||||
int cmdcomplete_str_to_type(char_u *complete_str);
|
int cmdcomplete_str_to_type(char_u *complete_str);
|
||||||
char *uc_fun_cmd(void);
|
char *uc_fun_cmd(void);
|
||||||
int parse_compl_arg(char_u *value, int vallen, int *complp, long *argt, char_u **compl_arg);
|
int parse_compl_arg(char_u *value, int vallen, int *complp, long *argt, char_u **compl_arg);
|
||||||
|
char_u *may_get_cmd_block(exarg_T *eap, char_u *p, char_u **tofree, int *flags);
|
||||||
void ex_command(exarg_T *eap);
|
void ex_command(exarg_T *eap);
|
||||||
void ex_comclear(exarg_T *eap);
|
void ex_comclear(exarg_T *eap);
|
||||||
void uc_clear(garray_T *gap);
|
void uc_clear(garray_T *gap);
|
||||||
|
@ -2810,5 +2810,21 @@ func Test_autocmd_vimgrep()
|
|||||||
augroup END
|
augroup END
|
||||||
endfunc
|
endfunc
|
||||||
|
|
||||||
|
func Test_autocmd_with_block()
|
||||||
|
augroup block_testing
|
||||||
|
au BufReadPost *.xml {
|
||||||
|
setlocal matchpairs+=<:>
|
||||||
|
/<start
|
||||||
|
}
|
||||||
|
augroup END
|
||||||
|
|
||||||
|
let expected = "\n--- Autocommands ---\nblock_testing BufRead\n *.xml {^@ setlocal matchpairs+=<:>^@ /<start^@ }"
|
||||||
|
call assert_equal(expected, execute('au BufReadPost *.xml'))
|
||||||
|
|
||||||
|
augroup block_testing
|
||||||
|
au!
|
||||||
|
augroup END
|
||||||
|
endfunc
|
||||||
|
|
||||||
|
|
||||||
" vim: shiftwidth=2 sts=2 expandtab
|
" vim: shiftwidth=2 sts=2 expandtab
|
||||||
|
@ -114,9 +114,6 @@ static struct
|
|||||||
{ADDR_NONE, NULL, NULL}
|
{ADDR_NONE, NULL, NULL}
|
||||||
};
|
};
|
||||||
|
|
||||||
#define UC_BUFFER 1 // -buffer: local to current buffer
|
|
||||||
#define UC_VIM9 2 // {} argument: Vim9 syntax.
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Search for a user command that matches "eap->cmd".
|
* Search for a user command that matches "eap->cmd".
|
||||||
* Return cmdidx in "eap->cmdidx", flags in "eap->argt", idx in "eap->useridx".
|
* Return cmdidx in "eap->cmdidx", flags in "eap->argt", idx in "eap->useridx".
|
||||||
@ -974,6 +971,49 @@ fail:
|
|||||||
return FAIL;
|
return FAIL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If "p" starts with "{" then read a block of commands until "}".
|
||||||
|
* Used for ":command" and ":autocmd".
|
||||||
|
*/
|
||||||
|
char_u *
|
||||||
|
may_get_cmd_block(exarg_T *eap, char_u *p, char_u **tofree, int *flags)
|
||||||
|
{
|
||||||
|
char_u *retp = p;
|
||||||
|
|
||||||
|
if (*p == '{' && ends_excmd2(eap->arg, skipwhite(p + 1))
|
||||||
|
&& eap->getline != NULL)
|
||||||
|
{
|
||||||
|
garray_T ga;
|
||||||
|
char_u *line = NULL;
|
||||||
|
|
||||||
|
ga_init2(&ga, sizeof(char_u *), 10);
|
||||||
|
if (ga_add_string(&ga, p) == FAIL)
|
||||||
|
return retp;
|
||||||
|
|
||||||
|
// Read lines between '{' and '}'. Does not support nesting or
|
||||||
|
// here-doc constructs.
|
||||||
|
for (;;)
|
||||||
|
{
|
||||||
|
vim_free(line);
|
||||||
|
if ((line = eap->getline(':', eap->cookie,
|
||||||
|
0, GETLINE_CONCAT_CONTBAR)) == NULL)
|
||||||
|
{
|
||||||
|
emsg(_(e_missing_rcurly));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (ga_add_string(&ga, line) == FAIL)
|
||||||
|
break;
|
||||||
|
if (*skipwhite(line) == '}')
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
vim_free(line);
|
||||||
|
retp = *tofree = ga_concat_strings(&ga, "\n");
|
||||||
|
ga_clear_strings(&ga);
|
||||||
|
*flags |= UC_VIM9;
|
||||||
|
}
|
||||||
|
return retp;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* ":command ..." implementation
|
* ":command ..." implementation
|
||||||
*/
|
*/
|
||||||
@ -1043,38 +1083,7 @@ ex_command(exarg_T *eap)
|
|||||||
{
|
{
|
||||||
char_u *tofree = NULL;
|
char_u *tofree = NULL;
|
||||||
|
|
||||||
if (*p == '{' && ends_excmd2(eap->arg, skipwhite(p + 1))
|
p = may_get_cmd_block(eap, p, &tofree, &flags);
|
||||||
&& eap->getline != NULL)
|
|
||||||
{
|
|
||||||
garray_T ga;
|
|
||||||
char_u *line = NULL;
|
|
||||||
|
|
||||||
ga_init2(&ga, sizeof(char_u *), 10);
|
|
||||||
if (ga_add_string(&ga, p) == FAIL)
|
|
||||||
return;
|
|
||||||
|
|
||||||
// Read lines between '{' and '}'. Does not support nesting or
|
|
||||||
// here-doc constructs.
|
|
||||||
//
|
|
||||||
for (;;)
|
|
||||||
{
|
|
||||||
vim_free(line);
|
|
||||||
if ((line = eap->getline(':', eap->cookie,
|
|
||||||
0, GETLINE_CONCAT_CONTBAR)) == NULL)
|
|
||||||
{
|
|
||||||
emsg(_(e_missing_rcurly));
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (ga_add_string(&ga, line) == FAIL)
|
|
||||||
break;
|
|
||||||
if (*skipwhite(line) == '}')
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
vim_free(line);
|
|
||||||
p = tofree = ga_concat_strings(&ga, "\n");
|
|
||||||
ga_clear_strings(&ga);
|
|
||||||
flags |= UC_VIM9;
|
|
||||||
}
|
|
||||||
|
|
||||||
uc_add_command(name, end - name, p, argt, def, flags, compl, compl_arg,
|
uc_add_command(name, end - name, p, argt, def, flags, compl, compl_arg,
|
||||||
addr_type_arg, eap->forceit);
|
addr_type_arg, eap->forceit);
|
||||||
|
@ -755,6 +755,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 */
|
||||||
|
/**/
|
||||||
|
3268,
|
||||||
/**/
|
/**/
|
||||||
3267,
|
3267,
|
||||||
/**/
|
/**/
|
||||||
|
@ -2739,4 +2739,9 @@ long elapsed(DWORD start_tick);
|
|||||||
// flags for equal_type()
|
// flags for equal_type()
|
||||||
#define ETYPE_ARG_UNKNOWN 1
|
#define ETYPE_ARG_UNKNOWN 1
|
||||||
|
|
||||||
|
// flags used by user commands and :autocmd
|
||||||
|
#define UC_BUFFER 1 // -buffer: local to current buffer
|
||||||
|
#define UC_VIM9 2 // {} argument: Vim9 syntax.
|
||||||
|
|
||||||
|
|
||||||
#endif // VIM__H
|
#endif // VIM__H
|
||||||
|
Loading…
x
Reference in New Issue
Block a user