mirror of
https://github.com/neovim/neovim.git
synced 2025-09-27 21:48:35 +00:00
vim-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 vim/vim#10144)
Rename AutoPatCmd to AutoPatCmd_T.
eca7c60d68
Omit AutoPatCmd -> AutoPatCmd_T rename as it is inconsistent.
Use `.sn_name` instead of `->sn_name` as v8.2.0154 hasn't been ported.
Omit acp_script_stx(), use member directly.
This commit is contained in:
@@ -1811,16 +1811,15 @@ bool apply_autocmds_group(event_T event, char *fname, char *fname_io, bool force
|
||||
char *tail = path_tail(fname);
|
||||
|
||||
// Find first autocommand that matches
|
||||
AutoPatCmd 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;
|
||||
AutoPatCmd patcmd = {
|
||||
.curpat = first_autopat[(int)event],
|
||||
.group = group,
|
||||
.fname = fname,
|
||||
.sfname = sfname,
|
||||
.tail = tail,
|
||||
.event = event,
|
||||
.arg_bufnr = autocmd_bufnr,
|
||||
};
|
||||
auto_next_pat(&patcmd, false);
|
||||
|
||||
// found one, start executing the autocommands
|
||||
@@ -1984,9 +1983,12 @@ void auto_next_pat(AutoPatCmd *apc, int stop_at_last)
|
||||
AutoPat *ap;
|
||||
AutoCmd *cp;
|
||||
char *s;
|
||||
char **const sourcing_namep = &SOURCING_NAME;
|
||||
|
||||
XFREE_CLEAR(*sourcing_namep);
|
||||
estack_T *const entry = ((estack_T *)exestack.ga_data) + exestack.ga_len - 1;
|
||||
|
||||
// Clear the exestack entry for this ETYPE_AUCMD entry.
|
||||
XFREE_CLEAR(entry->es_name);
|
||||
entry->es_info.aucmd = NULL;
|
||||
|
||||
for (ap = apc->curpat; ap != NULL && !got_int; ap = ap->next) {
|
||||
apc->curpat = NULL;
|
||||
@@ -2011,14 +2013,18 @@ void auto_next_pat(AutoPatCmd *apc, int stop_at_last)
|
||||
const size_t sourcing_name_len
|
||||
= (STRLEN(s) + strlen(name) + (size_t)ap->patlen + 1);
|
||||
|
||||
*sourcing_namep = xmalloc(sourcing_name_len);
|
||||
snprintf(*sourcing_namep, sourcing_name_len, s, name, ap->pat);
|
||||
char *const namep = xmalloc(sourcing_name_len);
|
||||
snprintf(namep, sourcing_name_len, s, name, 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
|
||||
@@ -2150,6 +2156,7 @@ char *getnextac(int c, void *cookie, int indent, bool do_concat)
|
||||
// lua code, so that it works properly
|
||||
autocmd_nested = ac->nested;
|
||||
current_sctx = ac->script_ctx;
|
||||
acp->script_ctx = current_sctx;
|
||||
|
||||
if (ac->exec.type == CALLABLE_CB) {
|
||||
if (call_autocmd_callback(ac, acp)) {
|
||||
|
@@ -29,7 +29,7 @@ struct AutoCmd_S {
|
||||
bool nested; // If autocommands nest here
|
||||
bool last; // last command in list
|
||||
int64_t id; // ID used for uniquely tracking an autocmd.
|
||||
sctx_T script_ctx; // script context where defined
|
||||
sctx_T script_ctx; // script context where it is defined
|
||||
char *desc; // Description for the autocmd.
|
||||
AutoCmd *next; // Next AutoCmd in list
|
||||
};
|
||||
@@ -59,6 +59,7 @@ struct AutoPatCmd_S {
|
||||
char *sfname; // sfname to match with
|
||||
char *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
|
||||
Object *data; // arbitrary data
|
||||
AutoPatCmd *next; // chain of active apc-s for auto-invalidation
|
||||
|
@@ -104,7 +104,7 @@ void estack_pop(void)
|
||||
/// ESTACK_SCRIPT for <script>.
|
||||
char *estack_sfile(estack_arg_T which)
|
||||
{
|
||||
estack_T *entry = ((estack_T *)exestack.ga_data) + exestack.ga_len - 1;
|
||||
const estack_T *entry = ((estack_T *)exestack.ga_data) + exestack.ga_len - 1;
|
||||
if (which == ESTACK_SFILE && entry->es_type != ETYPE_UFUNC) {
|
||||
if (entry->es_name == NULL) {
|
||||
return NULL;
|
||||
@@ -112,22 +112,31 @@ char *estack_sfile(estack_arg_T which)
|
||||
return xstrdup(entry->es_name);
|
||||
}
|
||||
|
||||
// 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) {
|
||||
sctx_T *def_ctx = &entry->es_info.ufunc->uf_script_ctx;
|
||||
if (def_ctx->sc_sid > 0) {
|
||||
return xstrdup((char *)(SCRIPT_ITEM(def_ctx->sc_sid).sn_name));
|
||||
}
|
||||
} else if (exestack.ga_len > 0) {
|
||||
// Walk the stack backwards, starting from the current frame.
|
||||
for (int idx = exestack.ga_len - 1; idx; idx--) {
|
||||
entry = ((estack_T *)exestack.ga_data) + idx;
|
||||
if (entry->es_type == ETYPE_SCRIPT) {
|
||||
return xstrdup(entry->es_name);
|
||||
assert(entry == ((estack_T *)exestack.ga_data) + exestack.ga_len - 1);
|
||||
// Walk the stack backwards, starting from the current frame.
|
||||
for (int idx = exestack.ga_len - 1; idx >= 0; idx--, entry--) {
|
||||
if (entry->es_type == ETYPE_UFUNC) {
|
||||
const sctx_T *const def_ctx = &entry->es_info.ufunc->uf_script_ctx;
|
||||
|
||||
if (def_ctx->sc_sid > 0) {
|
||||
return xstrdup((char *)(SCRIPT_ITEM(def_ctx->sc_sid).sn_name));
|
||||
} else {
|
||||
return NULL;
|
||||
}
|
||||
} else if (entry->es_type == ETYPE_AUCMD) {
|
||||
const sctx_T *const def_ctx = &entry->es_info.aucmd->script_ctx;
|
||||
|
||||
if (def_ctx->sc_sid > 0) {
|
||||
return xstrdup((char *)(SCRIPT_ITEM(def_ctx->sc_sid).sn_name));
|
||||
} else {
|
||||
return NULL;
|
||||
}
|
||||
} else if (entry->es_type == ETYPE_SCRIPT) {
|
||||
return xstrdup(entry->es_name);
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
|
@@ -157,43 +157,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
|
||||
|
Reference in New Issue
Block a user