0
0
mirror of https://github.com/vim/vim.git synced 2025-09-25 03:54:15 -04:00

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)
This commit is contained in:
zeertzjq
2023-04-18 21:04:53 +01:00
committed by Bram Moolenaar
parent 142ffb024d
commit a1f2b5ddc6
3 changed files with 51 additions and 15 deletions

View File

@@ -651,30 +651,55 @@ func Test_defer_throw()
call assert_false(filereadable('XDeleteTwo')) call assert_false(filereadable('XDeleteTwo'))
endfunc endfunc
func Test_defer_quitall() func Test_defer_quitall_func()
let lines =<< trim END let lines =<< trim END
vim9script
func DeferLevelTwo() func DeferLevelTwo()
call writefile(['text'], 'XQuitallTwo', 'D') call writefile(['text'], 'XQuitallFuncTwo', 'D')
call writefile(['quit'], 'XQuitallThree', 'a') call writefile(['quit'], 'XQuitallFuncThree', 'a')
qa! qa!
endfunc endfunc
func DeferLevelOne()
call writefile(['text'], 'XQuitalFunclOne', 'D')
defer DeferLevelTwo()
endfunc
call DeferLevelOne()
END
call writefile(lines, 'XdeferQuitallFunc', 'D')
call system(GetVimCommand() .. ' -X -S XdeferQuitallFunc')
call assert_equal(0, v:shell_error)
call assert_false(filereadable('XQuitallFuncOne'))
call assert_false(filereadable('XQuitallFuncTwo'))
call assert_equal(['quit'], readfile('XQuitallFuncThree'))
call delete('XQuitallFuncThree')
endfunc
func Test_defer_quitall_def()
let lines =<< trim END
vim9script
def DeferLevelTwo()
call writefile(['text'], 'XQuitallDefTwo', 'D')
call writefile(['quit'], 'XQuitallDefThree', 'a')
qa!
enddef
def DeferLevelOne() def DeferLevelOne()
call writefile(['text'], 'XQuitallOne', 'D') call writefile(['text'], 'XQuitallDefOne', 'D')
call DeferLevelTwo() defer DeferLevelTwo()
enddef enddef
DeferLevelOne() DeferLevelOne()
END END
call writefile(lines, 'XdeferQuitall', 'D') call writefile(lines, 'XdeferQuitallDef', 'D')
let res = system(GetVimCommand() .. ' -X -S XdeferQuitall') call system(GetVimCommand() .. ' -X -S XdeferQuitallDef')
call assert_equal(0, v:shell_error) call assert_equal(0, v:shell_error)
call assert_false(filereadable('XQuitallOne')) call assert_false(filereadable('XQuitallDefOne'))
call assert_false(filereadable('XQuitallTwo')) call assert_false(filereadable('XQuitallDefTwo'))
call assert_equal(['quit'], readfile('XQuitallThree')) call assert_equal(['quit'], readfile('XQuitallDefThree'))
call delete('XQuitallThree') call delete('XQuitallDefThree')
endfunc endfunc
func Test_defer_quitall_in_expr_func() func Test_defer_quitall_in_expr_func()
@@ -693,7 +718,7 @@ func Test_defer_quitall_in_expr_func()
call Test_defer_in_funcref() call Test_defer_in_funcref()
END END
call writefile(lines, 'XdeferQuitallExpr', 'D') call writefile(lines, 'XdeferQuitallExpr', 'D')
let res = system(GetVimCommand() .. ' -X -S XdeferQuitallExpr') call system(GetVimCommand() .. ' -X -S XdeferQuitallExpr')
call assert_equal(0, v:shell_error) call assert_equal(0, v:shell_error)
call assert_false(filereadable('Xentry0')) call assert_false(filereadable('Xentry0'))
call assert_false(filereadable('Xentry1')) call assert_false(filereadable('Xentry1'))

View File

@@ -695,6 +695,8 @@ static char *(features[]) =
static int included_patches[] = static int included_patches[] =
{ /* Add new patch number below this line */ { /* Add new patch number below this line */
/**/
1468,
/**/ /**/
1467, 1467,
/**/ /**/

View File

@@ -1063,6 +1063,10 @@ invoke_defer_funcs(ectx_T *ectx)
int obj_off = functv->v_type == VAR_PARTIAL ? 1 : 0; int obj_off = functv->v_type == VAR_PARTIAL ? 1 : 0;
int argcount = l->lv_len - 1 - obj_off; int argcount = l->lv_len - 1 - obj_off;
if (functv->vval.v_string == NULL)
// already being called, can happen if function does ":qa"
continue;
if (obj_off == 1) if (obj_off == 1)
arg_li = arg_li->li_next; // second list item is the object arg_li = arg_li->li_next; // second list item is the object
for (i = 0; i < argcount; ++i) for (i = 0; i < argcount; ++i)
@@ -1082,9 +1086,14 @@ invoke_defer_funcs(ectx_T *ectx)
if (funcexe.fe_object != NULL) if (funcexe.fe_object != NULL)
++funcexe.fe_object->obj_refcount; ++funcexe.fe_object->obj_refcount;
} }
(void)call_func(functv->vval.v_string, -1,
&rettv, argcount, argvars, &funcexe); char_u *name = functv->vval.v_string;
functv->vval.v_string = NULL;
(void)call_func(name, -1, &rettv, argcount, argvars, &funcexe);
clear_tv(&rettv); clear_tv(&rettv);
vim_free(name);
} }
} }