Skip to content

Commit a1f2b5d

Browse files
zeertzjqbrammool
authored andcommitted
patch 9.0.1468: recursively calling :defer function if it does :qa
Problem: Recursively calling :defer function if it does :qa in a compiled function. Solution: Clear the defer entry before calling the function. (closes #12271)
1 parent 142ffb0 commit a1f2b5d

3 files changed

Lines changed: 51 additions & 15 deletions

File tree

src/testdir/test_user_func.vim

Lines changed: 38 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -651,30 +651,55 @@ func Test_defer_throw()
651651
call assert_false(filereadable('XDeleteTwo'))
652652
endfunc
653653

654-
func Test_defer_quitall()
654+
func Test_defer_quitall_func()
655655
let lines =<< trim END
656-
vim9script
657656
func DeferLevelTwo()
658-
call writefile(['text'], 'XQuitallTwo', 'D')
659-
call writefile(['quit'], 'XQuitallThree', 'a')
657+
call writefile(['text'], 'XQuitallFuncTwo', 'D')
658+
call writefile(['quit'], 'XQuitallFuncThree', 'a')
660659
qa!
661660
endfunc
662661

662+
func DeferLevelOne()
663+
call writefile(['text'], 'XQuitalFunclOne', 'D')
664+
defer DeferLevelTwo()
665+
endfunc
666+
667+
call DeferLevelOne()
668+
END
669+
call writefile(lines, 'XdeferQuitallFunc', 'D')
670+
call system(GetVimCommand() .. ' -X -S XdeferQuitallFunc')
671+
call assert_equal(0, v:shell_error)
672+
call assert_false(filereadable('XQuitallFuncOne'))
673+
call assert_false(filereadable('XQuitallFuncTwo'))
674+
call assert_equal(['quit'], readfile('XQuitallFuncThree'))
675+
676+
call delete('XQuitallFuncThree')
677+
endfunc
678+
679+
func Test_defer_quitall_def()
680+
let lines =<< trim END
681+
vim9script
682+
def DeferLevelTwo()
683+
call writefile(['text'], 'XQuitallDefTwo', 'D')
684+
call writefile(['quit'], 'XQuitallDefThree', 'a')
685+
qa!
686+
enddef
687+
663688
def DeferLevelOne()
664-
call writefile(['text'], 'XQuitallOne', 'D')
665-
call DeferLevelTwo()
689+
call writefile(['text'], 'XQuitallDefOne', 'D')
690+
defer DeferLevelTwo()
666691
enddef
667692

668693
DeferLevelOne()
669694
END
670-
call writefile(lines, 'XdeferQuitall', 'D')
671-
let res = system(GetVimCommand() .. ' -X -S XdeferQuitall')
695+
call writefile(lines, 'XdeferQuitallDef', 'D')
696+
call system(GetVimCommand() .. ' -X -S XdeferQuitallDef')
672697
call assert_equal(0, v:shell_error)
673-
call assert_false(filereadable('XQuitallOne'))
674-
call assert_false(filereadable('XQuitallTwo'))
675-
call assert_equal(['quit'], readfile('XQuitallThree'))
698+
call assert_false(filereadable('XQuitallDefOne'))
699+
call assert_false(filereadable('XQuitallDefTwo'))
700+
call assert_equal(['quit'], readfile('XQuitallDefThree'))
676701

677-
call delete('XQuitallThree')
702+
call delete('XQuitallDefThree')
678703
endfunc
679704

680705
func Test_defer_quitall_in_expr_func()
@@ -693,7 +718,7 @@ func Test_defer_quitall_in_expr_func()
693718
call Test_defer_in_funcref()
694719
END
695720
call writefile(lines, 'XdeferQuitallExpr', 'D')
696-
let res = system(GetVimCommand() .. ' -X -S XdeferQuitallExpr')
721+
call system(GetVimCommand() .. ' -X -S XdeferQuitallExpr')
697722
call assert_equal(0, v:shell_error)
698723
call assert_false(filereadable('Xentry0'))
699724
call assert_false(filereadable('Xentry1'))

src/version.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -695,6 +695,8 @@ static char *(features[]) =
695695

696696
static int included_patches[] =
697697
{ /* Add new patch number below this line */
698+
/**/
699+
1468,
698700
/**/
699701
1467,
700702
/**/

src/vim9execute.c

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1063,6 +1063,10 @@ invoke_defer_funcs(ectx_T *ectx)
10631063
int obj_off = functv->v_type == VAR_PARTIAL ? 1 : 0;
10641064
int argcount = l->lv_len - 1 - obj_off;
10651065

1066+
if (functv->vval.v_string == NULL)
1067+
// already being called, can happen if function does ":qa"
1068+
continue;
1069+
10661070
if (obj_off == 1)
10671071
arg_li = arg_li->li_next; // second list item is the object
10681072
for (i = 0; i < argcount; ++i)
@@ -1082,9 +1086,14 @@ invoke_defer_funcs(ectx_T *ectx)
10821086
if (funcexe.fe_object != NULL)
10831087
++funcexe.fe_object->obj_refcount;
10841088
}
1085-
(void)call_func(functv->vval.v_string, -1,
1086-
&rettv, argcount, argvars, &funcexe);
1089+
1090+
char_u *name = functv->vval.v_string;
1091+
functv->vval.v_string = NULL;
1092+
1093+
(void)call_func(name, -1, &rettv, argcount, argvars, &funcexe);
1094+
10871095
clear_tv(&rettv);
1096+
vim_free(name);
10881097
}
10891098
}
10901099

0 commit comments

Comments
 (0)