commit 8e0ad6e261b81e9e2649bdba103904867b7ff6ef
parent 0a3645a72307afa563683a6e06c544810e0b65eb
Author: zeertzjq <zeertzjq@outlook.com>
Date: Wed, 19 Apr 2023 07:52:53 +0800
vim-patch:9.0.1462: recursively calling :defer function if it does :qa
Problem: Recursively calling :defer function if it does :qa.
Solution: Clear the defer entry before calling the function. (closes vim/vim#12266)
https://github.com/vim/vim/commit/42994bf678f46dc9ca66e49f512261da8864fff6
Co-authored-by: Bram Moolenaar <Bram@vim.org>
Diffstat:
2 files changed, 18 insertions(+), 2 deletions(-)
diff --git a/src/nvim/eval/userfunc.c b/src/nvim/eval/userfunc.c
@@ -3242,12 +3242,24 @@ static void handle_defer_one(funccall_T *funccal)
{
for (int idx = funccal->fc_defer.ga_len - 1; idx >= 0; idx--) {
defer_T *dr = ((defer_T *)funccal->fc_defer.ga_data) + idx;
+
+ if (dr->dr_name == NULL) {
+ // already being called, can happen if function does ":qa"
+ continue;
+ }
+
funcexe_T funcexe = { .fe_evaluate = true };
+
typval_T rettv;
rettv.v_type = VAR_UNKNOWN; // tv_clear() uses this
- call_func(dr->dr_name, -1, &rettv, dr->dr_argcount, dr->dr_argvars, &funcexe);
+
+ char *name = dr->dr_name;
+ dr->dr_name = NULL;
+
+ call_func(name, -1, &rettv, dr->dr_argcount, dr->dr_argvars, &funcexe);
+
tv_clear(&rettv);
- xfree(dr->dr_name);
+ xfree(name);
for (int i = dr->dr_argcount - 1; i >= 0; i--) {
tv_clear(&dr->dr_argvars[i]);
}
diff --git a/test/old/testdir/test_user_func.vim b/test/old/testdir/test_user_func.vim
@@ -614,6 +614,7 @@ func Test_defer_quitall()
" vim9script
func DeferLevelTwo()
call writefile(['text'], 'XQuitallTwo', 'D')
+ call writefile(['quit'], 'XQuitallThree', 'a')
qa!
endfunc
@@ -632,6 +633,9 @@ func Test_defer_quitall()
call assert_equal(0, v:shell_error)
call assert_false(filereadable('XQuitallOne'))
call assert_false(filereadable('XQuitallTwo'))
+ call assert_equal(['quit'], readfile('XQuitallThree'))
+
+ call delete('XQuitallThree')
endfunc
func Test_defer_quitall_in_expr_func()