aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorzeertzjq <zeertzjq@outlook.com>2023-04-16 11:37:41 +0800
committerzeertzjq <zeertzjq@outlook.com>2023-04-16 15:04:41 +0800
commit7b05ddbb72717f995fedc81583d73f82c78c881d (patch)
tree0e09fc8651f9fabd194751f2b9fcd56c3c1118d8
parent335bef0c211dc962499814d248670ff17758a642 (diff)
downloadrneovim-7b05ddbb72717f995fedc81583d73f82c78c881d.tar.gz
rneovim-7b05ddbb72717f995fedc81583d73f82c78c881d.tar.bz2
rneovim-7b05ddbb72717f995fedc81583d73f82c78c881d.zip
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. https://github.com/vim/vim/commit/58779858fb5a82a3233af5d4237a3cece88c10d4 Co-authored-by: Bram Moolenaar <Bram@vim.org>
-rw-r--r--src/nvim/eval/userfunc.c18
-rw-r--r--src/nvim/main.c4
-rw-r--r--test/old/testdir/test_user_func.vim49
3 files changed, 66 insertions, 5 deletions
diff --git a/src/nvim/eval/userfunc.c b/src/nvim/eval/userfunc.c
index e9e780747a..0a8e5c349a 100644
--- a/src/nvim/eval/userfunc.c
+++ b/src/nvim/eval/userfunc.c
@@ -1176,7 +1176,7 @@ void call_user_func(ufunc_T *fp, int argcount, typval_T *argvars, typval_T *rett
}
// Invoke functions added with ":defer".
- handle_defer();
+ handle_defer_one(current_funccal);
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.
-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--) {
- defer_T *dr = ((defer_T *)current_funccal->fc_defer.ga_data) + idx;
+ for (int idx = funccal->fc_defer.ga_len - 1; idx >= 0; idx--) {
+ defer_T *dr = ((defer_T *)funccal->fc_defer.ga_data) + idx;
funcexe_T funcexe = { .fe_evaluate = true };
typval_T rettv;
rettv.v_type = VAR_UNKNOWN; // tv_clear() uses this
@@ -3188,7 +3188,15 @@ static void handle_defer(void)
tv_clear(&dr->dr_argvars[i]);
}
}
- ga_clear(&current_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.
diff --git a/src/nvim/main.c b/src/nvim/main.c
index 0ef1fc9391..698c2dcc4f 100644
--- a/src/nvim/main.c
+++ b/src/nvim/main.c
@@ -30,6 +30,7 @@
#include "nvim/eval.h"
#include "nvim/eval/typval.h"
#include "nvim/eval/typval_defs.h"
+#include "nvim/eval/userfunc.h"
#include "nvim/event/multiqueue.h"
#include "nvim/event/stream.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
ui_cursor_goto(Rows - 1, 0);
+ // Invoked all deferred functions in the function stack.
+ invoke_all_defer();
+
// Optionally print hashtable efficiency.
hash_debug_results();
diff --git a/test/old/testdir/test_user_func.vim b/test/old/testdir/test_user_func.vim
index fd70d1acb0..4bb4078a1c 100644
--- a/test/old/testdir/test_user_func.vim
+++ b/test/old/testdir/test_user_func.vim
@@ -584,5 +584,54 @@ func Test_defer()
call assert_fails('defer Part("arg2")', 'E1300:')
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