aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorzeertzjq <zeertzjq@outlook.com>2023-04-16 10:51:27 +0800
committerzeertzjq <zeertzjq@outlook.com>2023-04-16 15:04:41 +0800
commit335bef0c211dc962499814d248670ff17758a642 (patch)
tree808c44bc0f507ad155927b41596a0408d0559a8d
parent0167649ce4071e60d985b65f3f9408ffb21cb58c (diff)
downloadrneovim-335bef0c211dc962499814d248670ff17758a642.tar.gz
rneovim-335bef0c211dc962499814d248670ff17758a642.tar.bz2
rneovim-335bef0c211dc962499814d248670ff17758a642.zip
vim-patch:9.0.0390: cannot use a partial with :defer
Problem: Cannot use a partial with :defer. Solution: Add the partial arguments before the other arguments. Disallow using a dictionary. https://github.com/vim/vim/commit/86d87256c4005c6215da5af2597fbf6f6304421f Co-authored-by: Bram Moolenaar <Bram@vim.org>
-rw-r--r--runtime/doc/userfunc.txt3
-rw-r--r--src/nvim/eval/userfunc.c26
-rw-r--r--test/old/testdir/test_user_func.vim25
3 files changed, 47 insertions, 7 deletions
diff --git a/runtime/doc/userfunc.txt b/runtime/doc/userfunc.txt
index 2c72f3d584..db0127df95 100644
--- a/runtime/doc/userfunc.txt
+++ b/runtime/doc/userfunc.txt
@@ -406,7 +406,8 @@ GetArg()->TheFunc()` does not work, it may work in a later version.
Errors are reported but do not cause aborting execution of deferred functions.
-No range is accepted.
+No range is accepted. The function can be a partial with extra arguments, but
+not with a dictionary. *E1300*
==============================================================================
diff --git a/src/nvim/eval/userfunc.c b/src/nvim/eval/userfunc.c
index 4b9bc1fdec..e9e780747a 100644
--- a/src/nvim/eval/userfunc.c
+++ b/src/nvim/eval/userfunc.c
@@ -81,6 +81,8 @@ static const char e_no_white_space_allowed_before_str_str[]
= N_("E1068: No white space allowed before '%s': %s");
static const char e_missing_heredoc_end_marker_str[]
= N_("E1145: Missing heredoc end marker: %s");
+static const char e_cannot_use_partial_with_dictionary_for_defer[]
+ = N_("E1300: Cannot use a partial with dictionary for :defer");
void func_init(void)
{
@@ -3062,7 +3064,7 @@ void ex_return(exarg_T *eap)
}
static int ex_call_inner(exarg_T *eap, char *name, char **arg, char *startarg,
- funcexe_T *funcexe_init, evalarg_T *const evalarg)
+ const funcexe_T *const funcexe_init, evalarg_T *const evalarg)
{
bool doesrange;
bool failed = false;
@@ -3116,16 +3118,32 @@ static int ex_call_inner(exarg_T *eap, char *name, char **arg, char *startarg,
/// Core part of ":defer func(arg)". "arg" points to the "(" and is advanced.
///
/// @return FAIL or OK.
-static int ex_defer_inner(char *name, char **arg, evalarg_T *const evalarg)
+static int ex_defer_inner(char *name, char **arg, const partial_T *const partial,
+ evalarg_T *const evalarg)
{
typval_T argvars[MAX_FUNC_ARGS + 1]; // vars for arguments
+ int partial_argc = 0; // number of partial arguments
int argcount = 0; // number of arguments found
if (current_funccal == NULL) {
semsg(_(e_str_not_inside_function), "defer");
return FAIL;
}
- if (get_func_arguments(arg, evalarg, false, argvars, &argcount) == FAIL) {
+ if (partial != NULL) {
+ if (partial->pt_dict != NULL) {
+ emsg(_(e_cannot_use_partial_with_dictionary_for_defer));
+ return FAIL;
+ }
+ if (partial->pt_argc > 0) {
+ partial_argc = partial->pt_argc;
+ for (int i = 0; i < partial_argc; i++) {
+ tv_copy(&partial->pt_argv[i], &argvars[i]);
+ }
+ }
+ }
+ int r = get_func_arguments(arg, evalarg, false, argvars + partial_argc, &argcount);
+ argcount += partial_argc;
+ if (r == FAIL) {
while (--argcount >= 0) {
tv_clear(&argvars[argcount]);
}
@@ -3236,7 +3254,7 @@ void ex_call(exarg_T *eap)
if (eap->cmdidx == CMD_defer) {
arg = startarg;
- failed = ex_defer_inner(name, &arg, &evalarg) == FAIL;
+ failed = ex_defer_inner(name, &arg, partial, &evalarg) == FAIL;
} else {
funcexe_T funcexe = FUNCEXE_INIT;
funcexe.fe_partial = partial;
diff --git a/test/old/testdir/test_user_func.vim b/test/old/testdir/test_user_func.vim
index 3579954fe6..fd70d1acb0 100644
--- a/test/old/testdir/test_user_func.vim
+++ b/test/old/testdir/test_user_func.vim
@@ -532,8 +532,11 @@ func Test_funcdef_alloc_failure()
bw!
endfunc
-func AddDefer(arg)
- call extend(g:deferred, [a:arg])
+func AddDefer(arg1, ...)
+ call extend(g:deferred, [a:arg1])
+ if a:0 == 1
+ call extend(g:deferred, [a:1])
+ endif
endfunc
func WithDeferTwo()
@@ -553,6 +556,13 @@ func WithDeferOne()
call extend(g:deferred, ['end One'])
endfunc
+func WithPartialDefer()
+ call extend(g:deferred, ['in Partial'])
+ let Part = funcref('AddDefer', ['arg1'])
+ defer Part("arg2")
+ call extend(g:deferred, ['end Partial'])
+endfunc
+
func Test_defer()
let g:deferred = []
call WithDeferOne()
@@ -561,6 +571,17 @@ func Test_defer()
unlet g:deferred
call assert_equal('', glob('Xfuncdefer'))
+
+ call assert_fails('defer delete("Xfuncdefer")->Another()', 'E488:')
+ call assert_fails('defer delete("Xfuncdefer").member', 'E488:')
+
+ let g:deferred = []
+ call WithPartialDefer()
+ call assert_equal(['in Partial', 'end Partial', 'arg1', 'arg2'], g:deferred)
+ unlet g:deferred
+
+ let Part = funcref('AddDefer', ['arg1'], {})
+ call assert_fails('defer Part("arg2")', 'E1300:')
endfunc