]> granicus.if.org Git - vim/commitdiff
patch 8.2.4749: <script> is not expanded in autocmd context v8.2.4749
authorLemonBoy <thatlemon@gmail.com>
Thu, 14 Apr 2022 14:39:43 +0000 (15:39 +0100)
committerBram Moolenaar <Bram@vim.org>
Thu, 14 Apr 2022 14:39:43 +0000 (15:39 +0100)
Problem:    <script> is not expanded in autocmd context.
Solution:   Add the context to the pattern struct. (closes #10144)
            Rename AutoPatCmd to AutoPatCmd_T.

src/autocmd.c
src/proto/autocmd.pro
src/scriptfile.c
src/structs.h
src/testdir/test_expand.vim
src/version.c

index 3b384f5f96a1a60056b370f91bf717d36f3c37c5..223f92cf6a4cb3e8ff40b62fb781f2dbaeaf5aaf 100644 (file)
@@ -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
@@ -2422,6 +2429,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".
@@ -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
index 366d7aa4dc04458c3a28a77376e097f46d8fab3e..ddf391516a7b911be89f320887dabca5ee31984c 100644 (file)
@@ -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);
index 2a1f84a50e6c0a27823027cb3a770f6c283b5a70..3dfb1c43cc0ea8c312b730375c3318ac626714ba 100644 (file)
@@ -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;
index 05ea6fc522495ae10a4b72bddbd821f1c8891064..176a86c1a3bbaec5ab9226b9db325b4bee103984 100644 (file)
@@ -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)
index 32c3b429ab938771f042426257e12dd809c75808..4f5bb67d2199112e4c97f0f1c6aaa213f56f6e38 100644 (file)
@@ -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
index e1a5bbd661fdb7c6fd75a20ad31dd52276a29803..40ed18989eab77fc5a7f65d5c2a9928975f08ad6 100644 (file)
@@ -746,6 +746,8 @@ static char *(features[]) =
 
 static int included_patches[] =
 {   /* Add new patch number below this line */
+/**/
+    4749,
 /**/
     4748,
 /**/