Mercurial > vim
changeset 32276:774c94489feb v9.0.1469
patch 9.0.1469: deferred functions not called from autocommands
Commit: https://github.com/vim/vim/commit/960cf9119e3f4922ca9719feb5e0c0bc5e3b9840
Author: zeertzjq <zeertzjq@outlook.com>
Date: Tue Apr 18 21:52:54 2023 +0100
patch 9.0.1469: deferred functions not called from autocommands
Problem: Deferred functions not called from autocommands.
Solution: Also go through the funccal_stack. (closes https://github.com/vim/vim/issues/12267)
author | Bram Moolenaar <Bram@vim.org> |
---|---|
date | Tue, 18 Apr 2023 23:00:03 +0200 |
parents | 07141765bae8 |
children | 272dc3dcacd3 |
files | src/testdir/test_user_func.vim src/userfunc.c src/version.c |
diffstat | 3 files changed, 51 insertions(+), 15 deletions(-) [+] |
line wrap: on
line diff
--- a/src/testdir/test_user_func.vim +++ b/src/testdir/test_user_func.vim @@ -702,6 +702,33 @@ func Test_defer_quitall_def() call delete('XQuitallDefThree') endfunc +func Test_defer_quitall_autocmd() + let lines =<< trim END + autocmd User DeferAutocmdThree qa! + + func DeferLevelTwo() + call writefile(['text'], 'XQuitallAutocmdTwo', 'D') + doautocmd User DeferAutocmdThree + endfunc + + autocmd User DeferAutocmdTwo ++nested call DeferLevelTwo() + + def DeferLevelOne() + call writefile(['text'], 'XQuitallAutocmdOne', 'D') + doautocmd User DeferAutocmdTwo + enddef + + autocmd User DeferAutocmdOne ++nested call DeferLevelOne() + + doautocmd User DeferAutocmdOne + END + call writefile(lines, 'XdeferQuitallAutocmd', 'D') + let res = system(GetVimCommand() .. ' -X -S XdeferQuitallAutocmd') + call assert_equal(0, v:shell_error) + call assert_false(filereadable('XQuitallAutocmdOne')) + call assert_false(filereadable('XQuitallAutocmdTwo')) +endfunc + func Test_defer_quitall_in_expr_func() let lines =<< trim END def DefIndex(idx: number, val: string): bool
--- a/src/userfunc.c +++ b/src/userfunc.c @@ -6122,27 +6122,34 @@ handle_defer_one(funccall_T *funccal) ga_clear(&funccal->fc_defer); } + static void +invoke_funccall_defer(funccall_T *fc) +{ + if (fc->fc_ectx != NULL) + { + // :def function + unwind_def_callstack(fc->fc_ectx); + may_invoke_defer_funcs(fc->fc_ectx); + } + else + { + // legacy function + handle_defer_one(fc); + } +} + /* * Called when exiting: call all defer functions. */ void invoke_all_defer(void) { - funccall_T *funccal; - - for (funccal = current_funccal; funccal != NULL; - funccal = funccal->fc_caller) - if (funccal->fc_ectx != NULL) - { - // :def function - unwind_def_callstack(funccal->fc_ectx); - may_invoke_defer_funcs(funccal->fc_ectx); - } - else - { - // legacy function - handle_defer_one(funccal); - } + for (funccal_entry_T *fce = funccal_stack; fce != NULL; fce = fce->next) + for (funccall_T *fc = fce->top_funccal; fc != NULL; fc = fc->fc_caller) + invoke_funccall_defer(fc); + + for (funccall_T *fc = current_funccal; fc != NULL; fc = fc->fc_caller) + invoke_funccall_defer(fc); } /*