diff options
author | zeertzjq <zeertzjq@outlook.com> | 2023-04-16 11:37:41 +0800 |
---|---|---|
committer | zeertzjq <zeertzjq@outlook.com> | 2023-04-16 15:04:41 +0800 |
commit | 7b05ddbb72717f995fedc81583d73f82c78c881d (patch) | |
tree | 0e09fc8651f9fabd194751f2b9fcd56c3c1118d8 | |
parent | 335bef0c211dc962499814d248670ff17758a642 (diff) | |
download | rneovim-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.c | 18 | ||||
-rw-r--r-- | src/nvim/main.c | 4 | ||||
-rw-r--r-- | test/old/testdir/test_user_func.vim | 49 |
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(¤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. 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 |