diff options
author | LemonBoy <thatlemon@gmail.com> | 2022-04-14 15:39:43 +0100 |
---|---|---|
committer | Bram Moolenaar <Bram@vim.org> | 2022-04-14 15:39:43 +0100 |
commit | eca7c60d68e63001dbe3c8e5d240b0895e607fc3 (patch) | |
tree | 04384f6cf892f06286cc7176f80af901cd72be40 | |
parent | 8944551534b311a2d25acf6e8db235c6d906256c (diff) | |
download | vim-git-eca7c60d68e63001dbe3c8e5d240b0895e607fc3.tar.gz |
patch 8.2.4749: <script> is not expanded in autocmd contextv8.2.4749
Problem: <script> is not expanded in autocmd context.
Solution: Add the context to the pattern struct. (closes #10144)
Rename AutoPatCmd to AutoPatCmd_T.
-rw-r--r-- | src/autocmd.c | 57 | ||||
-rw-r--r-- | src/proto/autocmd.pro | 5 | ||||
-rw-r--r-- | src/scriptfile.c | 37 | ||||
-rw-r--r-- | src/structs.h | 4 | ||||
-rw-r--r-- | src/testdir/test_expand.vim | 27 | ||||
-rw-r--r-- | src/version.c | 2 |
6 files changed, 85 insertions, 47 deletions
diff --git a/src/autocmd.c b/src/autocmd.c index 3b384f5f9..223f92cf6 100644 --- a/src/autocmd.c +++ b/src/autocmd.c @@ -55,7 +55,7 @@ typedef struct AutoCmd char once; // "One shot": removed after execution char nested; // If autocommands nest here. char last; // last command in list - sctx_T script_ctx; // script context where defined + sctx_T script_ctx; // script context where it is defined struct AutoCmd *next; // next AutoCmd in list } AutoCmd; @@ -234,12 +234,13 @@ struct AutoPatCmd_S char_u *sfname; // sfname to match with char_u *tail; // tail of fname event_T event; // current event + sctx_T script_ctx; // script context where it is defined int arg_bufnr; // Initially equal to <abuf>, set to zero when // buf is deleted. - AutoPatCmd *next; // chain of active apc-s for auto-invalidation + AutoPatCmd_T *next; // chain of active apc-s for auto-invalidation }; -static AutoPatCmd *active_apc_list = NULL; // stack of active autocommands +static AutoPatCmd_T *active_apc_list = NULL; // stack of active autocommands // Macro to loop over all the patterns for an autocmd event #define FOR_ALL_AUTOCMD_PATTERNS(event, ap) \ @@ -264,7 +265,7 @@ 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, 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 void auto_next_pat(AutoPatCmd_T *apc, int stop_at_last); static int au_find_group(char_u *name); static event_T last_event; @@ -453,9 +454,9 @@ au_cleanup(void) void aubuflocal_remove(buf_T *buf) { - AutoPat *ap; - event_T event; - AutoPatCmd *apc; + AutoPat *ap; + event_T event; + AutoPatCmd_T *apc; // invalidate currently executing autocommands for (apc = active_apc_list; apc; apc = apc->next) @@ -1914,7 +1915,7 @@ apply_autocmds_group( int save_autocmd_busy; int save_autocmd_nested; static int nesting = 0; - AutoPatCmd patcmd; + AutoPatCmd_T patcmd; AutoPat *ap; sctx_T save_current_sctx; #ifdef FEAT_EVAL @@ -2173,15 +2174,14 @@ apply_autocmds_group( tail = gettail(fname); // Find first autocommand that matches + CLEAR_FIELD(patcmd); patcmd.curpat = first_autopat[(int)event]; - patcmd.nextcmd = NULL; patcmd.group = group; patcmd.fname = fname; patcmd.sfname = sfname; patcmd.tail = tail; patcmd.event = event; patcmd.arg_bufnr = autocmd_bufnr; - patcmd.next = NULL; auto_next_pat(&patcmd, FALSE); // found one, start executing the autocommands @@ -2363,16 +2363,21 @@ is_autocmd_blocked(void) */ static void auto_next_pat( - AutoPatCmd *apc, + AutoPatCmd_T *apc, int stop_at_last) // stop when 'last' flag is set { AutoPat *ap; AutoCmd *cp; char_u *name; char *s; - char_u **sourcing_namep = &SOURCING_NAME; + estack_T *entry; + char_u *namep; + + entry = ((estack_T *)exestack.ga_data) + exestack.ga_len - 1; - VIM_CLEAR(*sourcing_namep); + // Clear the exestack entry for this ETYPE_AUCMD entry. + VIM_CLEAR(entry->es_name); + entry->es_info.aucmd = NULL; for (ap = apc->curpat; ap != NULL && !got_int; ap = ap->next) { @@ -2392,20 +2397,22 @@ auto_next_pat( { name = event_nr2name(apc->event); s = _("%s Autocommands for \"%s\""); - *sourcing_namep = alloc(STRLEN(s) - + STRLEN(name) + ap->patlen + 1); - if (*sourcing_namep != NULL) + namep = alloc(STRLEN(s) + STRLEN(name) + ap->patlen + 1); + if (namep != NULL) { - sprintf((char *)*sourcing_namep, s, - (char *)name, (char *)ap->pat); + sprintf((char *)namep, s, (char *)name, (char *)ap->pat); if (p_verbose >= 8) { verbose_enter(); - smsg(_("Executing %s"), *sourcing_namep); + smsg(_("Executing %s"), namep); verbose_leave(); } } + // Update the exestack entry for this autocmd. + entry->es_name = namep; + entry->es_info.aucmd = apc; + apc->curpat = ap; apc->nextcmd = ap->cmds; // mark last command @@ -2423,6 +2430,15 @@ auto_next_pat( } /* + * Get the script context where autocommand "acp" is defined. + */ + sctx_T * +acp_script_ctx(AutoPatCmd_T *acp) +{ + return &acp->script_ctx; +} + +/* * Get next autocommand command. * Called by do_cmdline() to get the next line for ":if". * Returns allocated string, or NULL for end of autocommands. @@ -2434,7 +2450,7 @@ getnextac( int indent UNUSED, getline_opt_T options UNUSED) { - AutoPatCmd *acp = (AutoPatCmd *)cookie; + AutoPatCmd_T *acp = (AutoPatCmd_T *)cookie; char_u *retval; AutoCmd *ac; @@ -2481,6 +2497,7 @@ getnextac( au_del_cmd(ac); autocmd_nested = ac->nested; current_sctx = ac->script_ctx; + acp->script_ctx = current_sctx; if (ac->last) acp->nextcmd = NULL; else diff --git a/src/proto/autocmd.pro b/src/proto/autocmd.pro index 366d7aa4d..ddf391516 100644 --- a/src/proto/autocmd.pro +++ b/src/proto/autocmd.pro @@ -7,7 +7,7 @@ int check_ei(void); char_u *au_event_disable(char *what); void au_event_restore(char_u *old_ei); 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_start, int do_msg, int *did_something); void ex_doautoall(exarg_T *eap); int check_nomodeline(char_u **argp); void aucmd_prepbuf(aco_save_T *aco, buf_T *buf); @@ -16,6 +16,7 @@ int apply_autocmds(event_T event, char_u *fname, char_u *fname_io, int force, bu int apply_autocmds_exarg(event_T event, char_u *fname, char_u *fname_io, int force, buf_T *buf, exarg_T *eap); int apply_autocmds_retval(event_T event, char_u *fname, char_u *fname_io, int force, buf_T *buf, int *retval); int trigger_cursorhold(void); +int has_winscrolled(void); int has_cursormoved(void); int has_cursormovedI(void); int has_textchanged(void); @@ -26,10 +27,10 @@ int has_cmdundefined(void); int has_textyankpost(void); int has_completechanged(void); int has_modechanged(void); -int has_winscrolled(void); void block_autocmds(void); void unblock_autocmds(void); int is_autocmd_blocked(void); +sctx_T *acp_script_ctx(AutoPatCmd_T *acp); char_u *getnextac(int c, void *cookie, int indent, getline_opt_T options); int has_autocmd(event_T event, char_u *sfname, buf_T *buf); char_u *get_augroup_name(expand_T *xp, int idx); diff --git a/src/scriptfile.c b/src/scriptfile.c index 2a1f84a50..3dfb1c43c 100644 --- a/src/scriptfile.c +++ b/src/scriptfile.c @@ -157,27 +157,36 @@ estack_sfile(estack_arg_T which UNUSED) return NULL; } - // If evaluated in a function return the path of the script where the - // function is defined, at script level the current script path is returned + // If evaluated in a function or autocommand, return the path of the script + // where it is defined, at script level the current script path is returned // instead. if (which == ESTACK_SCRIPT) { - if (entry->es_type == ETYPE_UFUNC) + entry = ((estack_T *)exestack.ga_data) + exestack.ga_len - 1; + // Walk the stack backwards, starting from the current frame. + for (idx = exestack.ga_len - 1; idx >= 0; --idx, --entry) { - sctx_T *def_ctx = &entry->es_info.ufunc->uf_script_ctx; + if (entry->es_type == ETYPE_UFUNC) + { + sctx_T *def_ctx = &entry->es_info.ufunc->uf_script_ctx; - if (def_ctx->sc_sid > 0) - return vim_strsave(SCRIPT_ITEM(def_ctx->sc_sid)->sn_name); - } - else if (exestack.ga_len > 0) - { - // Walk the stack backwards, starting from the current frame. - for (idx = exestack.ga_len - 1; idx; --idx) + if (def_ctx->sc_sid > 0) + return vim_strsave(SCRIPT_ITEM(def_ctx->sc_sid)->sn_name); + else + return NULL; + } + else if (entry->es_type == ETYPE_AUCMD) { - entry = ((estack_T *)exestack.ga_data) + idx; + sctx_T *def_ctx = acp_script_ctx(entry->es_info.aucmd); - if (entry->es_type == ETYPE_SCRIPT) - return vim_strsave(entry->es_name); + if (def_ctx->sc_sid > 0) + return vim_strsave(SCRIPT_ITEM(def_ctx->sc_sid)->sn_name); + else + return NULL; + } + else if (entry->es_type == ETYPE_SCRIPT) + { + return vim_strsave(entry->es_name); } } return NULL; diff --git a/src/structs.h b/src/structs.h index 05ea6fc52..176a86c1a 100644 --- a/src/structs.h +++ b/src/structs.h @@ -2073,7 +2073,7 @@ struct partial_S dict_T *pt_dict; // dict for "self" }; -typedef struct AutoPatCmd_S AutoPatCmd; +typedef struct AutoPatCmd_S AutoPatCmd_T; /* * Entry in the execution stack "exestack". @@ -2100,7 +2100,7 @@ typedef struct { #if defined(FEAT_EVAL) ufunc_T *ufunc; // function info #endif - AutoPatCmd *aucmd; // autocommand info + AutoPatCmd_T *aucmd; // autocommand info except_T *except; // exception info } es_info; #if defined(FEAT_EVAL) diff --git a/src/testdir/test_expand.vim b/src/testdir/test_expand.vim index 32c3b429a..4f5bb67d2 100644 --- a/src/testdir/test_expand.vim +++ b/src/testdir/test_expand.vim @@ -169,43 +169,52 @@ endfunc func Test_expand_script_source() let lines0 =<< trim [SCRIPT] - let g:script_level[0] = expand('<script>:t') + call extend(g:script_level, [expand('<script>:t')]) so Xscript1 func F0() - let g:func_level[0] = expand('<script>:t') + call extend(g:func_level, [expand('<script>:t')]) endfunc + + au User * call extend(g:au_level, [expand('<script>:t')]) [SCRIPT] let lines1 =<< trim [SCRIPT] - let g:script_level[1] = expand('<script>:t') + call extend(g:script_level, [expand('<script>:t')]) so Xscript2 func F1() - let g:func_level[1] = expand('<script>:t') + call extend(g:func_level, [expand('<script>:t')]) endfunc + + au User * call extend(g:au_level, [expand('<script>:t')]) [SCRIPT] let lines2 =<< trim [SCRIPT] - let g:script_level[2] = expand('<script>:t') + call extend(g:script_level, [expand('<script>:t')]) func F2() - let g:func_level[2] = expand('<script>:t') + call extend(g:func_level, [expand('<script>:t')]) endfunc + + au User * call extend(g:au_level, [expand('<script>:t')]) [SCRIPT] call writefile(lines0, 'Xscript0') call writefile(lines1, 'Xscript1') call writefile(lines2, 'Xscript2') - " Check the expansion of <script> at script and function level. - let g:script_level = ['', '', ''] - let g:func_level = ['', '', ''] + " Check the expansion of <script> at different levels. + let g:script_level = [] + let g:func_level = [] + let g:au_level = [] so Xscript0 call F0() call F1() call F2() + doautocmd User call assert_equal(['Xscript0', 'Xscript1', 'Xscript2'], g:script_level) call assert_equal(['Xscript0', 'Xscript1', 'Xscript2'], g:func_level) + call assert_equal(['Xscript2', 'Xscript1', 'Xscript0'], g:au_level) unlet g:script_level g:func_level delfunc F0 diff --git a/src/version.c b/src/version.c index e1a5bbd66..40ed18989 100644 --- a/src/version.c +++ b/src/version.c @@ -747,6 +747,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ /**/ + 4749, +/**/ 4748, /**/ 4747, |