mirror of
https://github.com/neovim/neovim.git
synced 2025-10-03 00:18:33 +00:00
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
48b7d05a4f
Co-authored-by: LemonBoy <thatlemon@gmail.com>
This commit is contained in:
@@ -3141,6 +3141,7 @@ M.funcs = {
|
||||
name = 'get',
|
||||
params = { { 'list', 'any[]' }, { 'idx', 'integer' }, { 'default', 'any' } },
|
||||
signature = 'get({list}, {idx} [, {default}])',
|
||||
tags = { 'get()-list' },
|
||||
},
|
||||
get__1 = {
|
||||
args = { 2, 3 },
|
||||
@@ -3153,6 +3154,7 @@ M.funcs = {
|
||||
name = 'get',
|
||||
params = { { 'blob', 'string' }, { 'idx', 'integer' }, { 'default', 'any' } },
|
||||
signature = 'get({blob}, {idx} [, {default}])',
|
||||
tags = { 'get()-blob' },
|
||||
},
|
||||
get__2 = {
|
||||
args = { 2, 3 },
|
||||
@@ -3168,23 +3170,38 @@ M.funcs = {
|
||||
name = 'get',
|
||||
params = { { 'dict', 'table<string,any>' }, { 'key', 'string' }, { 'default', 'any' } },
|
||||
signature = 'get({dict}, {key} [, {default}])',
|
||||
tags = { 'get()-dict' },
|
||||
},
|
||||
get__3 = {
|
||||
args = { 2, 3 },
|
||||
base = 1,
|
||||
desc = [=[
|
||||
Get item {what} from Funcref {func}. Possible values for
|
||||
Get item {what} from |Funcref| {func}. Possible values for
|
||||
{what} are:
|
||||
"name" The function name
|
||||
"func" The function
|
||||
"dict" The dictionary
|
||||
"args" The list with arguments
|
||||
"name" The function name
|
||||
"func" The function
|
||||
"dict" The dictionary
|
||||
"args" The list with arguments
|
||||
"arity" A dictionary with information about the number of
|
||||
arguments accepted by the function (minus the
|
||||
{arglist}) with the following fields:
|
||||
required the number of positional arguments
|
||||
optional the number of optional arguments,
|
||||
in addition to the required ones
|
||||
varargs |TRUE| if the function accepts a
|
||||
variable number of arguments |...|
|
||||
|
||||
Note: There is no error, if the {arglist} of
|
||||
the Funcref contains more arguments than the
|
||||
Funcref expects, it's not validated.
|
||||
|
||||
Returns zero on error.
|
||||
]=],
|
||||
name = 'get',
|
||||
params = { { 'func', 'function' }, { 'what', 'string' } },
|
||||
returns = 'any',
|
||||
signature = 'get({func}, {what})',
|
||||
tags = { 'get()-func' },
|
||||
},
|
||||
getbufinfo = {
|
||||
args = { 0, 1 },
|
||||
|
@@ -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);
|
||||
}
|
||||
|
@@ -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.
|
||||
|
Reference in New Issue
Block a user