aboutsummaryrefslogtreecommitdiff
path: root/src/nvim/eval
diff options
context:
space:
mode:
authorzeertzjq <zeertzjq@outlook.com>2024-07-10 08:07:16 +0800
committerGitHub <noreply@github.com>2024-07-10 08:07:16 +0800
commit545aafbeb80eb52c182ce139800489b392a12d0d (patch)
tree580a4c7a0f42bddae3b4577054b8758906d4d631 /src/nvim/eval
parentf3c7fb9db176f32606e83eb47cc7549300191d2f (diff)
downloadrneovim-545aafbeb80eb52c182ce139800489b392a12d0d.tar.gz
rneovim-545aafbeb80eb52c182ce139800489b392a12d0d.tar.bz2
rneovim-545aafbeb80eb52c182ce139800489b392a12d0d.zip
vim-patch:9.1.0547: No way to get the arity of a Vim function (#29638)
Problem: No way to get the arity of a Vim function (Austin Ziegler) Solution: Enhance get() Vim script function to return the function argument info using get(func, "arity") (LemonBoy) fixes: vim/vim#15097 closes: vim/vim#15109 https://github.com/vim/vim/commit/48b7d05a4f88c4326bd5d7a73a523f2d953b3e51 Co-authored-by: LemonBoy <thatlemon@gmail.com>
Diffstat (limited to 'src/nvim/eval')
-rw-r--r--src/nvim/eval/funcs.c27
-rw-r--r--src/nvim/eval/userfunc.c38
2 files changed, 65 insertions, 0 deletions
diff --git a/src/nvim/eval/funcs.c b/src/nvim/eval/funcs.c
index c319bd8214..22e7f383a5 100644
--- a/src/nvim/eval/funcs.c
+++ b/src/nvim/eval/funcs.c
@@ -2372,6 +2372,33 @@ static void f_get(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
for (int i = 0; i < pt->pt_argc; i++) {
tv_list_append_tv(rettv->vval.v_list, &pt->pt_argv[i]);
}
+ } else if (strcmp(what, "arity") == 0) {
+ int required = 0;
+ int optional = 0;
+ bool varargs = false;
+ const char *name = partial_name(pt);
+
+ get_func_arity(name, &required, &optional, &varargs);
+
+ rettv->v_type = VAR_DICT;
+ tv_dict_alloc_ret(rettv);
+ dict_T *dict = rettv->vval.v_dict;
+
+ // Take into account the arguments of the partial, if any.
+ // Note that it is possible to supply more arguments than the function
+ // accepts.
+ if (pt->pt_argc >= required + optional) {
+ required = optional = 0;
+ } else if (pt->pt_argc > required) {
+ optional -= pt->pt_argc - required;
+ required = 0;
+ } else {
+ required -= pt->pt_argc;
+ }
+
+ tv_dict_add_nr(dict, S_LEN("required"), required);
+ tv_dict_add_nr(dict, S_LEN("optional"), optional);
+ tv_dict_add_bool(dict, S_LEN("varargs"), varargs);
} else {
semsg(_(e_invarg2), what);
}
diff --git a/src/nvim/eval/userfunc.c b/src/nvim/eval/userfunc.c
index 122a1ac8ab..42391ecec7 100644
--- a/src/nvim/eval/userfunc.c
+++ b/src/nvim/eval/userfunc.c
@@ -642,6 +642,44 @@ static char *fname_trans_sid(const char *const name, char *const fname_buf, char
return fname;
}
+int get_func_arity(const char *name, int *required, int *optional, bool *varargs)
+{
+ int argcount = 0;
+ int min_argcount = 0;
+
+ const EvalFuncDef *fdef = find_internal_func(name);
+ if (fdef != NULL) {
+ argcount = fdef->max_argc;
+ min_argcount = fdef->min_argc;
+ *varargs = false;
+ } else {
+ char fname_buf[FLEN_FIXED + 1];
+ char *tofree = NULL;
+ int error = FCERR_NONE;
+
+ // May need to translate <SNR>123_ to K_SNR.
+ char *fname = fname_trans_sid(name, fname_buf, &tofree, &error);
+ ufunc_T *ufunc = NULL;
+ if (error == FCERR_NONE) {
+ ufunc = find_func(fname);
+ }
+ xfree(tofree);
+
+ if (ufunc == NULL) {
+ return FAIL;
+ }
+
+ argcount = ufunc->uf_args.ga_len;
+ min_argcount = ufunc->uf_args.ga_len - ufunc->uf_def_args.ga_len;
+ *varargs = ufunc->uf_varargs;
+ }
+
+ *required = min_argcount;
+ *optional = argcount - min_argcount;
+
+ return OK;
+}
+
/// Find a function by name, return pointer to it in ufuncs.
///
/// @return NULL for unknown function.