0
0
mirror of https://github.com/vim/vim.git synced 2025-09-24 03:44:06 -04:00

patch 8.2.4749: <script> is not expanded in autocmd context

Problem:    <script> is not expanded in autocmd context.
Solution:   Add the context to the pattern struct. (closes #10144)
            Rename AutoPatCmd to AutoPatCmd_T.
This commit is contained in:
LemonBoy
2022-04-14 15:39:43 +01:00
committed by Bram Moolenaar
parent 8944551534
commit eca7c60d68
6 changed files with 86 additions and 48 deletions

View File

@@ -55,7 +55,7 @@ typedef struct AutoCmd
char once; // "One shot": removed after execution char once; // "One shot": removed after execution
char nested; // If autocommands nest here. char nested; // If autocommands nest here.
char last; // last command in list 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 struct AutoCmd *next; // next AutoCmd in list
} AutoCmd; } AutoCmd;
@@ -234,12 +234,13 @@ struct AutoPatCmd_S
char_u *sfname; // sfname to match with char_u *sfname; // sfname to match with
char_u *tail; // tail of fname char_u *tail; // tail of fname
event_T event; // current event 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 int arg_bufnr; // Initially equal to <abuf>, set to zero when
// buf is deleted. // 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 // Macro to loop over all the patterns for an autocmd event
#define FOR_ALL_AUTOCMD_PATTERNS(event, ap) \ #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 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 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_T *apc, int stop_at_last);
static int au_find_group(char_u *name); static int au_find_group(char_u *name);
static event_T last_event; static event_T last_event;
@@ -453,9 +454,9 @@ au_cleanup(void)
void void
aubuflocal_remove(buf_T *buf) aubuflocal_remove(buf_T *buf)
{ {
AutoPat *ap; AutoPat *ap;
event_T event; event_T event;
AutoPatCmd *apc; AutoPatCmd_T *apc;
// invalidate currently executing autocommands // invalidate currently executing autocommands
for (apc = active_apc_list; apc; apc = apc->next) for (apc = active_apc_list; apc; apc = apc->next)
@@ -1914,7 +1915,7 @@ apply_autocmds_group(
int save_autocmd_busy; int save_autocmd_busy;
int save_autocmd_nested; int save_autocmd_nested;
static int nesting = 0; static int nesting = 0;
AutoPatCmd patcmd; AutoPatCmd_T patcmd;
AutoPat *ap; AutoPat *ap;
sctx_T save_current_sctx; sctx_T save_current_sctx;
#ifdef FEAT_EVAL #ifdef FEAT_EVAL
@@ -2173,15 +2174,14 @@ apply_autocmds_group(
tail = gettail(fname); tail = gettail(fname);
// Find first autocommand that matches // Find first autocommand that matches
CLEAR_FIELD(patcmd);
patcmd.curpat = first_autopat[(int)event]; patcmd.curpat = first_autopat[(int)event];
patcmd.nextcmd = NULL;
patcmd.group = group; patcmd.group = group;
patcmd.fname = fname; patcmd.fname = fname;
patcmd.sfname = sfname; patcmd.sfname = sfname;
patcmd.tail = tail; patcmd.tail = tail;
patcmd.event = event; patcmd.event = event;
patcmd.arg_bufnr = autocmd_bufnr; patcmd.arg_bufnr = autocmd_bufnr;
patcmd.next = NULL;
auto_next_pat(&patcmd, FALSE); auto_next_pat(&patcmd, FALSE);
// found one, start executing the autocommands // found one, start executing the autocommands
@@ -2363,16 +2363,21 @@ is_autocmd_blocked(void)
*/ */
static void static void
auto_next_pat( auto_next_pat(
AutoPatCmd *apc, AutoPatCmd_T *apc,
int stop_at_last) // stop when 'last' flag is set int stop_at_last) // stop when 'last' flag is set
{ {
AutoPat *ap; AutoPat *ap;
AutoCmd *cp; AutoCmd *cp;
char_u *name; char_u *name;
char *s; char *s;
char_u **sourcing_namep = &SOURCING_NAME; estack_T *entry;
char_u *namep;
VIM_CLEAR(*sourcing_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) for (ap = apc->curpat; ap != NULL && !got_int; ap = ap->next)
{ {
@@ -2392,20 +2397,22 @@ auto_next_pat(
{ {
name = event_nr2name(apc->event); name = event_nr2name(apc->event);
s = _("%s Autocommands for \"%s\""); s = _("%s Autocommands for \"%s\"");
*sourcing_namep = alloc(STRLEN(s) namep = alloc(STRLEN(s) + STRLEN(name) + ap->patlen + 1);
+ STRLEN(name) + ap->patlen + 1); if (namep != NULL)
if (*sourcing_namep != NULL)
{ {
sprintf((char *)*sourcing_namep, s, sprintf((char *)namep, s, (char *)name, (char *)ap->pat);
(char *)name, (char *)ap->pat);
if (p_verbose >= 8) if (p_verbose >= 8)
{ {
verbose_enter(); verbose_enter();
smsg(_("Executing %s"), *sourcing_namep); smsg(_("Executing %s"), namep);
verbose_leave(); verbose_leave();
} }
} }
// Update the exestack entry for this autocmd.
entry->es_name = namep;
entry->es_info.aucmd = apc;
apc->curpat = ap; apc->curpat = ap;
apc->nextcmd = ap->cmds; apc->nextcmd = ap->cmds;
// mark last command // 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. * Get next autocommand command.
* Called by do_cmdline() to get the next line for ":if". * Called by do_cmdline() to get the next line for ":if".
@@ -2434,7 +2450,7 @@ getnextac(
int indent UNUSED, int indent UNUSED,
getline_opt_T options UNUSED) getline_opt_T options UNUSED)
{ {
AutoPatCmd *acp = (AutoPatCmd *)cookie; AutoPatCmd_T *acp = (AutoPatCmd_T *)cookie;
char_u *retval; char_u *retval;
AutoCmd *ac; AutoCmd *ac;
@@ -2481,6 +2497,7 @@ getnextac(
au_del_cmd(ac); au_del_cmd(ac);
autocmd_nested = ac->nested; autocmd_nested = ac->nested;
current_sctx = ac->script_ctx; current_sctx = ac->script_ctx;
acp->script_ctx = current_sctx;
if (ac->last) if (ac->last)
acp->nextcmd = NULL; acp->nextcmd = NULL;
else else

View File

@@ -7,7 +7,7 @@ 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(exarg_T *eap, 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_start, 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);
void aucmd_prepbuf(aco_save_T *aco, buf_T *buf); 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_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 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 trigger_cursorhold(void);
int has_winscrolled(void);
int has_cursormoved(void); int has_cursormoved(void);
int has_cursormovedI(void); int has_cursormovedI(void);
int has_textchanged(void); int has_textchanged(void);
@@ -26,10 +27,10 @@ int has_cmdundefined(void);
int has_textyankpost(void); int has_textyankpost(void);
int has_completechanged(void); int has_completechanged(void);
int has_modechanged(void); int has_modechanged(void);
int has_winscrolled(void);
void block_autocmds(void); void block_autocmds(void);
void unblock_autocmds(void); void unblock_autocmds(void);
int is_autocmd_blocked(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); 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); int has_autocmd(event_T event, char_u *sfname, buf_T *buf);
char_u *get_augroup_name(expand_T *xp, int idx); char_u *get_augroup_name(expand_T *xp, int idx);

View File

@@ -157,27 +157,36 @@ estack_sfile(estack_arg_T which UNUSED)
return NULL; return NULL;
} }
// If evaluated in a function return the path of the script where the // If evaluated in a function or autocommand, return the path of the script
// function is defined, at script level the current script path is returned // where it is defined, at script level the current script path is returned
// instead. // instead.
if (which == ESTACK_SCRIPT) 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)
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; sctx_T *def_ctx = &entry->es_info.ufunc->uf_script_ctx;
if (entry->es_type == ETYPE_SCRIPT) if (def_ctx->sc_sid > 0)
return vim_strsave(entry->es_name); 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; return NULL;

View File

@@ -2073,7 +2073,7 @@ struct partial_S
dict_T *pt_dict; // dict for "self" dict_T *pt_dict; // dict for "self"
}; };
typedef struct AutoPatCmd_S AutoPatCmd; typedef struct AutoPatCmd_S AutoPatCmd_T;
/* /*
* Entry in the execution stack "exestack". * Entry in the execution stack "exestack".
@@ -2100,7 +2100,7 @@ typedef struct {
#if defined(FEAT_EVAL) #if defined(FEAT_EVAL)
ufunc_T *ufunc; // function info ufunc_T *ufunc; // function info
#endif #endif
AutoPatCmd *aucmd; // autocommand info AutoPatCmd_T *aucmd; // autocommand info
except_T *except; // exception info except_T *except; // exception info
} es_info; } es_info;
#if defined(FEAT_EVAL) #if defined(FEAT_EVAL)

View File

@@ -169,43 +169,52 @@ endfunc
func Test_expand_script_source() func Test_expand_script_source()
let lines0 =<< trim [SCRIPT] let lines0 =<< trim [SCRIPT]
let g:script_level[0] = expand('<script>:t') call extend(g:script_level, [expand('<script>:t')])
so Xscript1 so Xscript1
func F0() func F0()
let g:func_level[0] = expand('<script>:t') call extend(g:func_level, [expand('<script>:t')])
endfunc endfunc
au User * call extend(g:au_level, [expand('<script>:t')])
[SCRIPT] [SCRIPT]
let lines1 =<< trim [SCRIPT] let lines1 =<< trim [SCRIPT]
let g:script_level[1] = expand('<script>:t') call extend(g:script_level, [expand('<script>:t')])
so Xscript2 so Xscript2
func F1() func F1()
let g:func_level[1] = expand('<script>:t') call extend(g:func_level, [expand('<script>:t')])
endfunc endfunc
au User * call extend(g:au_level, [expand('<script>:t')])
[SCRIPT] [SCRIPT]
let lines2 =<< trim [SCRIPT] let lines2 =<< trim [SCRIPT]
let g:script_level[2] = expand('<script>:t') call extend(g:script_level, [expand('<script>:t')])
func F2() func F2()
let g:func_level[2] = expand('<script>:t') call extend(g:func_level, [expand('<script>:t')])
endfunc endfunc
au User * call extend(g:au_level, [expand('<script>:t')])
[SCRIPT] [SCRIPT]
call writefile(lines0, 'Xscript0') call writefile(lines0, 'Xscript0')
call writefile(lines1, 'Xscript1') call writefile(lines1, 'Xscript1')
call writefile(lines2, 'Xscript2') call writefile(lines2, 'Xscript2')
" Check the expansion of <script> at script and function level. " Check the expansion of <script> at different levels.
let g:script_level = ['', '', ''] let g:script_level = []
let g:func_level = ['', '', ''] let g:func_level = []
let g:au_level = []
so Xscript0 so Xscript0
call F0() call F0()
call F1() call F1()
call F2() call F2()
doautocmd User
call assert_equal(['Xscript0', 'Xscript1', 'Xscript2'], g:script_level) call assert_equal(['Xscript0', 'Xscript1', 'Xscript2'], g:script_level)
call assert_equal(['Xscript0', 'Xscript1', 'Xscript2'], g:func_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 unlet g:script_level g:func_level
delfunc F0 delfunc F0

View File

@@ -746,6 +746,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 */
/**/
4749,
/**/ /**/
4748, 4748,
/**/ /**/