aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorzeertzjq <zeertzjq@outlook.com>2022-08-23 12:20:37 +0800
committerzeertzjq <zeertzjq@outlook.com>2022-08-23 17:48:12 +0800
commitd0b9fe2d5a95def67acc83f713b932f3f12dea08 (patch)
tree3c21b8d776e099c1f55c25a6593ccb3cbf1a9f7a /src
parent7afc17dec17bcc40c646b796f05d373e46916dd7 (diff)
downloadrneovim-d0b9fe2d5a95def67acc83f713b932f3f12dea08.tar.gz
rneovim-d0b9fe2d5a95def67acc83f713b932f3f12dea08.tar.bz2
rneovim-d0b9fe2d5a95def67acc83f713b932f3f12dea08.zip
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. https://github.com/vim/vim/commit/eca7c60d68e63001dbe3c8e5d240b0895e607fc3 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.
Diffstat (limited to 'src')
-rw-r--r--src/nvim/autocmd.c37
-rw-r--r--src/nvim/autocmd.h3
-rw-r--r--src/nvim/runtime.c37
-rw-r--r--src/nvim/testdir/test_expand.vim27
4 files changed, 65 insertions, 39 deletions
diff --git a/src/nvim/autocmd.c b/src/nvim/autocmd.c
index 579c6c029f..c20db2910c 100644
--- a/src/nvim/autocmd.c
+++ b/src/nvim/autocmd.c
@@ -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)) {
diff --git a/src/nvim/autocmd.h b/src/nvim/autocmd.h
index d559d8c3d2..75a8a7aaa1 100644
--- a/src/nvim/autocmd.h
+++ b/src/nvim/autocmd.h
@@ -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
diff --git a/src/nvim/runtime.c b/src/nvim/runtime.c
index 412b78728e..038aad12a4 100644
--- a/src/nvim/runtime.c
+++ b/src/nvim/runtime.c
@@ -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;
diff --git a/src/nvim/testdir/test_expand.vim b/src/nvim/testdir/test_expand.vim
index 6579e09d5e..aa131a49ff 100644
--- a/src/nvim/testdir/test_expand.vim
+++ b/src/nvim/testdir/test_expand.vim
@@ -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