mirror of
https://github.com/neovim/neovim.git
synced 2025-09-06 03:18:16 +00:00
vim-patch:9.0.0397: :defer not tested with exceptions and ":qa!"
Problem: :defer not tested with exceptions and ":qa!".
Solution: Test :defer works when exceptions are thrown and when ":qa!" is
used. Invoke the deferred calls on exit.
58779858fb
Co-authored-by: Bram Moolenaar <Bram@vim.org>
This commit is contained in:
@@ -1176,7 +1176,7 @@ void call_user_func(ufunc_T *fp, int argcount, typval_T *argvars, typval_T *rett
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Invoke functions added with ":defer".
|
// Invoke functions added with ":defer".
|
||||||
handle_defer();
|
handle_defer_one(current_funccal);
|
||||||
|
|
||||||
RedrawingDisabled--;
|
RedrawingDisabled--;
|
||||||
|
|
||||||
@@ -3174,10 +3174,10 @@ void add_defer(char *name, int argcount_arg, typval_T *argvars)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Invoked after a function has finished: invoke ":defer" functions.
|
/// Invoked after a function has finished: invoke ":defer" functions.
|
||||||
static void handle_defer(void)
|
static void handle_defer_one(funccall_T *funccal)
|
||||||
{
|
{
|
||||||
for (int idx = current_funccal->fc_defer.ga_len - 1; idx >= 0; idx--) {
|
for (int idx = funccal->fc_defer.ga_len - 1; idx >= 0; idx--) {
|
||||||
defer_T *dr = ((defer_T *)current_funccal->fc_defer.ga_data) + idx;
|
defer_T *dr = ((defer_T *)funccal->fc_defer.ga_data) + idx;
|
||||||
funcexe_T funcexe = { .fe_evaluate = true };
|
funcexe_T funcexe = { .fe_evaluate = true };
|
||||||
typval_T rettv;
|
typval_T rettv;
|
||||||
rettv.v_type = VAR_UNKNOWN; // tv_clear() uses this
|
rettv.v_type = VAR_UNKNOWN; // tv_clear() uses this
|
||||||
@@ -3188,7 +3188,15 @@ static void handle_defer(void)
|
|||||||
tv_clear(&dr->dr_argvars[i]);
|
tv_clear(&dr->dr_argvars[i]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ga_clear(¤t_funccal->fc_defer);
|
ga_clear(&funccal->fc_defer);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Called when exiting: call all defer functions.
|
||||||
|
void invoke_all_defer(void)
|
||||||
|
{
|
||||||
|
for (funccall_T *funccal = current_funccal; funccal != NULL; funccal = funccal->caller) {
|
||||||
|
handle_defer_one(funccal);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// ":1,25call func(arg1, arg2)" function call.
|
/// ":1,25call func(arg1, arg2)" function call.
|
||||||
|
@@ -30,6 +30,7 @@
|
|||||||
#include "nvim/eval.h"
|
#include "nvim/eval.h"
|
||||||
#include "nvim/eval/typval.h"
|
#include "nvim/eval/typval.h"
|
||||||
#include "nvim/eval/typval_defs.h"
|
#include "nvim/eval/typval_defs.h"
|
||||||
|
#include "nvim/eval/userfunc.h"
|
||||||
#include "nvim/event/multiqueue.h"
|
#include "nvim/event/multiqueue.h"
|
||||||
#include "nvim/event/stream.h"
|
#include "nvim/event/stream.h"
|
||||||
#include "nvim/ex_cmds.h"
|
#include "nvim/ex_cmds.h"
|
||||||
@@ -693,6 +694,9 @@ void getout(int exitval)
|
|||||||
// Position the cursor on the last screen line, below all the text
|
// Position the cursor on the last screen line, below all the text
|
||||||
ui_cursor_goto(Rows - 1, 0);
|
ui_cursor_goto(Rows - 1, 0);
|
||||||
|
|
||||||
|
// Invoked all deferred functions in the function stack.
|
||||||
|
invoke_all_defer();
|
||||||
|
|
||||||
// Optionally print hashtable efficiency.
|
// Optionally print hashtable efficiency.
|
||||||
hash_debug_results();
|
hash_debug_results();
|
||||||
|
|
||||||
|
@@ -584,5 +584,54 @@ func Test_defer()
|
|||||||
call assert_fails('defer Part("arg2")', 'E1300:')
|
call assert_fails('defer Part("arg2")', 'E1300:')
|
||||||
endfunc
|
endfunc
|
||||||
|
|
||||||
|
func DeferLevelTwo()
|
||||||
|
call writefile(['text'], 'XDeleteTwo', 'D')
|
||||||
|
throw 'someerror'
|
||||||
|
endfunc
|
||||||
|
|
||||||
|
" def DeferLevelOne()
|
||||||
|
func DeferLevelOne()
|
||||||
|
call writefile(['text'], 'XDeleteOne', 'D')
|
||||||
|
call g:DeferLevelTwo()
|
||||||
|
" enddef
|
||||||
|
endfunc
|
||||||
|
|
||||||
|
func Test_defer_throw()
|
||||||
|
let caught = 'no'
|
||||||
|
try
|
||||||
|
call DeferLevelOne()
|
||||||
|
catch /someerror/
|
||||||
|
let caught = 'yes'
|
||||||
|
endtry
|
||||||
|
call assert_equal('yes', caught)
|
||||||
|
call assert_false(filereadable('XDeleteOne'))
|
||||||
|
call assert_false(filereadable('XDeleteTwo'))
|
||||||
|
endfunc
|
||||||
|
|
||||||
|
func Test_defer_quitall()
|
||||||
|
let lines =<< trim END
|
||||||
|
" vim9script
|
||||||
|
func DeferLevelTwo()
|
||||||
|
call writefile(['text'], 'XQuitallTwo', 'D')
|
||||||
|
qa!
|
||||||
|
endfunc
|
||||||
|
|
||||||
|
" def DeferLevelOne()
|
||||||
|
func DeferLevelOne()
|
||||||
|
call writefile(['text'], 'XQuitallOne', 'D')
|
||||||
|
call DeferLevelTwo()
|
||||||
|
" enddef
|
||||||
|
endfunc
|
||||||
|
|
||||||
|
" DeferLevelOne()
|
||||||
|
call DeferLevelOne()
|
||||||
|
END
|
||||||
|
call writefile(lines, 'XdeferQuitall', 'D')
|
||||||
|
let res = system(GetVimCommandClean() .. ' -X -S XdeferQuitall')
|
||||||
|
call assert_equal(0, v:shell_error)
|
||||||
|
call assert_false(filereadable('XQuitallOne'))
|
||||||
|
call assert_false(filereadable('XQuitallTwo'))
|
||||||
|
endfunc
|
||||||
|
|
||||||
|
|
||||||
" vim: shiftwidth=2 sts=2 expandtab
|
" vim: shiftwidth=2 sts=2 expandtab
|
||||||
|
Reference in New Issue
Block a user