Patch 8.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.
Files:      src/autocmd.c, src/proto/autocmd.pro, src/scriptfile.c,
            src/structs.h, src/testdir/test_expand.vim


*** ../vim-8.2.4748/src/autocmd.c       2022-04-09 18:17:30.060746546 +0100
--- src/autocmd.c       2022-04-14 15:35:58.641829848 +0100
***************
*** 55,61 ****
      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
      struct AutoCmd  *next;            // next AutoCmd in list
  } AutoCmd;
  
--- 55,61 ----
      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 it is defined
      struct AutoCmd  *next;            // next AutoCmd in list
  } AutoCmd;
  
***************
*** 234,245 ****
      char_u    *sfname;        // sfname to match with
      char_u    *tail;          // tail of fname
      event_T   event;          // current event
      int               arg_bufnr;      // Initially equal to <abuf>, set to 
zero when
                                // buf is deleted.
!     AutoPatCmd   *next;               // chain of active apc-s for 
auto-invalidation
  };
  
! static AutoPatCmd *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) \
--- 234,246 ----
      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_T *next;               // chain of active apc-s for 
auto-invalidation
  };
  
! 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,270 ****
  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 int au_find_group(char_u *name);
  
  static event_T        last_event;
--- 265,271 ----
  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_T *apc, int stop_at_last);
  static int au_find_group(char_u *name);
  
  static event_T        last_event;
***************
*** 453,461 ****
      void
  aubuflocal_remove(buf_T *buf)
  {
!     AutoPat   *ap;
!     event_T   event;
!     AutoPatCmd        *apc;
  
      // invalidate currently executing autocommands
      for (apc = active_apc_list; apc; apc = apc->next)
--- 454,462 ----
      void
  aubuflocal_remove(buf_T *buf)
  {
!     AutoPat       *ap;
!     event_T       event;
!     AutoPatCmd_T    *apc;
  
      // invalidate currently executing autocommands
      for (apc = active_apc_list; apc; apc = apc->next)
***************
*** 1914,1920 ****
      int               save_autocmd_busy;
      int               save_autocmd_nested;
      static int        nesting = 0;
!     AutoPatCmd        patcmd;
      AutoPat   *ap;
      sctx_T    save_current_sctx;
  #ifdef FEAT_EVAL
--- 1915,1921 ----
      int               save_autocmd_busy;
      int               save_autocmd_nested;
      static int        nesting = 0;
!     AutoPatCmd_T patcmd;
      AutoPat   *ap;
      sctx_T    save_current_sctx;
  #ifdef FEAT_EVAL
***************
*** 2173,2187 ****
      tail = gettail(fname);
  
      // Find first autocommand that matches
      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
--- 2174,2187 ----
      tail = gettail(fname);
  
      // Find first autocommand that matches
+     CLEAR_FIELD(patcmd);
      patcmd.curpat = first_autopat[(int)event];
      patcmd.group = group;
      patcmd.fname = fname;
      patcmd.sfname = sfname;
      patcmd.tail = tail;
      patcmd.event = event;
      patcmd.arg_bufnr = autocmd_bufnr;
      auto_next_pat(&patcmd, FALSE);
  
      // found one, start executing the autocommands
***************
*** 2363,2378 ****
   */
      static void
  auto_next_pat(
!     AutoPatCmd        *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;
  
!     VIM_CLEAR(*sourcing_namep);
  
      for (ap = apc->curpat; ap != NULL && !got_int; ap = ap->next)
      {
--- 2363,2383 ----
   */
      static void
  auto_next_pat(
!     AutoPatCmd_T *apc,
      int               stop_at_last)       // stop when 'last' flag is set
  {
      AutoPat   *ap;
      AutoCmd   *cp;
      char_u    *name;
      char      *s;
!     estack_T  *entry;
!     char_u    *namep;
! 
!     entry = ((estack_T *)exestack.ga_data) + exestack.ga_len - 1;
  
!     // 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,2411 ****
            {
                name = event_nr2name(apc->event);
                s = _("%s Autocommands for \"%s\"");
!               *sourcing_namep = alloc(STRLEN(s)
!                                             + STRLEN(name) + ap->patlen + 1);
!               if (*sourcing_namep != NULL)
                {
!                   sprintf((char *)*sourcing_namep, s,
!                                              (char *)name, (char *)ap->pat);
                    if (p_verbose >= 8)
                    {
                        verbose_enter();
!                       smsg(_("Executing %s"), *sourcing_namep);
                        verbose_leave();
                    }
                }
  
                apc->curpat = ap;
                apc->nextcmd = ap->cmds;
                // mark last command
--- 2397,2418 ----
            {
                name = event_nr2name(apc->event);
                s = _("%s Autocommands for \"%s\"");
!               namep = alloc(STRLEN(s) + STRLEN(name) + ap->patlen + 1);
!               if (namep != NULL)
                {
!                   sprintf((char *)namep, s, (char *)name, (char *)ap->pat);
                    if (p_verbose >= 8)
                    {
                        verbose_enter();
!                       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,2428 ****
--- 2430,2444 ----
  }
  
  /*
+  * 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,2440 ****
        int indent UNUSED,
        getline_opt_T options UNUSED)
  {
!     AutoPatCmd            *acp = (AutoPatCmd *)cookie;
      char_u        *retval;
      AutoCmd       *ac;
  
--- 2450,2456 ----
        int indent UNUSED,
        getline_opt_T options UNUSED)
  {
!     AutoPatCmd_T    *acp = (AutoPatCmd_T *)cookie;
      char_u        *retval;
      AutoCmd       *ac;
  
***************
*** 2481,2486 ****
--- 2497,2503 ----
        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
*** ../vim-8.2.4748/src/proto/autocmd.pro       2022-04-08 15:17:53.067952553 
+0100
--- src/proto/autocmd.pro       2022-04-14 15:36:36.865820601 +0100
***************
*** 7,13 ****
  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);
  void ex_doautoall(exarg_T *eap);
  int check_nomodeline(char_u **argp);
  void aucmd_prepbuf(aco_save_T *aco, buf_T *buf);
--- 7,13 ----
  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_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,21 ****
--- 16,22 ----
  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,35 ****
  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);
  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);
--- 27,36 ----
  int has_textyankpost(void);
  int has_completechanged(void);
  int has_modechanged(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);
*** ../vim-8.2.4748/src/scriptfile.c    2022-04-14 12:58:19.604895030 +0100
--- src/scriptfile.c    2022-04-14 15:29:19.265779919 +0100
***************
*** 157,183 ****
        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
      // instead.
      if (which == ESTACK_SCRIPT)
      {
!       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)
            {
!               entry = ((estack_T *)exestack.ga_data) + idx;
  
!               if (entry->es_type == ETYPE_SCRIPT)
!                   return vim_strsave(entry->es_name);
            }
        }
        return NULL;
--- 157,192 ----
        return NULL;
      }
  
!     // 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)
      {
!       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)
        {
!           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
!                   return NULL;
!           }
!           else if (entry->es_type == ETYPE_AUCMD)
            {
!               sctx_T *def_ctx = acp_script_ctx(entry->es_info.aucmd);
  
!               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;
*** ../vim-8.2.4748/src/structs.h       2022-04-12 14:22:46.890838165 +0100
--- src/structs.h       2022-04-14 15:36:19.653824975 +0100
***************
*** 2073,2079 ****
      dict_T    *pt_dict;       // dict for "self"
  };
  
! typedef struct AutoPatCmd_S AutoPatCmd;
  
  /*
   * Entry in the execution stack "exestack".
--- 2073,2079 ----
      dict_T    *pt_dict;       // dict for "self"
  };
  
! typedef struct AutoPatCmd_S AutoPatCmd_T;
  
  /*
   * Entry in the execution stack "exestack".
***************
*** 2100,2106 ****
  #if defined(FEAT_EVAL)
        ufunc_T *ufunc;     // function info
  #endif
!       AutoPatCmd *aucmd;  // autocommand info
        except_T   *except; // exception info
      } es_info;
  #if defined(FEAT_EVAL)
--- 2100,2106 ----
  #if defined(FEAT_EVAL)
        ufunc_T *ufunc;     // function info
  #endif
!       AutoPatCmd_T *aucmd;  // autocommand info
        except_T   *except; // exception info
      } es_info;
  #if defined(FEAT_EVAL)
*** ../vim-8.2.4748/src/testdir/test_expand.vim 2022-04-12 12:54:06.917010952 
+0100
--- src/testdir/test_expand.vim 2022-04-14 15:29:19.265779919 +0100
***************
*** 169,211 ****
  
  func Test_expand_script_source()
    let lines0 =<< trim [SCRIPT]
!     let g:script_level[0] = expand('<script>:t')
      so Xscript1
      func F0()
!       let g:func_level[0] = expand('<script>:t')
      endfunc
    [SCRIPT]
  
    let lines1 =<< trim [SCRIPT]
!     let g:script_level[1] = expand('<script>:t')
      so Xscript2
      func F1()
!       let g:func_level[1] = expand('<script>:t')
      endfunc
    [SCRIPT]
  
    let lines2 =<< trim [SCRIPT]
!     let g:script_level[2] = expand('<script>:t')
      func F2()
!       let g:func_level[2] = expand('<script>:t')
      endfunc
    [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 = ['', '', '']
  
    so Xscript0
    call F0()
    call F1()
    call F2()
  
    call assert_equal(['Xscript0', 'Xscript1', 'Xscript2'], g:script_level)
    call assert_equal(['Xscript0', 'Xscript1', 'Xscript2'], g:func_level)
  
    unlet g:script_level g:func_level
    delfunc F0
--- 169,220 ----
  
  func Test_expand_script_source()
    let lines0 =<< trim [SCRIPT]
!     call extend(g:script_level, [expand('<script>:t')])
      so Xscript1
      func F0()
!       call extend(g:func_level, [expand('<script>:t')])
      endfunc
+ 
+     au User * call extend(g:au_level, [expand('<script>:t')])
    [SCRIPT]
  
    let lines1 =<< trim [SCRIPT]
!     call extend(g:script_level, [expand('<script>:t')])
      so Xscript2
      func F1()
!       call extend(g:func_level, [expand('<script>:t')])
      endfunc
+ 
+     au User * call extend(g:au_level, [expand('<script>:t')])
    [SCRIPT]
  
    let lines2 =<< trim [SCRIPT]
!     call extend(g:script_level, [expand('<script>:t')])
      func F2()
!       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 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
*** ../vim-8.2.4748/src/version.c       2022-04-14 12:58:19.608895029 +0100
--- src/version.c       2022-04-14 15:30:35.345815517 +0100
***************
*** 748,749 ****
--- 748,751 ----
  {   /* Add new patch number below this line */
+ /**/
+     4749,
  /**/

-- 
If the Universe is constantly expanding, why can't I ever find a parking space?

 /// Bram Moolenaar -- [email protected] -- http://www.Moolenaar.net   \\\
///                                                                      \\\
\\\        sponsor Vim, vote for features -- http://www.Vim.org/sponsor/ ///
 \\\            help me help AIDS victims -- http://ICCF-Holland.org    ///

-- 
-- 
You received this message from the "vim_dev" maillist.
Do not top-post! Type your reply below the text you are replying to.
For more information, visit http://www.vim.org/maillist.php

--- 
You received this message because you are subscribed to the Google Groups 
"vim_dev" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
To view this discussion on the web visit 
https://groups.google.com/d/msgid/vim_dev/20220414144030.B1C741C0EA0%40moolenaar.net.

Raspunde prin e-mail lui