diff options
author | zeertzjq <zeertzjq@outlook.com> | 2022-08-23 12:20:37 +0800 |
---|---|---|
committer | zeertzjq <zeertzjq@outlook.com> | 2022-08-23 17:48:12 +0800 |
commit | d0b9fe2d5a95def67acc83f713b932f3f12dea08 (patch) | |
tree | 3c21b8d776e099c1f55c25a6593ccb3cbf1a9f7a /src | |
parent | 7afc17dec17bcc40c646b796f05d373e46916dd7 (diff) | |
download | rneovim-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.c | 37 | ||||
-rw-r--r-- | src/nvim/autocmd.h | 3 | ||||
-rw-r--r-- | src/nvim/runtime.c | 37 | ||||
-rw-r--r-- | src/nvim/testdir/test_expand.vim | 27 |
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 |