mirror of
https://github.com/neovim/neovim.git
synced 2025-09-14 07:18:17 +00:00
vim-patch:7.4.1559
Problem: Passing cookie to a callback is clumsy.
Solution: Change function() to take arguments and return a partial.
1735bc988c
This commit is contained in:

committed by
James McCoy

parent
75c18b6aaa
commit
521e45f2a8
@@ -1913,7 +1913,8 @@ foldlevel({lnum}) Number fold level at {lnum}
|
|||||||
foldtext() String line displayed for closed fold
|
foldtext() String line displayed for closed fold
|
||||||
foldtextresult({lnum}) String text for closed fold at {lnum}
|
foldtextresult({lnum}) String text for closed fold at {lnum}
|
||||||
foreground() Number bring the Vim window to the foreground
|
foreground() Number bring the Vim window to the foreground
|
||||||
function({name}) Funcref reference to function {name}
|
function({name} [, {arglist}] [, {dict}])
|
||||||
|
Funcref reference to function {name}
|
||||||
garbagecollect([{atexit}]) none free memory, breaking cyclic references
|
garbagecollect([{atexit}]) none free memory, breaking cyclic references
|
||||||
get({list}, {idx} [, {def}]) any get item {idx} from {list} or {def}
|
get({list}, {idx} [, {def}]) any get item {idx} from {list} or {def}
|
||||||
get({dict}, {key} [, {def}]) any get item {key} from {dict} or {def}
|
get({dict}, {key} [, {def}]) any get item {key} from {dict} or {def}
|
||||||
@@ -3483,10 +3484,46 @@ foreground() Move the Vim window to the foreground. Useful when sent from
|
|||||||
{only in the Win32 GUI and console version}
|
{only in the Win32 GUI and console version}
|
||||||
|
|
||||||
|
|
||||||
function({name}) *function()* *E700*
|
*function()* *E700* *E922* *E929*
|
||||||
|
function({name} [, {arglist}] [, {dict}])
|
||||||
Return a |Funcref| variable that refers to function {name}.
|
Return a |Funcref| variable that refers to function {name}.
|
||||||
{name} can be a user defined function or an internal function.
|
{name} can be a user defined function or an internal function.
|
||||||
|
|
||||||
|
When {arglist} or {dict} is present this creates a partial.
|
||||||
|
That mans the argument list and/or the dictionary is stored in
|
||||||
|
the Funcref and will be used when the Funcref is called.
|
||||||
|
|
||||||
|
The arguments are passed to the function in front of other
|
||||||
|
arguments. Example: >
|
||||||
|
func Callback(arg1, arg2, name)
|
||||||
|
...
|
||||||
|
let Func = function('Callback', ['one', 'two'])
|
||||||
|
...
|
||||||
|
call Func('name')
|
||||||
|
< Invokes the function as with: >
|
||||||
|
call Callback('one', 'two', 'name')
|
||||||
|
|
||||||
|
< The Dictionary is only useful when calling a "dict" function.
|
||||||
|
In that case the {dict} is passed in as "self". Example: >
|
||||||
|
function Callback() dict
|
||||||
|
echo "called for " . self.name
|
||||||
|
endfunction
|
||||||
|
...
|
||||||
|
let context = {"name": "example"}
|
||||||
|
let Func = function('Callback', context)
|
||||||
|
...
|
||||||
|
call Func() " will echo: called for example
|
||||||
|
|
||||||
|
< The argument list and the Dictionary can be combined: >
|
||||||
|
function Callback(arg1, count) dict
|
||||||
|
...
|
||||||
|
let context = {"name": "example"}
|
||||||
|
let Func = function('Callback', ['one'], context)
|
||||||
|
...
|
||||||
|
call Func(500)
|
||||||
|
< Invokes the function as with: >
|
||||||
|
call context.Callback('one', 500)
|
||||||
|
|
||||||
|
|
||||||
garbagecollect([{atexit}]) *garbagecollect()*
|
garbagecollect([{atexit}]) *garbagecollect()*
|
||||||
Cleanup unused |Lists| and |Dictionaries| that have circular
|
Cleanup unused |Lists| and |Dictionaries| that have circular
|
||||||
|
@@ -360,6 +360,9 @@ void set_option_to(void *to, int type, String name, Object value, Error *err)
|
|||||||
#define TYPVAL_ENCODE_CONV_FUNC(fun) \
|
#define TYPVAL_ENCODE_CONV_FUNC(fun) \
|
||||||
TYPVAL_ENCODE_CONV_NIL()
|
TYPVAL_ENCODE_CONV_NIL()
|
||||||
|
|
||||||
|
#define TYPVAL_ENCODE_CONV_PARTIAL(partial) \
|
||||||
|
TYPVAL_ENCODE_CONV_NIL()
|
||||||
|
|
||||||
#define TYPVAL_ENCODE_CONV_EMPTY_LIST() \
|
#define TYPVAL_ENCODE_CONV_EMPTY_LIST() \
|
||||||
kv_push(edata->stack, ARRAY_OBJ(((Array) { .capacity = 0, .size = 0 })))
|
kv_push(edata->stack, ARRAY_OBJ(((Array) { .capacity = 0, .size = 0 })))
|
||||||
|
|
||||||
@@ -482,6 +485,7 @@ TYPVAL_ENCODE_DEFINE_CONV_FUNCTIONS(static, object, EncodedData *const, edata)
|
|||||||
#undef TYPVAL_ENCODE_CONV_NUMBER
|
#undef TYPVAL_ENCODE_CONV_NUMBER
|
||||||
#undef TYPVAL_ENCODE_CONV_FLOAT
|
#undef TYPVAL_ENCODE_CONV_FLOAT
|
||||||
#undef TYPVAL_ENCODE_CONV_FUNC
|
#undef TYPVAL_ENCODE_CONV_FUNC
|
||||||
|
#undef TYPVAL_ENCODE_CONV_PARTIAL
|
||||||
#undef TYPVAL_ENCODE_CONV_EMPTY_LIST
|
#undef TYPVAL_ENCODE_CONV_EMPTY_LIST
|
||||||
#undef TYPVAL_ENCODE_CONV_LIST_START
|
#undef TYPVAL_ENCODE_CONV_LIST_START
|
||||||
#undef TYPVAL_ENCODE_CONV_EMPTY_DICT
|
#undef TYPVAL_ENCODE_CONV_EMPTY_DICT
|
||||||
|
@@ -225,7 +225,7 @@ Object nvim_call_function(String fname, Array args, Error *err)
|
|||||||
&rettv, (int) args.size, vim_args,
|
&rettv, (int) args.size, vim_args,
|
||||||
curwin->w_cursor.lnum, curwin->w_cursor.lnum, &dummy,
|
curwin->w_cursor.lnum, curwin->w_cursor.lnum, &dummy,
|
||||||
true,
|
true,
|
||||||
NULL);
|
NULL, NULL);
|
||||||
if (r == FAIL) {
|
if (r == FAIL) {
|
||||||
api_set_error(err, Exception, _("Error calling function."));
|
api_set_error(err, Exception, _("Error calling function."));
|
||||||
}
|
}
|
||||||
|
394
src/nvim/eval.c
394
src/nvim/eval.c
@@ -1208,7 +1208,7 @@ int call_vim_function(
|
|||||||
rettv->v_type = VAR_UNKNOWN; /* clear_tv() uses this */
|
rettv->v_type = VAR_UNKNOWN; /* clear_tv() uses this */
|
||||||
ret = call_func(func, (int)STRLEN(func), rettv, argc, argvars,
|
ret = call_func(func, (int)STRLEN(func), rettv, argc, argvars,
|
||||||
curwin->w_cursor.lnum, curwin->w_cursor.lnum,
|
curwin->w_cursor.lnum, curwin->w_cursor.lnum,
|
||||||
&doesrange, true, NULL);
|
&doesrange, true, NULL, NULL);
|
||||||
if (safe) {
|
if (safe) {
|
||||||
--sandbox;
|
--sandbox;
|
||||||
restore_funccal(save_funccalp);
|
restore_funccal(save_funccalp);
|
||||||
@@ -2455,6 +2455,7 @@ static int tv_op(typval_T *tv1, typval_T *tv2, char_u *op)
|
|||||||
switch (tv1->v_type) {
|
switch (tv1->v_type) {
|
||||||
case VAR_DICT:
|
case VAR_DICT:
|
||||||
case VAR_FUNC:
|
case VAR_FUNC:
|
||||||
|
case VAR_PARTIAL:
|
||||||
case VAR_SPECIAL:
|
case VAR_SPECIAL:
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@@ -2756,8 +2757,9 @@ void ex_call(exarg_T *eap)
|
|||||||
typval_T rettv;
|
typval_T rettv;
|
||||||
linenr_T lnum;
|
linenr_T lnum;
|
||||||
int doesrange;
|
int doesrange;
|
||||||
int failed = FALSE;
|
int failed = false;
|
||||||
funcdict_T fudi;
|
funcdict_T fudi;
|
||||||
|
partial_T *partial;
|
||||||
|
|
||||||
if (eap->skip) {
|
if (eap->skip) {
|
||||||
/* trans_function_name() doesn't work well when skipping, use eval0()
|
/* trans_function_name() doesn't work well when skipping, use eval0()
|
||||||
@@ -2786,7 +2788,7 @@ void ex_call(exarg_T *eap)
|
|||||||
|
|
||||||
/* If it is the name of a variable of type VAR_FUNC use its contents. */
|
/* If it is the name of a variable of type VAR_FUNC use its contents. */
|
||||||
len = (int)STRLEN(tofree);
|
len = (int)STRLEN(tofree);
|
||||||
name = deref_func_name(tofree, &len, FALSE);
|
name = deref_func_name(tofree, &len, &partial, false);
|
||||||
|
|
||||||
/* Skip white space to allow ":call func ()". Not good, but required for
|
/* Skip white space to allow ":call func ()". Not good, but required for
|
||||||
* backward compatibility. */
|
* backward compatibility. */
|
||||||
@@ -2818,8 +2820,8 @@ void ex_call(exarg_T *eap)
|
|||||||
arg = startarg;
|
arg = startarg;
|
||||||
if (get_func_tv(name, (int)STRLEN(name), &rettv, &arg,
|
if (get_func_tv(name, (int)STRLEN(name), &rettv, &arg,
|
||||||
eap->line1, eap->line2, &doesrange,
|
eap->line1, eap->line2, &doesrange,
|
||||||
!eap->skip, fudi.fd_dict) == FAIL) {
|
!eap->skip, partial, fudi.fd_dict) == FAIL) {
|
||||||
failed = TRUE;
|
failed = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -3182,6 +3184,7 @@ static void item_lock(typval_T *tv, int deep, int lock)
|
|||||||
case VAR_FLOAT:
|
case VAR_FLOAT:
|
||||||
case VAR_STRING:
|
case VAR_STRING:
|
||||||
case VAR_FUNC:
|
case VAR_FUNC:
|
||||||
|
case VAR_PARTIAL:
|
||||||
case VAR_SPECIAL:
|
case VAR_SPECIAL:
|
||||||
break;
|
break;
|
||||||
case VAR_UNKNOWN:
|
case VAR_UNKNOWN:
|
||||||
@@ -3754,7 +3757,9 @@ static int eval4(char_u **arg, typval_T *rettv, int evaluate)
|
|||||||
if (type == TYPE_NEQUAL)
|
if (type == TYPE_NEQUAL)
|
||||||
n1 = !n1;
|
n1 = !n1;
|
||||||
}
|
}
|
||||||
} else if (rettv->v_type == VAR_FUNC || var2.v_type == VAR_FUNC) {
|
} else if (rettv->v_type == VAR_FUNC || var2.v_type == VAR_FUNC
|
||||||
|
|| rettv->v_type == VAR_PARTIAL
|
||||||
|
|| var2.v_type == VAR_PARTIAL) {
|
||||||
if (rettv->v_type != var2.v_type
|
if (rettv->v_type != var2.v_type
|
||||||
|| (type != TYPE_EQUAL && type != TYPE_NEQUAL)) {
|
|| (type != TYPE_EQUAL && type != TYPE_NEQUAL)) {
|
||||||
if (rettv->v_type != var2.v_type)
|
if (rettv->v_type != var2.v_type)
|
||||||
@@ -3764,15 +3769,20 @@ static int eval4(char_u **arg, typval_T *rettv, int evaluate)
|
|||||||
clear_tv(rettv);
|
clear_tv(rettv);
|
||||||
clear_tv(&var2);
|
clear_tv(&var2);
|
||||||
return FAIL;
|
return FAIL;
|
||||||
|
} else if (rettv->v_type == VAR_PARTIAL) {
|
||||||
|
// Partials are only equal when identical.
|
||||||
|
n1 = rettv->vval.v_partial != NULL
|
||||||
|
&& rettv->vval.v_partial == var2.vval.v_partial;
|
||||||
} else {
|
} else {
|
||||||
/* Compare two Funcrefs for being equal or unequal. */
|
/* Compare two Funcrefs for being equal or unequal. */
|
||||||
if (rettv->vval.v_string == NULL
|
if (rettv->vval.v_string == NULL
|
||||||
|| var2.vval.v_string == NULL)
|
|| var2.vval.v_string == NULL) {
|
||||||
n1 = FALSE;
|
n1 = false;
|
||||||
else
|
} else {
|
||||||
n1 = STRCMP(rettv->vval.v_string,
|
n1 = STRCMP(rettv->vval.v_string, var2.vval.v_string) == 0;
|
||||||
var2.vval.v_string) == 0;
|
}
|
||||||
if (type == TYPE_NEQUAL)
|
}
|
||||||
|
if (type == TYPE_NEQUAL) {
|
||||||
n1 = !n1;
|
n1 = !n1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -4308,14 +4318,15 @@ static int eval7(
|
|||||||
ret = FAIL;
|
ret = FAIL;
|
||||||
} else {
|
} else {
|
||||||
if (**arg == '(') { // recursive!
|
if (**arg == '(') { // recursive!
|
||||||
|
partial_T *partial;
|
||||||
// If "s" is the name of a variable of type VAR_FUNC
|
// If "s" is the name of a variable of type VAR_FUNC
|
||||||
// use its contents.
|
// use its contents.
|
||||||
s = deref_func_name(s, &len, !evaluate);
|
s = deref_func_name(s, &len, &partial, !evaluate);
|
||||||
|
|
||||||
// Invoke the function.
|
// Invoke the function.
|
||||||
ret = get_func_tv(s, len, rettv, arg,
|
ret = get_func_tv(s, len, rettv, arg,
|
||||||
curwin->w_cursor.lnum, curwin->w_cursor.lnum,
|
curwin->w_cursor.lnum, curwin->w_cursor.lnum,
|
||||||
&len, evaluate, NULL);
|
&len, evaluate, partial, NULL);
|
||||||
|
|
||||||
// If evaluate is false rettv->v_type was not set in
|
// If evaluate is false rettv->v_type was not set in
|
||||||
// get_func_tv, but it's needed in handle_subscript() to parse
|
// get_func_tv, but it's needed in handle_subscript() to parse
|
||||||
@@ -4418,7 +4429,8 @@ eval_index (
|
|||||||
char_u *key = NULL;
|
char_u *key = NULL;
|
||||||
|
|
||||||
switch (rettv->v_type) {
|
switch (rettv->v_type) {
|
||||||
case VAR_FUNC: {
|
case VAR_FUNC:
|
||||||
|
case VAR_PARTIAL: {
|
||||||
if (verbose) {
|
if (verbose) {
|
||||||
EMSG(_("E695: Cannot index a Funcref"));
|
EMSG(_("E695: Cannot index a Funcref"));
|
||||||
}
|
}
|
||||||
@@ -4638,6 +4650,7 @@ eval_index (
|
|||||||
break;
|
break;
|
||||||
case VAR_SPECIAL:
|
case VAR_SPECIAL:
|
||||||
case VAR_FUNC:
|
case VAR_FUNC:
|
||||||
|
case VAR_PARTIAL:
|
||||||
case VAR_FLOAT:
|
case VAR_FLOAT:
|
||||||
case VAR_UNKNOWN:
|
case VAR_UNKNOWN:
|
||||||
break; // Not evaluating, skipping over subscript
|
break; // Not evaluating, skipping over subscript
|
||||||
@@ -5177,6 +5190,10 @@ tv_equal (
|
|||||||
&& tv2->vval.v_string != NULL
|
&& tv2->vval.v_string != NULL
|
||||||
&& STRCMP(tv1->vval.v_string, tv2->vval.v_string) == 0;
|
&& STRCMP(tv1->vval.v_string, tv2->vval.v_string) == 0;
|
||||||
|
|
||||||
|
case VAR_PARTIAL:
|
||||||
|
return tv1->vval.v_partial != NULL
|
||||||
|
&& tv1->vval.v_partial == tv2->vval.v_partial;
|
||||||
|
|
||||||
case VAR_NUMBER:
|
case VAR_NUMBER:
|
||||||
return tv1->vval.v_number == tv2->vval.v_number;
|
return tv1->vval.v_number == tv2->vval.v_number;
|
||||||
|
|
||||||
@@ -6059,6 +6076,7 @@ bool set_ref_in_item(typval_T *tv, int copyID, ht_stack_T **ht_stack,
|
|||||||
}
|
}
|
||||||
|
|
||||||
case VAR_FUNC:
|
case VAR_FUNC:
|
||||||
|
case VAR_PARTIAL:
|
||||||
case VAR_UNKNOWN:
|
case VAR_UNKNOWN:
|
||||||
case VAR_SPECIAL:
|
case VAR_SPECIAL:
|
||||||
case VAR_FLOAT:
|
case VAR_FLOAT:
|
||||||
@@ -6797,12 +6815,18 @@ static VimLFuncDef *find_internal_func(const char *const name)
|
|||||||
/*
|
/*
|
||||||
* Check if "name" is a variable of type VAR_FUNC. If so, return the function
|
* Check if "name" is a variable of type VAR_FUNC. If so, return the function
|
||||||
* name it contains, otherwise return "name".
|
* name it contains, otherwise return "name".
|
||||||
|
* If "name" is of type VAR_PARTIAL also return "partial"
|
||||||
*/
|
*/
|
||||||
static char_u *deref_func_name(char_u *name, int *lenp, int no_autoload)
|
static char_u *deref_func_name(
|
||||||
|
char_u *name, int *lenp,
|
||||||
|
partial_T **partial, int no_autoload
|
||||||
|
)
|
||||||
{
|
{
|
||||||
dictitem_T *v;
|
dictitem_T *v;
|
||||||
int cc;
|
int cc;
|
||||||
|
|
||||||
|
*partial = NULL;
|
||||||
|
|
||||||
cc = name[*lenp];
|
cc = name[*lenp];
|
||||||
name[*lenp] = NUL;
|
name[*lenp] = NUL;
|
||||||
v = find_var(name, NULL, no_autoload);
|
v = find_var(name, NULL, no_autoload);
|
||||||
@@ -6816,6 +6840,16 @@ static char_u *deref_func_name(char_u *name, int *lenp, int no_autoload)
|
|||||||
return v->di_tv.vval.v_string;
|
return v->di_tv.vval.v_string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (v != NULL && v->di_tv.v_type == VAR_PARTIAL) {
|
||||||
|
*partial = v->di_tv.vval.v_partial;
|
||||||
|
if (*partial == NULL) {
|
||||||
|
*lenp = 0;
|
||||||
|
return (char_u *)""; // just in case
|
||||||
|
}
|
||||||
|
*lenp = (int)STRLEN((*partial)->pt_name);
|
||||||
|
return (*partial)->pt_name;
|
||||||
|
}
|
||||||
|
|
||||||
return name;
|
return name;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -6833,7 +6867,8 @@ get_func_tv (
|
|||||||
linenr_T lastline, /* last line of range */
|
linenr_T lastline, /* last line of range */
|
||||||
int *doesrange, /* return: function handled range */
|
int *doesrange, /* return: function handled range */
|
||||||
int evaluate,
|
int evaluate,
|
||||||
dict_T *selfdict /* Dictionary for "self" */
|
partial_T *partial, // for extra arguments
|
||||||
|
dict_T *selfdict // Dictionary for "self"
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
char_u *argp;
|
char_u *argp;
|
||||||
@@ -6845,10 +6880,11 @@ get_func_tv (
|
|||||||
* Get the arguments.
|
* Get the arguments.
|
||||||
*/
|
*/
|
||||||
argp = *arg;
|
argp = *arg;
|
||||||
while (argcount < MAX_FUNC_ARGS) {
|
while (argcount < MAX_FUNC_ARGS - (partial == NULL ? 0 : partial->pt_argc)) {
|
||||||
argp = skipwhite(argp + 1); /* skip the '(' or ',' */
|
argp = skipwhite(argp + 1); // skip the '(' or ','
|
||||||
if (*argp == ')' || *argp == ',' || *argp == NUL)
|
if (*argp == ')' || *argp == ',' || *argp == NUL) {
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
if (eval1(&argp, &argvars[argcount], evaluate) == FAIL) {
|
if (eval1(&argp, &argvars[argcount], evaluate) == FAIL) {
|
||||||
ret = FAIL;
|
ret = FAIL;
|
||||||
break;
|
break;
|
||||||
@@ -6862,15 +6898,17 @@ get_func_tv (
|
|||||||
else
|
else
|
||||||
ret = FAIL;
|
ret = FAIL;
|
||||||
|
|
||||||
if (ret == OK)
|
if (ret == OK) {
|
||||||
ret = call_func(name, len, rettv, argcount, argvars,
|
ret = call_func(name, len, rettv, argcount, argvars,
|
||||||
firstline, lastline, doesrange, evaluate, selfdict);
|
firstline, lastline, doesrange, evaluate,
|
||||||
else if (!aborting()) {
|
partial, selfdict);
|
||||||
if (argcount == MAX_FUNC_ARGS)
|
} else if (!aborting()) {
|
||||||
|
if (argcount == MAX_FUNC_ARGS) {
|
||||||
emsg_funcname(N_("E740: Too many arguments for function %s"), name);
|
emsg_funcname(N_("E740: Too many arguments for function %s"), name);
|
||||||
else
|
} else {
|
||||||
emsg_funcname(N_("E116: Invalid arguments for function %s"), name);
|
emsg_funcname(N_("E116: Invalid arguments for function %s"), name);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
while (--argcount >= 0)
|
while (--argcount >= 0)
|
||||||
clear_tv(&argvars[argcount]);
|
clear_tv(&argvars[argcount]);
|
||||||
@@ -6887,17 +6925,18 @@ get_func_tv (
|
|||||||
*/
|
*/
|
||||||
int
|
int
|
||||||
call_func(
|
call_func(
|
||||||
char_u *funcname, /* name of the function */
|
char_u *funcname, // name of the function
|
||||||
int len, /* length of "name" */
|
int len, // length of "name"
|
||||||
typval_T *rettv, /* return value goes here */
|
typval_T *rettv, // return value goes here
|
||||||
int argcount, /* number of "argvars" */
|
int argcount_in, // number of "argvars"
|
||||||
typval_T *argvars, /* vars for arguments, must have "argcount"
|
typval_T *argvars_in, // vars for arguments, must have "argcount"
|
||||||
PLUS ONE elements! */
|
// PLUS ONE elements!
|
||||||
linenr_T firstline, /* first line of range */
|
linenr_T firstline, // first line of range
|
||||||
linenr_T lastline, /* last line of range */
|
linenr_T lastline, // last line of range
|
||||||
int *doesrange, /* return: function handled range */
|
int *doesrange, // return: function handled range
|
||||||
int evaluate,
|
int evaluate,
|
||||||
dict_T *selfdict /* Dictionary for "self" */
|
partial_T *partial, // optional, can be NULL
|
||||||
|
dict_T *selfdict_in // Dictionary for "self"
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
int ret = FAIL;
|
int ret = FAIL;
|
||||||
@@ -6908,6 +6947,7 @@ call_func (
|
|||||||
#define ERROR_DICT 4
|
#define ERROR_DICT 4
|
||||||
#define ERROR_NONE 5
|
#define ERROR_NONE 5
|
||||||
#define ERROR_OTHER 6
|
#define ERROR_OTHER 6
|
||||||
|
#define ERROR_BOTH 7
|
||||||
int error = ERROR_NONE;
|
int error = ERROR_NONE;
|
||||||
int llen;
|
int llen;
|
||||||
ufunc_T *fp;
|
ufunc_T *fp;
|
||||||
@@ -6915,9 +6955,14 @@ call_func (
|
|||||||
char_u fname_buf[FLEN_FIXED + 1];
|
char_u fname_buf[FLEN_FIXED + 1];
|
||||||
char_u *fname;
|
char_u *fname;
|
||||||
char_u *name;
|
char_u *name;
|
||||||
|
int argcount = argcount_in;
|
||||||
|
typval_T *argvars = argvars_in;
|
||||||
|
dict_T *selfdict = selfdict_in;
|
||||||
|
typval_T argv[MAX_FUNC_ARGS + 1]; // used when "partial" is not NULL
|
||||||
|
int argv_clear = 0;
|
||||||
|
|
||||||
/* Make a copy of the name, if it comes from a funcref variable it could
|
// Make a copy of the name, if it comes from a funcref variable it could
|
||||||
* be changed or deleted in the called function. */
|
// be changed or deleted in the called function.
|
||||||
name = vim_strnsave(funcname, len);
|
name = vim_strnsave(funcname, len);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -6953,6 +6998,27 @@ call_func (
|
|||||||
|
|
||||||
*doesrange = FALSE;
|
*doesrange = FALSE;
|
||||||
|
|
||||||
|
if (partial != NULL) {
|
||||||
|
if (partial->pt_dict != NULL) {
|
||||||
|
if (selfdict_in != NULL) {
|
||||||
|
error = ERROR_BOTH;
|
||||||
|
}
|
||||||
|
selfdict = partial->pt_dict;
|
||||||
|
}
|
||||||
|
if (error == ERROR_NONE && partial->pt_argc > 0) {
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for (argv_clear = 0; argv_clear < partial->pt_argc; argv_clear++) {
|
||||||
|
copy_tv(&partial->pt_argv[argv_clear], &argv[argv_clear]);
|
||||||
|
}
|
||||||
|
for (i = 0; i < argcount_in; i++) {
|
||||||
|
argv[i + argv_clear] = argvars_in[i];
|
||||||
|
}
|
||||||
|
argvars = argv;
|
||||||
|
argcount = partial->pt_argc + argcount_in;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/* execute the function if no errors detected and executing */
|
/* execute the function if no errors detected and executing */
|
||||||
if (evaluate && error == ERROR_NONE) {
|
if (evaluate && error == ERROR_NONE) {
|
||||||
@@ -7056,11 +7122,19 @@ call_func (
|
|||||||
emsg_funcname(N_("E725: Calling dict function without Dictionary: %s"),
|
emsg_funcname(N_("E725: Calling dict function without Dictionary: %s"),
|
||||||
name);
|
name);
|
||||||
break;
|
break;
|
||||||
|
case ERROR_BOTH:
|
||||||
|
emsg_funcname(N_("E924: can't have both a \"self\" dict and "
|
||||||
|
"a partial: %s"), name);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (fname != name && fname != fname_buf)
|
while (argv_clear > 0) {
|
||||||
|
clear_tv(&argv[--argv_clear]);
|
||||||
|
}
|
||||||
|
if (fname != name && fname != fname_buf) {
|
||||||
xfree(fname);
|
xfree(fname);
|
||||||
|
}
|
||||||
xfree(name);
|
xfree(name);
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
@@ -7823,7 +7897,8 @@ static void f_byteidxcomp(typval_T *argvars, typval_T *rettv, FunPtr fptr)
|
|||||||
byteidx(argvars, rettv, TRUE);
|
byteidx(argvars, rettv, TRUE);
|
||||||
}
|
}
|
||||||
|
|
||||||
int func_call(char_u *name, typval_T *args, dict_T *selfdict, typval_T *rettv)
|
int func_call(char_u *name, typval_T *args, partial_T *partial,
|
||||||
|
dict_T *selfdict, typval_T *rettv)
|
||||||
{
|
{
|
||||||
listitem_T *item;
|
listitem_T *item;
|
||||||
typval_T argv[MAX_FUNC_ARGS + 1];
|
typval_T argv[MAX_FUNC_ARGS + 1];
|
||||||
@@ -7833,7 +7908,7 @@ int func_call(char_u *name, typval_T *args, dict_T *selfdict, typval_T *rettv)
|
|||||||
|
|
||||||
for (item = args->vval.v_list->lv_first; item != NULL;
|
for (item = args->vval.v_list->lv_first; item != NULL;
|
||||||
item = item->li_next) {
|
item = item->li_next) {
|
||||||
if (argc == MAX_FUNC_ARGS) {
|
if (argc == MAX_FUNC_ARGS - (partial == NULL ? 0 : partial->pt_argc)) {
|
||||||
EMSG(_("E699: Too many arguments"));
|
EMSG(_("E699: Too many arguments"));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -7843,10 +7918,11 @@ int func_call(char_u *name, typval_T *args, dict_T *selfdict, typval_T *rettv)
|
|||||||
copy_tv(&item->li_tv, &argv[argc++]);
|
copy_tv(&item->li_tv, &argv[argc++]);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (item == NULL)
|
if (item == NULL) {
|
||||||
r = call_func(name, (int)STRLEN(name), rettv, argc, argv,
|
r = call_func(name, (int)STRLEN(name), rettv, argc, argv,
|
||||||
curwin->w_cursor.lnum, curwin->w_cursor.lnum,
|
curwin->w_cursor.lnum, curwin->w_cursor.lnum,
|
||||||
&dummy, TRUE, selfdict);
|
&dummy, true, partial, selfdict);
|
||||||
|
}
|
||||||
|
|
||||||
/* Free the arguments. */
|
/* Free the arguments. */
|
||||||
while (argc > 0)
|
while (argc > 0)
|
||||||
@@ -7855,12 +7931,11 @@ int func_call(char_u *name, typval_T *args, dict_T *selfdict, typval_T *rettv)
|
|||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/// "call(func, arglist [, dict])" function
|
||||||
* "call(func, arglist)" function
|
|
||||||
*/
|
|
||||||
static void f_call(typval_T *argvars, typval_T *rettv, FunPtr fptr)
|
static void f_call(typval_T *argvars, typval_T *rettv, FunPtr fptr)
|
||||||
{
|
{
|
||||||
char_u *func;
|
char_u *func;
|
||||||
|
partial_T *partial = NULL;
|
||||||
dict_T *selfdict = NULL;
|
dict_T *selfdict = NULL;
|
||||||
|
|
||||||
if (argvars[1].v_type != VAR_LIST) {
|
if (argvars[1].v_type != VAR_LIST) {
|
||||||
@@ -7870,12 +7945,17 @@ static void f_call(typval_T *argvars, typval_T *rettv, FunPtr fptr)
|
|||||||
if (argvars[1].vval.v_list == NULL)
|
if (argvars[1].vval.v_list == NULL)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (argvars[0].v_type == VAR_FUNC)
|
if (argvars[0].v_type == VAR_FUNC) {
|
||||||
func = argvars[0].vval.v_string;
|
func = argvars[0].vval.v_string;
|
||||||
else
|
} else if (argvars[0].v_type == VAR_PARTIAL) {
|
||||||
|
partial = argvars[0].vval.v_partial;
|
||||||
|
func = partial->pt_name;
|
||||||
|
} else {
|
||||||
func = get_tv_string(&argvars[0]);
|
func = get_tv_string(&argvars[0]);
|
||||||
if (*func == NUL)
|
}
|
||||||
return; /* type error or empty name */
|
if (*func == NUL) {
|
||||||
|
return; // type error or empty name
|
||||||
|
}
|
||||||
|
|
||||||
if (argvars[2].v_type != VAR_UNKNOWN) {
|
if (argvars[2].v_type != VAR_UNKNOWN) {
|
||||||
if (argvars[2].v_type != VAR_DICT) {
|
if (argvars[2].v_type != VAR_DICT) {
|
||||||
@@ -7885,7 +7965,7 @@ static void f_call(typval_T *argvars, typval_T *rettv, FunPtr fptr)
|
|||||||
selfdict = argvars[2].vval.v_dict;
|
selfdict = argvars[2].vval.v_dict;
|
||||||
}
|
}
|
||||||
|
|
||||||
(void)func_call(func, &argvars[1], selfdict, rettv);
|
(void)func_call(func, &argvars[1], partial, selfdict, rettv);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -8467,6 +8547,9 @@ static void f_empty(typval_T *argvars, typval_T *rettv, FunPtr fptr)
|
|||||||
n = argvars[0].vval.v_string == NULL
|
n = argvars[0].vval.v_string == NULL
|
||||||
|| *argvars[0].vval.v_string == NUL;
|
|| *argvars[0].vval.v_string == NUL;
|
||||||
break;
|
break;
|
||||||
|
case VAR_PARTIAL:
|
||||||
|
n = false;
|
||||||
|
break;
|
||||||
case VAR_NUMBER:
|
case VAR_NUMBER:
|
||||||
n = argvars[0].vval.v_number == 0;
|
n = argvars[0].vval.v_number == 0;
|
||||||
break;
|
break;
|
||||||
@@ -9342,6 +9425,7 @@ static void f_foreground(typval_T *argvars, typval_T *rettv, FunPtr fptr)
|
|||||||
static void f_function(typval_T *argvars, typval_T *rettv, FunPtr fptr)
|
static void f_function(typval_T *argvars, typval_T *rettv, FunPtr fptr)
|
||||||
{
|
{
|
||||||
char_u *s;
|
char_u *s;
|
||||||
|
char_u *name;
|
||||||
|
|
||||||
s = get_tv_string(&argvars[0]);
|
s = get_tv_string(&argvars[0]);
|
||||||
if (s == NULL || *s == NUL || ascii_isdigit(*s))
|
if (s == NULL || *s == NUL || ascii_isdigit(*s))
|
||||||
@@ -9354,23 +9438,112 @@ static void f_function(typval_T *argvars, typval_T *rettv, FunPtr fptr)
|
|||||||
char sid_buf[25];
|
char sid_buf[25];
|
||||||
int off = *s == 's' ? 2 : 5;
|
int off = *s == 's' ? 2 : 5;
|
||||||
|
|
||||||
/* Expand s: and <SID> into <SNR>nr_, so that the function can
|
// Expand s: and <SID> into <SNR>nr_, so that the function can
|
||||||
* also be called from another script. Using trans_function_name()
|
// also be called from another script. Using trans_function_name()
|
||||||
* would also work, but some plugins depend on the name being
|
// would also work, but some plugins depend on the name being
|
||||||
* printable text. */
|
// printable text.
|
||||||
sprintf(sid_buf, "<SNR>%" PRId64 "_", (int64_t)current_SID);
|
snprintf(sid_buf, sizeof(sid_buf), "<SNR>%" PRId64 "_",
|
||||||
rettv->vval.v_string = xmalloc(STRLEN(sid_buf) + STRLEN(s + off) + 1);
|
(int64_t)current_SID);
|
||||||
STRCPY(rettv->vval.v_string, sid_buf);
|
name = xmalloc((int)(STRLEN(sid_buf) + STRLEN(s + off) + 1));
|
||||||
STRCAT(rettv->vval.v_string, s + off);
|
if (name != NULL) {
|
||||||
} else
|
STRCPY(name, sid_buf);
|
||||||
rettv->vval.v_string = vim_strsave(s);
|
STRCAT(name, s + off);
|
||||||
rettv->v_type = VAR_FUNC;
|
}
|
||||||
|
} else {
|
||||||
|
name = vim_strsave(s);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (argvars[1].v_type != VAR_UNKNOWN) {
|
||||||
|
partial_T *pt;
|
||||||
|
int dict_idx = 0;
|
||||||
|
int arg_idx = 0;
|
||||||
|
|
||||||
|
if (argvars[2].v_type != VAR_UNKNOWN) {
|
||||||
|
// function(name, [args], dict)
|
||||||
|
arg_idx = 1;
|
||||||
|
dict_idx = 2;
|
||||||
|
} else if (argvars[1].v_type == VAR_DICT) {
|
||||||
|
// function(name, dict)
|
||||||
|
dict_idx = 1;
|
||||||
|
} else {
|
||||||
|
// function(name, [args])
|
||||||
|
arg_idx = 1;
|
||||||
|
}
|
||||||
|
if (dict_idx > 0 && (argvars[dict_idx].v_type != VAR_DICT
|
||||||
|
|| argvars[dict_idx].vval.v_dict == NULL)) {
|
||||||
|
EMSG(_("E922: expected a dict"));
|
||||||
|
xfree(name);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (arg_idx > 0 && (argvars[arg_idx].v_type != VAR_LIST
|
||||||
|
|| argvars[arg_idx].vval.v_list == NULL)) {
|
||||||
|
EMSG(_("E923: Second argument of function() must be a list or a dict"));
|
||||||
|
xfree(name);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
pt = (partial_T *)xcalloc(1, sizeof(partial_T));
|
||||||
|
if (pt != NULL) {
|
||||||
|
if (arg_idx > 0) {
|
||||||
|
list_T *list = argvars[arg_idx].vval.v_list;
|
||||||
|
listitem_T *li;
|
||||||
|
int i = 0;
|
||||||
|
|
||||||
|
pt->pt_argv = (typval_T *)xmalloc(sizeof(typval_T) * list->lv_len);
|
||||||
|
if (pt->pt_argv == NULL) {
|
||||||
|
xfree(pt);
|
||||||
|
xfree(name);
|
||||||
|
return;
|
||||||
|
} else {
|
||||||
|
pt->pt_argc = list->lv_len;
|
||||||
|
for (li = list->lv_first; li != NULL; li = li->li_next) {
|
||||||
|
copy_tv(&li->li_tv, &pt->pt_argv[i++]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
if (dict_idx > 0) {
|
||||||
* "garbagecollect()" function
|
pt->pt_dict = argvars[dict_idx].vval.v_dict;
|
||||||
*/
|
(pt->pt_dict->dv_refcount)++;
|
||||||
|
}
|
||||||
|
|
||||||
|
pt->pt_refcount = 1;
|
||||||
|
pt->pt_name = name;
|
||||||
|
func_ref(pt->pt_name);
|
||||||
|
}
|
||||||
|
rettv->v_type = VAR_PARTIAL;
|
||||||
|
rettv->vval.v_partial = pt;
|
||||||
|
} else {
|
||||||
|
rettv->v_type = VAR_FUNC;
|
||||||
|
rettv->vval.v_string = name;
|
||||||
|
func_ref(name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void partial_free(partial_T *pt)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for (i = 0; i < pt->pt_argc; i++) {
|
||||||
|
clear_tv(&pt->pt_argv[i]);
|
||||||
|
}
|
||||||
|
xfree(pt->pt_argv);
|
||||||
|
func_unref(pt->pt_name);
|
||||||
|
xfree(pt->pt_name);
|
||||||
|
xfree(pt);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Unreference a closure: decrement the reference count and free it when it
|
||||||
|
// becomes zero.
|
||||||
|
void partial_unref(partial_T *pt)
|
||||||
|
{
|
||||||
|
if (pt != NULL && --pt->pt_refcount <= 0) {
|
||||||
|
partial_free(pt);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// "garbagecollect()" function
|
||||||
static void f_garbagecollect(typval_T *argvars, typval_T *rettv, FunPtr fptr)
|
static void f_garbagecollect(typval_T *argvars, typval_T *rettv, FunPtr fptr)
|
||||||
{
|
{
|
||||||
/* This is postponed until we are back at the toplevel, because we may be
|
/* This is postponed until we are back at the toplevel, because we may be
|
||||||
@@ -11971,6 +12144,7 @@ static void f_len(typval_T *argvars, typval_T *rettv, FunPtr fptr)
|
|||||||
case VAR_SPECIAL:
|
case VAR_SPECIAL:
|
||||||
case VAR_FLOAT:
|
case VAR_FLOAT:
|
||||||
case VAR_FUNC:
|
case VAR_FUNC:
|
||||||
|
case VAR_PARTIAL:
|
||||||
EMSG(_("E701: Invalid type for len()"));
|
EMSG(_("E701: Invalid type for len()"));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -15035,6 +15209,7 @@ typedef struct {
|
|||||||
bool item_compare_numbers;
|
bool item_compare_numbers;
|
||||||
bool item_compare_float;
|
bool item_compare_float;
|
||||||
char_u *item_compare_func;
|
char_u *item_compare_func;
|
||||||
|
partial_T *item_compare_partial;
|
||||||
dict_T *item_compare_selfdict;
|
dict_T *item_compare_selfdict;
|
||||||
int item_compare_func_err;
|
int item_compare_func_err;
|
||||||
} sortinfo_T;
|
} sortinfo_T;
|
||||||
@@ -15141,6 +15316,8 @@ static int item_compare2(const void *s1, const void *s2, bool keep_zero)
|
|||||||
typval_T rettv;
|
typval_T rettv;
|
||||||
typval_T argv[3];
|
typval_T argv[3];
|
||||||
int dummy;
|
int dummy;
|
||||||
|
char_u *func_name;
|
||||||
|
partial_T *partial = sortinfo->item_compare_partial;
|
||||||
|
|
||||||
// shortcut after failure in previous call; compare all items equal
|
// shortcut after failure in previous call; compare all items equal
|
||||||
if (sortinfo->item_compare_func_err) {
|
if (sortinfo->item_compare_func_err) {
|
||||||
@@ -15150,16 +15327,22 @@ static int item_compare2(const void *s1, const void *s2, bool keep_zero)
|
|||||||
si1 = (sortItem_T *)s1;
|
si1 = (sortItem_T *)s1;
|
||||||
si2 = (sortItem_T *)s2;
|
si2 = (sortItem_T *)s2;
|
||||||
|
|
||||||
|
if (partial == NULL) {
|
||||||
|
func_name = sortinfo->item_compare_func;
|
||||||
|
} else {
|
||||||
|
func_name = partial->pt_name;
|
||||||
|
}
|
||||||
|
|
||||||
// Copy the values. This is needed to be able to set v_lock to VAR_FIXED
|
// Copy the values. This is needed to be able to set v_lock to VAR_FIXED
|
||||||
// in the copy without changing the original list items.
|
// in the copy without changing the original list items.
|
||||||
copy_tv(&si1->item->li_tv, &argv[0]);
|
copy_tv(&si1->item->li_tv, &argv[0]);
|
||||||
copy_tv(&si2->item->li_tv, &argv[1]);
|
copy_tv(&si2->item->li_tv, &argv[1]);
|
||||||
|
|
||||||
rettv.v_type = VAR_UNKNOWN; // clear_tv() uses this
|
rettv.v_type = VAR_UNKNOWN; // clear_tv() uses this
|
||||||
res = call_func(sortinfo->item_compare_func,
|
res = call_func(func_name,
|
||||||
(int)STRLEN(sortinfo->item_compare_func),
|
(int)STRLEN(func_name),
|
||||||
&rettv, 2, argv, 0L, 0L, &dummy, true,
|
&rettv, 2, argv, 0L, 0L, &dummy, true,
|
||||||
sortinfo->item_compare_selfdict);
|
partial, sortinfo->item_compare_selfdict);
|
||||||
clear_tv(&argv[0]);
|
clear_tv(&argv[0]);
|
||||||
clear_tv(&argv[1]);
|
clear_tv(&argv[1]);
|
||||||
|
|
||||||
@@ -15235,12 +15418,15 @@ static void do_sort_uniq(typval_T *argvars, typval_T *rettv, bool sort)
|
|||||||
info.item_compare_numbers = false;
|
info.item_compare_numbers = false;
|
||||||
info.item_compare_float = false;
|
info.item_compare_float = false;
|
||||||
info.item_compare_func = NULL;
|
info.item_compare_func = NULL;
|
||||||
|
info.item_compare_partial = NULL;
|
||||||
info.item_compare_selfdict = NULL;
|
info.item_compare_selfdict = NULL;
|
||||||
|
|
||||||
if (argvars[1].v_type != VAR_UNKNOWN) {
|
if (argvars[1].v_type != VAR_UNKNOWN) {
|
||||||
/* optional second argument: {func} */
|
/* optional second argument: {func} */
|
||||||
if (argvars[1].v_type == VAR_FUNC) {
|
if (argvars[1].v_type == VAR_FUNC) {
|
||||||
info.item_compare_func = argvars[1].vval.v_string;
|
info.item_compare_func = argvars[1].vval.v_string;
|
||||||
|
} else if (argvars[1].v_type == VAR_PARTIAL) {
|
||||||
|
info.item_compare_partial = argvars[1].vval.v_partial;
|
||||||
} else {
|
} else {
|
||||||
int error = FALSE;
|
int error = FALSE;
|
||||||
|
|
||||||
@@ -15300,14 +15486,16 @@ static void do_sort_uniq(typval_T *argvars, typval_T *rettv, bool sort)
|
|||||||
|
|
||||||
info.item_compare_func_err = false;
|
info.item_compare_func_err = false;
|
||||||
// Test the compare function.
|
// Test the compare function.
|
||||||
if (info.item_compare_func != NULL
|
if ((info.item_compare_func != NULL
|
||||||
|
|| info.item_compare_partial != NULL)
|
||||||
&& item_compare2_not_keeping_zero(&ptrs[0], &ptrs[1])
|
&& item_compare2_not_keeping_zero(&ptrs[0], &ptrs[1])
|
||||||
== ITEM_COMPARE_FAIL) {
|
== ITEM_COMPARE_FAIL) {
|
||||||
EMSG(_("E702: Sort compare function failed"));
|
EMSG(_("E702: Sort compare function failed"));
|
||||||
} else {
|
} else {
|
||||||
// Sort the array with item pointers.
|
// Sort the array with item pointers.
|
||||||
qsort(ptrs, (size_t)len, sizeof (sortItem_T),
|
qsort(ptrs, (size_t)len, sizeof (sortItem_T),
|
||||||
(info.item_compare_func == NULL ?
|
(info.item_compare_func == NULL
|
||||||
|
&& info.item_compare_partial == NULL ?
|
||||||
item_compare_not_keeping_zero :
|
item_compare_not_keeping_zero :
|
||||||
item_compare2_not_keeping_zero));
|
item_compare2_not_keeping_zero));
|
||||||
|
|
||||||
@@ -15328,7 +15516,8 @@ static void do_sort_uniq(typval_T *argvars, typval_T *rettv, bool sort)
|
|||||||
|
|
||||||
// f_uniq(): ptrs will be a stack of items to remove.
|
// f_uniq(): ptrs will be a stack of items to remove.
|
||||||
info.item_compare_func_err = false;
|
info.item_compare_func_err = false;
|
||||||
if (info.item_compare_func != NULL) {
|
if (info.item_compare_func != NULL
|
||||||
|
|| info.item_compare_partial != NULL) {
|
||||||
item_compare_func_ptr = item_compare2_keeping_zero;
|
item_compare_func_ptr = item_compare2_keeping_zero;
|
||||||
} else {
|
} else {
|
||||||
item_compare_func_ptr = item_compare_keeping_zero;
|
item_compare_func_ptr = item_compare_keeping_zero;
|
||||||
@@ -16865,6 +17054,7 @@ static void f_type(typval_T *argvars, typval_T *rettv, FunPtr fptr)
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
case VAR_PARTIAL: n = 8; break;
|
||||||
case VAR_UNKNOWN: {
|
case VAR_UNKNOWN: {
|
||||||
EMSG2(_(e_intern2), "f_type(UNKNOWN)");
|
EMSG2(_(e_intern2), "f_type(UNKNOWN)");
|
||||||
break;
|
break;
|
||||||
@@ -18052,11 +18242,13 @@ handle_subscript (
|
|||||||
char_u *s;
|
char_u *s;
|
||||||
int len;
|
int len;
|
||||||
typval_T functv;
|
typval_T functv;
|
||||||
|
partial_T *pt = NULL;
|
||||||
|
|
||||||
while (ret == OK
|
while (ret == OK
|
||||||
&& (**arg == '['
|
&& (**arg == '['
|
||||||
|| (**arg == '.' && rettv->v_type == VAR_DICT)
|
|| (**arg == '.' && rettv->v_type == VAR_DICT)
|
||||||
|| (**arg == '(' && (!evaluate || rettv->v_type == VAR_FUNC)))
|
|| (**arg == '(' && (!evaluate || rettv->v_type == VAR_FUNC
|
||||||
|
|| rettv->v_type == VAR_PARTIAL)))
|
||||||
&& !ascii_iswhite(*(*arg - 1))) {
|
&& !ascii_iswhite(*(*arg - 1))) {
|
||||||
if (**arg == '(') {
|
if (**arg == '(') {
|
||||||
/* need to copy the funcref so that we can clear rettv */
|
/* need to copy the funcref so that we can clear rettv */
|
||||||
@@ -18064,13 +18256,19 @@ handle_subscript (
|
|||||||
functv = *rettv;
|
functv = *rettv;
|
||||||
rettv->v_type = VAR_UNKNOWN;
|
rettv->v_type = VAR_UNKNOWN;
|
||||||
|
|
||||||
/* Invoke the function. Recursive! */
|
// Invoke the function. Recursive!
|
||||||
|
if (rettv->v_type == VAR_PARTIAL) {
|
||||||
|
pt = functv.vval.v_partial;
|
||||||
|
s = pt->pt_name;
|
||||||
|
} else {
|
||||||
s = functv.vval.v_string;
|
s = functv.vval.v_string;
|
||||||
} else
|
}
|
||||||
|
} else {
|
||||||
s = (char_u *)"";
|
s = (char_u *)"";
|
||||||
|
}
|
||||||
ret = get_func_tv(s, (int)STRLEN(s), rettv, arg,
|
ret = get_func_tv(s, (int)STRLEN(s), rettv, arg,
|
||||||
curwin->w_cursor.lnum, curwin->w_cursor.lnum,
|
curwin->w_cursor.lnum, curwin->w_cursor.lnum,
|
||||||
&len, evaluate, selfdict);
|
&len, evaluate, pt, selfdict);
|
||||||
|
|
||||||
/* Clear the funcref afterwards, so that deleting it while
|
/* Clear the funcref afterwards, so that deleting it while
|
||||||
* evaluating the arguments is possible (see test55). */
|
* evaluating the arguments is possible (see test55). */
|
||||||
@@ -18118,6 +18316,9 @@ void free_tv(typval_T *varp)
|
|||||||
case VAR_STRING:
|
case VAR_STRING:
|
||||||
xfree(varp->vval.v_string);
|
xfree(varp->vval.v_string);
|
||||||
break;
|
break;
|
||||||
|
case VAR_PARTIAL:
|
||||||
|
partial_unref(varp->vval.v_partial);
|
||||||
|
break;
|
||||||
case VAR_LIST:
|
case VAR_LIST:
|
||||||
list_unref(varp->vval.v_list);
|
list_unref(varp->vval.v_list);
|
||||||
break;
|
break;
|
||||||
@@ -18182,6 +18383,12 @@ void free_tv(typval_T *varp)
|
|||||||
tv->v_lock = VAR_UNLOCKED; \
|
tv->v_lock = VAR_UNLOCKED; \
|
||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
|
#define TYPVAL_ENCODE_CONV_PARTIAL(partial) \
|
||||||
|
do { \
|
||||||
|
partial_unref(partial); \
|
||||||
|
tv->v_lock = VAR_UNLOCKED; \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
#define TYPVAL_ENCODE_CONV_EMPTY_LIST() \
|
#define TYPVAL_ENCODE_CONV_EMPTY_LIST() \
|
||||||
do { \
|
do { \
|
||||||
list_unref(tv->vval.v_list); \
|
list_unref(tv->vval.v_list); \
|
||||||
@@ -18258,6 +18465,7 @@ TYPVAL_ENCODE_DEFINE_CONV_FUNCTIONS(static, nothing, void *, ignored)
|
|||||||
#undef TYPVAL_ENCODE_CONV_STR_STRING
|
#undef TYPVAL_ENCODE_CONV_STR_STRING
|
||||||
#undef TYPVAL_ENCODE_CONV_EXT_STRING
|
#undef TYPVAL_ENCODE_CONV_EXT_STRING
|
||||||
#undef TYPVAL_ENCODE_CONV_FUNC
|
#undef TYPVAL_ENCODE_CONV_FUNC
|
||||||
|
#undef TYPVAL_ENCODE_CONV_PARTIAL
|
||||||
#undef TYPVAL_ENCODE_CONV_EMPTY_LIST
|
#undef TYPVAL_ENCODE_CONV_EMPTY_LIST
|
||||||
#undef TYPVAL_ENCODE_CONV_EMPTY_DICT
|
#undef TYPVAL_ENCODE_CONV_EMPTY_DICT
|
||||||
#undef TYPVAL_ENCODE_CONV_LIST_START
|
#undef TYPVAL_ENCODE_CONV_LIST_START
|
||||||
@@ -18315,6 +18523,7 @@ long get_tv_number_chk(typval_T *varp, int *denote)
|
|||||||
EMSG(_("E805: Using a Float as a Number"));
|
EMSG(_("E805: Using a Float as a Number"));
|
||||||
break;
|
break;
|
||||||
case VAR_FUNC:
|
case VAR_FUNC:
|
||||||
|
case VAR_PARTIAL:
|
||||||
EMSG(_("E703: Using a Funcref as a Number"));
|
EMSG(_("E703: Using a Funcref as a Number"));
|
||||||
break;
|
break;
|
||||||
case VAR_STRING:
|
case VAR_STRING:
|
||||||
@@ -18362,6 +18571,7 @@ static float_T get_tv_float(typval_T *varp)
|
|||||||
return varp->vval.v_float;
|
return varp->vval.v_float;
|
||||||
break;
|
break;
|
||||||
case VAR_FUNC:
|
case VAR_FUNC:
|
||||||
|
case VAR_PARTIAL:
|
||||||
EMSG(_("E891: Using a Funcref as a Float"));
|
EMSG(_("E891: Using a Funcref as a Float"));
|
||||||
break;
|
break;
|
||||||
case VAR_STRING:
|
case VAR_STRING:
|
||||||
@@ -18458,6 +18668,7 @@ static char_u *get_tv_string_buf_chk(const typval_T *varp, char_u *buf)
|
|||||||
sprintf((char *)buf, "%" PRId64, (int64_t)varp->vval.v_number);
|
sprintf((char *)buf, "%" PRId64, (int64_t)varp->vval.v_number);
|
||||||
return buf;
|
return buf;
|
||||||
case VAR_FUNC:
|
case VAR_FUNC:
|
||||||
|
case VAR_PARTIAL:
|
||||||
EMSG(_("E729: using Funcref as a String"));
|
EMSG(_("E729: using Funcref as a String"));
|
||||||
break;
|
break;
|
||||||
case VAR_LIST:
|
case VAR_LIST:
|
||||||
@@ -18793,11 +19004,11 @@ list_one_var_a (
|
|||||||
msg_puts(name);
|
msg_puts(name);
|
||||||
msg_putchar(' ');
|
msg_putchar(' ');
|
||||||
msg_advance(22);
|
msg_advance(22);
|
||||||
if (type == VAR_NUMBER)
|
if (type == VAR_NUMBER) {
|
||||||
msg_putchar('#');
|
msg_putchar('#');
|
||||||
else if (type == VAR_FUNC)
|
} else if (type == VAR_FUNC || type == VAR_PARTIAL) {
|
||||||
msg_putchar('*');
|
msg_putchar('*');
|
||||||
else if (type == VAR_LIST) {
|
} else if (type == VAR_LIST) {
|
||||||
msg_putchar('[');
|
msg_putchar('[');
|
||||||
if (*string == '[')
|
if (*string == '[')
|
||||||
++string;
|
++string;
|
||||||
@@ -18810,8 +19021,9 @@ list_one_var_a (
|
|||||||
|
|
||||||
msg_outtrans(string);
|
msg_outtrans(string);
|
||||||
|
|
||||||
if (type == VAR_FUNC)
|
if (type == VAR_FUNC || type == VAR_PARTIAL) {
|
||||||
msg_puts((char_u *)"()");
|
msg_puts((char_u *)"()");
|
||||||
|
}
|
||||||
if (*first) {
|
if (*first) {
|
||||||
msg_clr_eos();
|
msg_clr_eos();
|
||||||
*first = FALSE;
|
*first = FALSE;
|
||||||
@@ -18849,8 +19061,10 @@ set_var (
|
|||||||
}
|
}
|
||||||
v = find_var_in_ht(ht, 0, varname, TRUE);
|
v = find_var_in_ht(ht, 0, varname, TRUE);
|
||||||
|
|
||||||
if (tv->v_type == VAR_FUNC && var_check_func_name(name, v == NULL))
|
if ((tv->v_type == VAR_FUNC || tv->v_type == VAR_PARTIAL)
|
||||||
|
&& var_check_func_name(name, v == NULL)) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (v != NULL) {
|
if (v != NULL) {
|
||||||
// existing variable, need to clear the value
|
// existing variable, need to clear the value
|
||||||
@@ -19050,6 +19264,14 @@ void copy_tv(typval_T *from, typval_T *to)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case VAR_PARTIAL:
|
||||||
|
if (from->vval.v_partial == NULL) {
|
||||||
|
to->vval.v_partial = NULL;
|
||||||
|
} else {
|
||||||
|
to->vval.v_partial = from->vval.v_partial;
|
||||||
|
(to->vval.v_partial->pt_refcount)++;
|
||||||
|
}
|
||||||
|
break;
|
||||||
case VAR_LIST:
|
case VAR_LIST:
|
||||||
if (from->vval.v_list != NULL) {
|
if (from->vval.v_list != NULL) {
|
||||||
to->vval.v_list->lv_refcount++;
|
to->vval.v_list->lv_refcount++;
|
||||||
@@ -19102,6 +19324,7 @@ int var_item_copy(const vimconv_T *const conv,
|
|||||||
case VAR_NUMBER:
|
case VAR_NUMBER:
|
||||||
case VAR_FLOAT:
|
case VAR_FLOAT:
|
||||||
case VAR_FUNC:
|
case VAR_FUNC:
|
||||||
|
case VAR_PARTIAL:
|
||||||
case VAR_SPECIAL:
|
case VAR_SPECIAL:
|
||||||
copy_tv(from, to);
|
copy_tv(from, to);
|
||||||
break;
|
break;
|
||||||
@@ -19956,6 +20179,7 @@ trans_function_name (
|
|||||||
char_u sid_buf[20];
|
char_u sid_buf[20];
|
||||||
int len;
|
int len;
|
||||||
lval_T lv;
|
lval_T lv;
|
||||||
|
partial_T *partial;
|
||||||
|
|
||||||
if (fdp != NULL)
|
if (fdp != NULL)
|
||||||
memset(fdp, 0, sizeof(funcdict_T));
|
memset(fdp, 0, sizeof(funcdict_T));
|
||||||
@@ -20030,15 +20254,18 @@ trans_function_name (
|
|||||||
/* Check if the name is a Funcref. If so, use the value. */
|
/* Check if the name is a Funcref. If so, use the value. */
|
||||||
if (lv.ll_exp_name != NULL) {
|
if (lv.ll_exp_name != NULL) {
|
||||||
len = (int)STRLEN(lv.ll_exp_name);
|
len = (int)STRLEN(lv.ll_exp_name);
|
||||||
name = deref_func_name(lv.ll_exp_name, &len, flags & TFN_NO_AUTOLOAD);
|
name = deref_func_name(lv.ll_exp_name, &len, &partial,
|
||||||
if (name == lv.ll_exp_name)
|
flags & TFN_NO_AUTOLOAD);
|
||||||
|
if (name == lv.ll_exp_name) {
|
||||||
name = NULL;
|
name = NULL;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
len = (int)(end - *pp);
|
len = (int)(end - *pp);
|
||||||
name = deref_func_name(*pp, &len, flags & TFN_NO_AUTOLOAD);
|
name = deref_func_name(*pp, &len, &partial, flags & TFN_NO_AUTOLOAD);
|
||||||
if (name == *pp)
|
if (name == *pp) {
|
||||||
name = NULL;
|
name = NULL;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
if (name != NULL) {
|
if (name != NULL) {
|
||||||
name = vim_strsave(name);
|
name = vim_strsave(name);
|
||||||
*pp = end;
|
*pp = end;
|
||||||
@@ -22301,6 +22528,7 @@ typval_T eval_call_provider(char *provider, char *method, list_T *arguments)
|
|||||||
curwin->w_cursor.lnum,
|
curwin->w_cursor.lnum,
|
||||||
&dummy,
|
&dummy,
|
||||||
true,
|
true,
|
||||||
|
NULL,
|
||||||
NULL);
|
NULL);
|
||||||
|
|
||||||
list_unref(arguments);
|
list_unref(arguments);
|
||||||
|
@@ -103,7 +103,7 @@ return {
|
|||||||
foldtext={},
|
foldtext={},
|
||||||
foldtextresult={args=1},
|
foldtextresult={args=1},
|
||||||
foreground={},
|
foreground={},
|
||||||
['function']={args=1},
|
['function']={args={1, 3}},
|
||||||
garbagecollect={args={0, 1}},
|
garbagecollect={args={0, 1}},
|
||||||
get={args={2, 3}},
|
get={args={2, 3}},
|
||||||
getbufline={args={2, 3}},
|
getbufline={args={2, 3}},
|
||||||
|
@@ -315,6 +315,13 @@ int encode_read_from_list(ListReaderState *const state, char *const buf,
|
|||||||
ga_append(gap, ')'); \
|
ga_append(gap, ')'); \
|
||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
|
#define TYPVAL_ENCODE_CONV_PARTIAL(partial) \
|
||||||
|
do { \
|
||||||
|
ga_concat(gap, "partial("); \
|
||||||
|
TYPVAL_ENCODE_CONV_STRING(partial, STRLEN(partial)); \
|
||||||
|
ga_append(gap, ')'); \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
#define TYPVAL_ENCODE_CONV_EMPTY_LIST() \
|
#define TYPVAL_ENCODE_CONV_EMPTY_LIST() \
|
||||||
ga_concat(gap, "[]")
|
ga_concat(gap, "[]")
|
||||||
|
|
||||||
@@ -661,6 +668,12 @@ static inline int convert_to_json_string(garray_T *const gap,
|
|||||||
"attempt to dump function reference"), \
|
"attempt to dump function reference"), \
|
||||||
mpstack, objname)
|
mpstack, objname)
|
||||||
|
|
||||||
|
#undef TYPVAL_ENCODE_CONV_PARTIAL
|
||||||
|
#define TYPVAL_ENCODE_CONV_PARTIAL(partial) \
|
||||||
|
return conv_error(_("E474: Error while dumping %s, %s: " \
|
||||||
|
"attempt to dump partial"), \
|
||||||
|
mpstack, objname)
|
||||||
|
|
||||||
/// Check whether given key can be used in json_encode()
|
/// Check whether given key can be used in json_encode()
|
||||||
///
|
///
|
||||||
/// @param[in] tv Key to check.
|
/// @param[in] tv Key to check.
|
||||||
@@ -718,6 +731,7 @@ TYPVAL_ENCODE_DEFINE_CONV_FUNCTIONS(static, json, garray_T *const, gap)
|
|||||||
#undef TYPVAL_ENCODE_CONV_NUMBER
|
#undef TYPVAL_ENCODE_CONV_NUMBER
|
||||||
#undef TYPVAL_ENCODE_CONV_FLOAT
|
#undef TYPVAL_ENCODE_CONV_FLOAT
|
||||||
#undef TYPVAL_ENCODE_CONV_FUNC
|
#undef TYPVAL_ENCODE_CONV_FUNC
|
||||||
|
#undef TYPVAL_ENCODE_CONV_PARTIAL
|
||||||
#undef TYPVAL_ENCODE_CONV_EMPTY_LIST
|
#undef TYPVAL_ENCODE_CONV_EMPTY_LIST
|
||||||
#undef TYPVAL_ENCODE_CONV_LIST_START
|
#undef TYPVAL_ENCODE_CONV_LIST_START
|
||||||
#undef TYPVAL_ENCODE_CONV_EMPTY_DICT
|
#undef TYPVAL_ENCODE_CONV_EMPTY_DICT
|
||||||
@@ -846,6 +860,11 @@ char *encode_tv2json(typval_T *tv, size_t *len)
|
|||||||
"attempt to dump function reference"), \
|
"attempt to dump function reference"), \
|
||||||
mpstack, objname)
|
mpstack, objname)
|
||||||
|
|
||||||
|
#define TYPVAL_ENCODE_CONV_PARTIAL(partial) \
|
||||||
|
return conv_error(_("E951: Error while dumping %s, %s: " \
|
||||||
|
"attempt to dump partial"), \
|
||||||
|
mpstack, objname)
|
||||||
|
|
||||||
#define TYPVAL_ENCODE_CONV_EMPTY_LIST() \
|
#define TYPVAL_ENCODE_CONV_EMPTY_LIST() \
|
||||||
msgpack_pack_array(packer, 0)
|
msgpack_pack_array(packer, 0)
|
||||||
|
|
||||||
@@ -902,6 +921,7 @@ TYPVAL_ENCODE_DEFINE_CONV_FUNCTIONS(, msgpack, msgpack_packer *const, packer)
|
|||||||
#undef TYPVAL_ENCODE_CONV_NUMBER
|
#undef TYPVAL_ENCODE_CONV_NUMBER
|
||||||
#undef TYPVAL_ENCODE_CONV_FLOAT
|
#undef TYPVAL_ENCODE_CONV_FLOAT
|
||||||
#undef TYPVAL_ENCODE_CONV_FUNC
|
#undef TYPVAL_ENCODE_CONV_FUNC
|
||||||
|
#undef TYPVAL_ENCODE_CONV_PARTIAL
|
||||||
#undef TYPVAL_ENCODE_CONV_EMPTY_LIST
|
#undef TYPVAL_ENCODE_CONV_EMPTY_LIST
|
||||||
#undef TYPVAL_ENCODE_CONV_LIST_START
|
#undef TYPVAL_ENCODE_CONV_LIST_START
|
||||||
#undef TYPVAL_ENCODE_CONV_EMPTY_DICT
|
#undef TYPVAL_ENCODE_CONV_EMPTY_DICT
|
||||||
|
@@ -69,6 +69,11 @@
|
|||||||
///
|
///
|
||||||
/// @param fun Function name.
|
/// @param fun Function name.
|
||||||
|
|
||||||
|
/// @def TYPVAL_ENCODE_CONV_PARTIAL
|
||||||
|
/// @brief Macros used to convert a partial
|
||||||
|
///
|
||||||
|
/// @param partial Partial name.
|
||||||
|
|
||||||
/// @def TYPVAL_ENCODE_CONV_EMPTY_LIST
|
/// @def TYPVAL_ENCODE_CONV_EMPTY_LIST
|
||||||
/// @brief Macros used to convert an empty list
|
/// @brief Macros used to convert an empty list
|
||||||
///
|
///
|
||||||
@@ -248,6 +253,10 @@ static int name##_convert_one_value(firstargtype firstargname, \
|
|||||||
TYPVAL_ENCODE_CONV_FUNC(tv->vval.v_string); \
|
TYPVAL_ENCODE_CONV_FUNC(tv->vval.v_string); \
|
||||||
break; \
|
break; \
|
||||||
} \
|
} \
|
||||||
|
case VAR_PARTIAL: { \
|
||||||
|
TYPVAL_ENCODE_CONV_PARTIAL(tv->vval.v_partial); \
|
||||||
|
break; \
|
||||||
|
} \
|
||||||
case VAR_LIST: { \
|
case VAR_LIST: { \
|
||||||
if (tv->vval.v_list == NULL || tv->vval.v_list->lv_len == 0) { \
|
if (tv->vval.v_list == NULL || tv->vval.v_list->lv_len == 0) { \
|
||||||
TYPVAL_ENCODE_CONV_EMPTY_LIST(); \
|
TYPVAL_ENCODE_CONV_EMPTY_LIST(); \
|
||||||
|
@@ -15,6 +15,7 @@ typedef double float_T;
|
|||||||
|
|
||||||
typedef struct listvar_S list_T;
|
typedef struct listvar_S list_T;
|
||||||
typedef struct dictvar_S dict_T;
|
typedef struct dictvar_S dict_T;
|
||||||
|
typedef struct partial_S partial_T;
|
||||||
|
|
||||||
/// Special variable values
|
/// Special variable values
|
||||||
typedef enum {
|
typedef enum {
|
||||||
@@ -35,7 +36,8 @@ typedef enum {
|
|||||||
VAR_UNKNOWN = 0, ///< Unknown (unspecified) value.
|
VAR_UNKNOWN = 0, ///< Unknown (unspecified) value.
|
||||||
VAR_NUMBER, ///< Number, .v_number is used.
|
VAR_NUMBER, ///< Number, .v_number is used.
|
||||||
VAR_STRING, ///< String, .v_string is used.
|
VAR_STRING, ///< String, .v_string is used.
|
||||||
VAR_FUNC, ///< Function referene, .v_string is used for function name.
|
VAR_FUNC, ///< Function reference, .v_string is used as function name.
|
||||||
|
VAR_PARTIAL, ///< Partial, .v_partial is used.
|
||||||
VAR_LIST, ///< List, .v_list is used.
|
VAR_LIST, ///< List, .v_list is used.
|
||||||
VAR_DICT, ///< Dictionary, .v_dict is used.
|
VAR_DICT, ///< Dictionary, .v_dict is used.
|
||||||
VAR_FLOAT, ///< Floating-point value, .v_float is used.
|
VAR_FLOAT, ///< Floating-point value, .v_float is used.
|
||||||
@@ -54,6 +56,7 @@ typedef struct {
|
|||||||
char_u *v_string; ///< String, for VAR_STRING and VAR_FUNC, can be NULL.
|
char_u *v_string; ///< String, for VAR_STRING and VAR_FUNC, can be NULL.
|
||||||
list_T *v_list; ///< List for VAR_LIST, can be NULL.
|
list_T *v_list; ///< List for VAR_LIST, can be NULL.
|
||||||
dict_T *v_dict; ///< Dictionary for VAR_DICT, can be NULL.
|
dict_T *v_dict; ///< Dictionary for VAR_DICT, can be NULL.
|
||||||
|
partial_T *v_partial; ///< Closure: function with args.
|
||||||
} vval; ///< Actual value.
|
} vval; ///< Actual value.
|
||||||
} typval_T;
|
} typval_T;
|
||||||
|
|
||||||
@@ -144,6 +147,14 @@ struct dictvar_S {
|
|||||||
QUEUE watchers; ///< Dictionary key watchers set by user code.
|
QUEUE watchers; ///< Dictionary key watchers set by user code.
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct partial_S {
|
||||||
|
int pt_refcount; ///< Reference count.
|
||||||
|
char_u *pt_name; ///< Function name.
|
||||||
|
int pt_argc; ///< Number of arguments.
|
||||||
|
typval_T *pt_argv; ///< Arguments in allocated array.
|
||||||
|
dict_T *pt_dict; ///< Dict for "self".
|
||||||
|
};
|
||||||
|
|
||||||
// structure used for explicit stack while garbage collecting hash tables
|
// structure used for explicit stack while garbage collecting hash tables
|
||||||
typedef struct ht_stack_S {
|
typedef struct ht_stack_S {
|
||||||
hashtab_T *ht;
|
hashtab_T *ht;
|
||||||
|
@@ -2466,7 +2466,7 @@ do_mouse (
|
|||||||
(int) strlen(tab_page_click_defs[mouse_col].func),
|
(int) strlen(tab_page_click_defs[mouse_col].func),
|
||||||
&rettv, ARRAY_SIZE(argv), argv,
|
&rettv, ARRAY_SIZE(argv), argv,
|
||||||
curwin->w_cursor.lnum, curwin->w_cursor.lnum,
|
curwin->w_cursor.lnum, curwin->w_cursor.lnum,
|
||||||
&doesrange, true, NULL);
|
&doesrange, true, NULL, NULL);
|
||||||
clear_tv(&rettv);
|
clear_tv(&rettv);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@@ -14,6 +14,7 @@ source test_matchadd_conceal_utf8.vim
|
|||||||
source test_menu.vim
|
source test_menu.vim
|
||||||
source test_messages.vim
|
source test_messages.vim
|
||||||
source test_options.vim
|
source test_options.vim
|
||||||
|
source test_partial.vim
|
||||||
source test_popup.vim
|
source test_popup.vim
|
||||||
source test_regexp_utf8.vim
|
source test_regexp_utf8.vim
|
||||||
source test_statusline.vim
|
source test_statusline.vim
|
||||||
|
43
src/nvim/testdir/test_partial.vim
Normal file
43
src/nvim/testdir/test_partial.vim
Normal file
@@ -0,0 +1,43 @@
|
|||||||
|
" Test binding arguments to a Funcref.
|
||||||
|
|
||||||
|
func MyFunc(arg1, arg2, arg3)
|
||||||
|
return a:arg1 . '/' . a:arg2 . '/' . a:arg3
|
||||||
|
endfunc
|
||||||
|
|
||||||
|
func MySort(up, one, two)
|
||||||
|
if a:one == a:two
|
||||||
|
return 0
|
||||||
|
endif
|
||||||
|
if a:up
|
||||||
|
return a:one > a:two
|
||||||
|
endif
|
||||||
|
return a:one < a:two
|
||||||
|
endfunc
|
||||||
|
|
||||||
|
func Test_partial_args()
|
||||||
|
let Cb = function('MyFunc', ["foo", "bar"])
|
||||||
|
call assert_equal("foo/bar/xxx", Cb("xxx"))
|
||||||
|
call assert_equal("foo/bar/yyy", call(Cb, ["yyy"]))
|
||||||
|
|
||||||
|
let Sort = function('MySort', [1])
|
||||||
|
call assert_equal([1, 2, 3], sort([3, 1, 2], Sort))
|
||||||
|
let Sort = function('MySort', [0])
|
||||||
|
call assert_equal([3, 2, 1], sort([3, 1, 2], Sort))
|
||||||
|
endfunc
|
||||||
|
|
||||||
|
func MyDictFunc(arg1, arg2) dict
|
||||||
|
return self.name . '/' . a:arg1 . '/' . a:arg2
|
||||||
|
endfunc
|
||||||
|
|
||||||
|
func Test_partial_dict()
|
||||||
|
let dict = {'name': 'hello'}
|
||||||
|
let Cb = function('MyDictFunc', ["foo", "bar"], dict)
|
||||||
|
call assert_equal("hello/foo/bar", Cb())
|
||||||
|
call assert_fails('Cb("xxx")', 'E492:')
|
||||||
|
let Cb = function('MyDictFunc', ["foo"], dict)
|
||||||
|
call assert_equal("hello/foo/xxx", Cb("xxx"))
|
||||||
|
call assert_fails('Cb()', 'E492:')
|
||||||
|
let Cb = function('MyDictFunc', dict)
|
||||||
|
call assert_equal("hello/xxx/yyy", Cb("xxx", "yyy"))
|
||||||
|
call assert_fails('Cb()', 'E492:')
|
||||||
|
endfunc
|
@@ -883,7 +883,7 @@ static int included_patches[] = {
|
|||||||
// 1562 NA
|
// 1562 NA
|
||||||
// 1561 NA
|
// 1561 NA
|
||||||
// 1560 NA
|
// 1560 NA
|
||||||
// 1559,
|
1559,
|
||||||
1558,
|
1558,
|
||||||
1557,
|
1557,
|
||||||
// 1556 NA
|
// 1556 NA
|
||||||
|
Reference in New Issue
Block a user