diff options
author | Bram Moolenaar <Bram@vim.org> | 2021-08-01 14:52:32 +0200 |
---|---|---|
committer | Bram Moolenaar <Bram@vim.org> | 2021-08-01 14:52:32 +0200 |
commit | 73b8b0ae3acac220e823076f8ca1c14524ed96dd (patch) | |
tree | 0b9157946ccfc3a56e621e7e271c97207817a801 | |
parent | 6db660bed9ed5063f8c6e0fadeef32d44bbd017d (diff) | |
download | vim-git-73b8b0ae3acac220e823076f8ca1c14524ed96dd.tar.gz |
patch 8.2.3268: cannot use a block with :autocmd like with :commandv8.2.3268
Problem: Cannot use a block with :autocmd like with :command.
Solution: Add support for a {} block after :autocmd. (closes #8620)
-rw-r--r-- | runtime/doc/autocmd.txt | 6 | ||||
-rw-r--r-- | runtime/doc/map.txt | 8 | ||||
-rw-r--r-- | src/autocmd.c | 29 | ||||
-rw-r--r-- | src/ex_docmd.c | 2 | ||||
-rw-r--r-- | src/proto/autocmd.pro | 2 | ||||
-rw-r--r-- | src/proto/usercmd.pro | 1 | ||||
-rw-r--r-- | src/testdir/test_autocmd.vim | 16 | ||||
-rw-r--r-- | src/usercmd.c | 79 | ||||
-rw-r--r-- | src/version.c | 2 | ||||
-rw-r--r-- | src/vim.h | 5 |
10 files changed, 100 insertions, 50 deletions
diff --git a/runtime/doc/autocmd.txt b/runtime/doc/autocmd.txt index 7614e8bd7..d3ebc11fe 100644 --- a/runtime/doc/autocmd.txt +++ b/runtime/doc/autocmd.txt @@ -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 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 '|' appears before {cmd}. This works: > :augroup mine | au! BufRead | augroup END diff --git a/runtime/doc/map.txt b/runtime/doc/map.txt index 505f81522..a10c85b7a 100644 --- a/runtime/doc/map.txt +++ b/runtime/doc/map.txt @@ -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 @@ -1571,7 +1571,7 @@ feature. Use the full name for new scripts. Replacement text ~ - + *:command-repl* The {repl} argument is normally one long string, possibly with "|" separated 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. @@ -1580,8 +1580,8 @@ Example: > echo 'hello' g:calledMyCommand = true } -No nesting is supported. Using `:normal` directly does not work, you can use -it indirectly with `:execute`. +No nesting is supported, inline functions cannot be used. Using `:normal` +directly does not work, you can use it indirectly with `:execute`. The replacement text {repl} for a user defined command is scanned for special escape sequences, using <...> notation. Escape sequences are replaced with diff --git a/src/autocmd.c b/src/autocmd.c index 4c12e729e..83e990df0 100644 --- a/src/autocmd.c +++ b/src/autocmd.c @@ -258,7 +258,7 @@ static int au_need_clean = FALSE; // need to delete marked patterns static char_u *event_nr2name(event_T event); 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 void auto_next_pat(AutoPatCmd *apc, int stop_at_last); 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; ++current_augroup) - do_autocmd((char_u *)"", TRUE); + do_autocmd(NULL, (char_u *)"", TRUE); 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. * * Mostly a {group} argument can optionally appear before <event>. + * "eap" can be NULL. */ 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 *pat; char_u *envpat = NULL; char_u *cmd; + int cmd_need_free = FALSE; event_T event; - int need_free = FALSE; + char_u *tofree = NULL; int nested = FALSE; int once = FALSE; int group; int i; + int flags = 0; if (*arg == '|') { @@ -935,10 +938,14 @@ do_autocmd(char_u *arg_in, int forceit) */ 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); if (cmd == NULL) // some error 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; event = (event_T)((int)event + 1)) if (do_autocmd_event(event, pat, - once, nested, cmd, forceit, group) == FAIL) + once, nested, cmd, forceit, group, flags) == FAIL) break; } else { while (*arg && *arg != '|' && !VIM_ISWHITE(*arg)) if (do_autocmd_event(event_name2nr(arg, &arg), pat, - once, nested, cmd, forceit, group) == FAIL) + once, nested, cmd, forceit, group, flags) == FAIL) break; } - if (need_free) + if (cmd_need_free) vim_free(cmd); + vim_free(tofree); vim_free(envpat); } @@ -1024,7 +1032,8 @@ do_autocmd_event( int nested, char_u *cmd, int forceit, - int group) + int group, + int flags) { AutoPat *ap; AutoPat **prev_ap; @@ -1251,6 +1260,8 @@ do_autocmd_event( return FAIL; ac->cmd = vim_strsave(cmd); ac->script_ctx = current_sctx; + if (flags & UC_VIM9) + ac->script_ctx.sc_version = SCRIPT_VERSION_VIM9; #ifdef FEAT_EVAL ac->script_ctx.sc_lnum += SOURCING_LNUM; #endif diff --git a/src/ex_docmd.c b/src/ex_docmd.c index c72e9c1b7..f2ff787e0 100644 --- a/src/ex_docmd.c +++ b/src/ex_docmd.c @@ -5203,7 +5203,7 @@ ex_autocmd(exarg_T *eap) _(e_command_not_allowed_from_vimrc_in_current_dir_or_tag_search); } else if (eap->cmdidx == CMD_autocmd) - do_autocmd(eap->arg, eap->forceit); + do_autocmd(eap, eap->arg, eap->forceit); else do_augroup(eap->arg, eap->forceit); } diff --git a/src/proto/autocmd.pro b/src/proto/autocmd.pro index 88eae5a78..24dd1ba8e 100644 --- a/src/proto/autocmd.pro +++ b/src/proto/autocmd.pro @@ -6,7 +6,7 @@ void free_all_autocmds(void); int check_ei(void); char_u *au_event_disable(char *what); 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); void ex_doautoall(exarg_T *eap); int check_nomodeline(char_u **argp); diff --git a/src/proto/usercmd.pro b/src/proto/usercmd.pro index 9e16a80e6..e9230d572 100644 --- a/src/proto/usercmd.pro +++ b/src/proto/usercmd.pro @@ -10,6 +10,7 @@ char_u *get_user_cmd_complete(expand_T *xp, int idx); int cmdcomplete_str_to_type(char_u *complete_str); char *uc_fun_cmd(void); 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_comclear(exarg_T *eap); void uc_clear(garray_T *gap); diff --git a/src/testdir/test_autocmd.vim b/src/testdir/test_autocmd.vim index 8abf911fa..4a7dd60f6 100644 --- a/src/testdir/test_autocmd.vim +++ b/src/testdir/test_autocmd.vim @@ -2810,5 +2810,21 @@ func Test_autocmd_vimgrep() augroup END 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 diff --git a/src/usercmd.c b/src/usercmd.c index 09e7b26b3..48f84b1c3 100644 --- a/src/usercmd.c +++ b/src/usercmd.c @@ -114,9 +114,6 @@ static struct {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". * Return cmdidx in "eap->cmdidx", flags in "eap->argt", idx in "eap->useridx". @@ -975,6 +972,49 @@ 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 */ void @@ -1043,38 +1083,7 @@ ex_command(exarg_T *eap) { char_u *tofree = NULL; - 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; - - // 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; - } + p = may_get_cmd_block(eap, p, &tofree, &flags); uc_add_command(name, end - name, p, argt, def, flags, compl, compl_arg, addr_type_arg, eap->forceit); diff --git a/src/version.c b/src/version.c index 962f002d5..b5173e6d0 100644 --- a/src/version.c +++ b/src/version.c @@ -756,6 +756,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ /**/ + 3268, +/**/ 3267, /**/ 3266, @@ -2739,4 +2739,9 @@ long elapsed(DWORD start_tick); // flags for equal_type() #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 |