mirror of
https://github.com/vim/vim
synced 2025-07-16 01:01:58 +00:00
patch 9.1.0547: No way to get the arity of a Vim function
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: #15097 closes: #15109 Signed-off-by: LemonBoy <thatlemon@gmail.com> Signed-off-by: Christian Brabandt <cb@256bit.org>
This commit is contained in:
committed by
Christian Brabandt
parent
03acd4761b
commit
48b7d05a4f
@ -1,4 +1,4 @@
|
||||
*builtin.txt* For Vim version 9.1. Last change: 2024 Jun 23
|
||||
*builtin.txt* For Vim version 9.1. Last change: 2024 Jul 09
|
||||
|
||||
|
||||
VIM REFERENCE MANUAL by Bram Moolenaar
|
||||
@ -3574,7 +3574,7 @@ garbagecollect([{atexit}]) *garbagecollect()*
|
||||
Return type: |String|
|
||||
|
||||
|
||||
get({list}, {idx} [, {default}]) *get()*
|
||||
get({list}, {idx} [, {default}]) *get()* *get()-list*
|
||||
Get item {idx} from |List| {list}. When this item is not
|
||||
available return {default}. Return zero when {default} is
|
||||
omitted.
|
||||
@ -3583,7 +3583,7 @@ get({list}, {idx} [, {default}]) *get()*
|
||||
<
|
||||
Return type: any, depending on {list}
|
||||
|
||||
get({blob}, {idx} [, {default}])
|
||||
get({blob}, {idx} [, {default}]) *get()-blob*
|
||||
Get byte {idx} from |Blob| {blob}. When this byte is not
|
||||
available return {default}. Return -1 when {default} is
|
||||
omitted.
|
||||
@ -3592,7 +3592,7 @@ get({blob}, {idx} [, {default}])
|
||||
<
|
||||
Return type: |Number|
|
||||
|
||||
get({dict}, {key} [, {default}])
|
||||
get({dict}, {key} [, {default}]) *get()-dict*
|
||||
Get item with key {key} from |Dictionary| {dict}. When this
|
||||
item is not available return {default}. Return zero when
|
||||
{default} is omitted. Useful example: >
|
||||
@ -3604,18 +3604,32 @@ get({dict}, {key} [, {default}])
|
||||
<
|
||||
Return type: any, depending on {dict}
|
||||
|
||||
get({func}, {what})
|
||||
Get item {what} from Funcref {func}. Possible values for
|
||||
get({func}, {what}) *get()-func*
|
||||
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.
|
||||
|
||||
Preferably used as a |method|: >
|
||||
myfunc->get(what)
|
||||
<
|
||||
Return type: any, depending on {func}
|
||||
Return type: any, depending on {func} and {what}
|
||||
|
||||
*getbufinfo()*
|
||||
getbufinfo([{buf}])
|
||||
|
@ -7783,6 +7783,10 @@ gdb-version terminal.txt /*gdb-version*
|
||||
ge motion.txt /*ge*
|
||||
gender-neutral helphelp.txt /*gender-neutral*
|
||||
get() builtin.txt /*get()*
|
||||
get()-blob builtin.txt /*get()-blob*
|
||||
get()-dict builtin.txt /*get()-dict*
|
||||
get()-func builtin.txt /*get()-func*
|
||||
get()-list builtin.txt /*get()-list*
|
||||
get-ms-debuggers debug.txt /*get-ms-debuggers*
|
||||
getbufinfo() builtin.txt /*getbufinfo()*
|
||||
getbufline() builtin.txt /*getbufline()*
|
||||
|
@ -1,4 +1,4 @@
|
||||
*version9.txt* For Vim version 9.1. Last change: 2024 Jul 06
|
||||
*version9.txt* For Vim version 9.1. Last change: 2024 Jul 08
|
||||
|
||||
|
||||
VIM REFERENCE MANUAL by Bram Moolenaar
|
||||
@ -41577,6 +41577,8 @@ Changed~
|
||||
- 'nrformat' accepts the new "blank" suboption, to determine a signed or
|
||||
unsigned number based on whitespace in front of a minus sign.
|
||||
- allow to specify a priority when defining a new sign |:sign-define|
|
||||
- provide information about function arguments using the get(func, "arity")
|
||||
function |get()-func|
|
||||
|
||||
*added-9.2*
|
||||
Added ~
|
||||
|
@ -5134,6 +5134,36 @@ f_get(typval_T *argvars, typval_T *rettv)
|
||||
list_append_tv(rettv->vval.v_list, &pt->pt_argv[i]);
|
||||
}
|
||||
}
|
||||
else if (STRCMP(what, "arity") == 0)
|
||||
{
|
||||
int required = 0, optional = 0, varargs = FALSE;
|
||||
char_u *name = partial_name(pt);
|
||||
|
||||
get_func_arity(name, &required, &optional, &varargs);
|
||||
|
||||
rettv->v_type = VAR_DICT;
|
||||
if (rettv_dict_alloc(rettv) == OK)
|
||||
{
|
||||
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;
|
||||
|
||||
dict_add_number(dict, "required", required);
|
||||
dict_add_number(dict, "optional", optional);
|
||||
dict_add_bool(dict, "varargs", varargs);
|
||||
}
|
||||
}
|
||||
else
|
||||
semsg(_(e_invalid_argument_str), what);
|
||||
|
||||
|
@ -95,4 +95,5 @@ int set_ref_in_call_stack(int copyID);
|
||||
int set_ref_in_functions(int copyID);
|
||||
int set_ref_in_func_args(int copyID);
|
||||
int set_ref_in_func(char_u *name, ufunc_T *fp_in, int copyID);
|
||||
int get_func_arity(char_u *name, int *required, int *optional, int *varargs);
|
||||
/* vim: set ft=c : */
|
||||
|
@ -142,20 +142,28 @@ func Test_get_func()
|
||||
let l:F = function('tr')
|
||||
call assert_equal('tr', get(l:F, 'name'))
|
||||
call assert_equal(l:F, get(l:F, 'func'))
|
||||
call assert_equal({'required': 3, 'optional': 0, 'varargs': v:false},
|
||||
\ get(l:F, 'arity'))
|
||||
|
||||
let Fb_func = function('s:FooBar')
|
||||
call assert_match('<SNR>\d\+_FooBar', get(Fb_func, 'name'))
|
||||
call assert_equal({'required': 0, 'optional': 0, 'varargs': v:false},
|
||||
\ get(Fb_func, 'arity'))
|
||||
let Fb_ref = funcref('s:FooBar')
|
||||
call assert_match('<SNR>\d\+_FooBar', get(Fb_ref, 'name'))
|
||||
call assert_equal({'required': 0, 'optional': 0, 'varargs': v:false},
|
||||
\ get(Fb_ref, 'arity'))
|
||||
|
||||
call assert_equal({'func has': 'no dict'}, get(l:F, 'dict', {'func has': 'no dict'}))
|
||||
call assert_equal(0, get(l:F, 'dict'))
|
||||
call assert_equal([], get(l:F, 'args'))
|
||||
|
||||
let NF = test_null_function()
|
||||
call assert_equal('', get(NF, 'name'))
|
||||
call assert_equal(NF, get(NF, 'func'))
|
||||
call assert_equal(0, get(NF, 'dict'))
|
||||
call assert_equal([], get(NF, 'args'))
|
||||
call assert_equal({'required': 0, 'optional': 0, 'varargs': v:false}, get(NF, 'arity'))
|
||||
endfunc
|
||||
|
||||
" get({partial}, {what} [, {default}]) - in test_partial.vim
|
||||
|
@ -311,6 +311,11 @@ func Test_auto_partial_rebind()
|
||||
endfunc
|
||||
|
||||
func Test_get_partial_items()
|
||||
func s:Qux(x, y, z=3, w=1, ...)
|
||||
endfunc
|
||||
func s:Qux1(x, y)
|
||||
endfunc
|
||||
|
||||
let dict = {'name': 'hello'}
|
||||
let args = ["foo", "bar"]
|
||||
let Func = function('MyDictFunc')
|
||||
@ -331,6 +336,23 @@ func Test_get_partial_items()
|
||||
let dict = {'partial has': 'no dict'}
|
||||
call assert_equal(dict, get(P, 'dict', dict))
|
||||
call assert_equal(0, get(l:P, 'dict'))
|
||||
|
||||
call assert_equal({'required': 2, 'optional': 2, 'varargs': v:true},
|
||||
\ get(funcref('s:Qux', []), 'arity'))
|
||||
call assert_equal({'required': 1, 'optional': 2, 'varargs': v:true},
|
||||
\ get(funcref('s:Qux', [1]), 'arity'))
|
||||
call assert_equal({'required': 0, 'optional': 2, 'varargs': v:true},
|
||||
\ get(funcref('s:Qux', [1, 2]), 'arity'))
|
||||
call assert_equal({'required': 0, 'optional': 1, 'varargs': v:true},
|
||||
\ get(funcref('s:Qux', [1, 2, 3]), 'arity'))
|
||||
call assert_equal({'required': 0, 'optional': 0, 'varargs': v:true},
|
||||
\ get(funcref('s:Qux', [1, 2, 3, 4]), 'arity'))
|
||||
" More args than expected is not an error
|
||||
call assert_equal({'required': 0, 'optional': 0, 'varargs': v:false},
|
||||
\ get(funcref('s:Qux1', [1, 2, 3, 4]), 'arity'))
|
||||
|
||||
delfunc s:Qux
|
||||
delfunc s:Qux1
|
||||
endfunc
|
||||
|
||||
func Test_compare_partials()
|
||||
|
@ -5503,6 +5503,47 @@ ex_function(exarg_T *eap)
|
||||
ga_clear_strings(&lines_to_free);
|
||||
}
|
||||
|
||||
int
|
||||
get_func_arity(char_u *name, int *required, int *optional, int *varargs)
|
||||
{
|
||||
ufunc_T *ufunc = NULL;
|
||||
int argcount = 0;
|
||||
int min_argcount = 0;
|
||||
int idx;
|
||||
|
||||
idx = find_internal_func(name);
|
||||
if (idx >= 0)
|
||||
{
|
||||
internal_func_get_argcount(idx, &argcount, &min_argcount);
|
||||
*varargs = FALSE;
|
||||
}
|
||||
else
|
||||
{
|
||||
char_u fname_buf[FLEN_FIXED + 1];
|
||||
char_u *tofree = NULL;
|
||||
funcerror_T error = FCERR_NONE;
|
||||
char_u *fname;
|
||||
|
||||
// May need to translate <SNR>123_ to K_SNR.
|
||||
fname = fname_trans_sid(name, fname_buf, &tofree, &error);
|
||||
if (error == FCERR_NONE)
|
||||
ufunc = find_func(fname, FALSE);
|
||||
vim_free(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 = has_varargs(ufunc);
|
||||
}
|
||||
|
||||
*required = min_argcount;
|
||||
*optional = argcount - min_argcount;
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
/*
|
||||
* Find a function by name, including "<lambda>123".
|
||||
* Check for "profile" and "debug" arguments and set"compile_type".
|
||||
|
@ -704,6 +704,8 @@ static char *(features[]) =
|
||||
|
||||
static int included_patches[] =
|
||||
{ /* Add new patch number below this line */
|
||||
/**/
|
||||
547,
|
||||
/**/
|
||||
546,
|
||||
/**/
|
||||
|
Reference in New Issue
Block a user