diff options
author | zeertzjq <zeertzjq@outlook.com> | 2022-09-16 23:09:26 +0800 |
---|---|---|
committer | GitHub <noreply@github.com> | 2022-09-16 23:09:26 +0800 |
commit | 6b2f0f43b5f9d375d2be1b4eb4784716dd89ec8f (patch) | |
tree | 1e53e27a8ca184decab0a7929b80870c7e406832 /src/nvim/eval/userfunc.c | |
parent | a0642ec75e5986af03829ad4f448e300fa40ebb4 (diff) | |
download | rneovim-6b2f0f43b5f9d375d2be1b4eb4784716dd89ec8f.tar.gz rneovim-6b2f0f43b5f9d375d2be1b4eb4784716dd89ec8f.tar.bz2 rneovim-6b2f0f43b5f9d375d2be1b4eb4784716dd89ec8f.zip |
fix(eval)!: make Lua Funcref work as method and in substitute() (#20217)
BREAKING CHANGE: When using a Funcref converted from a Lua function as
a method in Vim script, the result of the base expression is now passed
as the first argument instead of being ignored.
vim-patch:8.2.5117: crash when calling a Lua callback from a :def function
Problem: Crash when calling a Lua callback from a :def function. (Bohdan
Makohin)
Solution: Handle FC_CFUNC in call_user_func_check(). (closes vim/vim#10587)
https://github.com/vim/vim/commit/7d149f899d423b7bf2b90d7b11ebe3e560c462b9
Diffstat (limited to 'src/nvim/eval/userfunc.c')
-rw-r--r-- | src/nvim/eval/userfunc.c | 47 |
1 files changed, 29 insertions, 18 deletions
diff --git a/src/nvim/eval/userfunc.c b/src/nvim/eval/userfunc.c index 30814a8d35..f28af5a6cc 100644 --- a/src/nvim/eval/userfunc.c +++ b/src/nvim/eval/userfunc.c @@ -1199,6 +1199,34 @@ static bool func_name_refcount(char_u *name) return isdigit(*name) || *name == '<'; } +/// Call a user function after checking the arguments. +static int call_user_func_check(ufunc_T *fp, int argcount, typval_T *argvars, typval_T *rettv, + funcexe_T *funcexe, dict_T *selfdict) + FUNC_ATTR_NONNULL_ARG(1, 3, 4, 5) +{ + if (fp->uf_flags & FC_LUAREF) { + return typval_exec_lua_callable(fp->uf_luaref, argcount, argvars, rettv); + } + + if ((fp->uf_flags & FC_RANGE) && funcexe->fe_doesrange != NULL) { + *funcexe->fe_doesrange = true; + } + int error; + if (argcount < fp->uf_args.ga_len - fp->uf_def_args.ga_len) { + error = FCERR_TOOFEW; + } else if (!fp->uf_varargs && argcount > fp->uf_args.ga_len) { + error = FCERR_TOOMANY; + } else if ((fp->uf_flags & FC_DICT) && selfdict == NULL) { + error = FCERR_DICT; + } else { + // Call the user function. + call_user_func(fp, argcount, argvars, rettv, funcexe->fe_firstline, funcexe->fe_lastline, + (fp->uf_flags & FC_DICT) ? selfdict : NULL); + error = FCERR_NONE; + } + return error; +} + static funccal_entry_T *funccal_stack = NULL; /// Save the current function call pointer, and set it to NULL. @@ -1524,8 +1552,6 @@ int call_func(const char *funcname, int len, typval_T *rettv, int argcount_in, t if (fp != NULL && (fp->uf_flags & FC_DELETED)) { error = FCERR_DELETED; - } else if (fp != NULL && (fp->uf_flags & FC_LUAREF)) { - error = typval_exec_lua_callable(fp->uf_luaref, argcount, argvars, rettv); } else if (fp != NULL) { if (funcexe->fe_argv_func != NULL) { // postponed filling in the arguments, do it now @@ -1534,22 +1560,7 @@ int call_func(const char *funcname, int len, typval_T *rettv, int argcount_in, t argv_add_base(funcexe->fe_basetv, &argvars, &argcount, argv, &argv_base); - if (fp->uf_flags & FC_RANGE && funcexe->fe_doesrange != NULL) { - *funcexe->fe_doesrange = true; - } - if (argcount < fp->uf_args.ga_len - fp->uf_def_args.ga_len) { - error = FCERR_TOOFEW; - } else if (!fp->uf_varargs && argcount > fp->uf_args.ga_len) { - error = FCERR_TOOMANY; - } else if ((fp->uf_flags & FC_DICT) && selfdict == NULL) { - error = FCERR_DICT; - } else { - // Call the user function. - call_user_func(fp, argcount, argvars, rettv, funcexe->fe_firstline, - funcexe->fe_lastline, - (fp->uf_flags & FC_DICT) ? selfdict : NULL); - error = FCERR_NONE; - } + error = call_user_func_check(fp, argcount, argvars, rettv, funcexe, selfdict); } } else if (funcexe->fe_basetv != NULL) { // expr->method(): Find the method name in the table, call its |