forked from aniani/vim
patch 7.4.1559
Problem: Passing cookie to a callback is clumsy. Solution: Change function() to take arguments and return a partial.
This commit is contained in:
@@ -1,4 +1,4 @@
|
|||||||
*eval.txt* For Vim version 7.4. Last change: 2016 Mar 13
|
*eval.txt* For Vim version 7.4. Last change: 2016 Mar 14
|
||||||
|
|
||||||
|
|
||||||
VIM REFERENCE MANUAL by Bram Moolenaar
|
VIM REFERENCE MANUAL by Bram Moolenaar
|
||||||
@@ -1895,7 +1895,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}
|
||||||
@@ -3568,10 +3569,46 @@ foreground() Move the Vim window to the foreground. Useful when sent from
|
|||||||
Win32 console version}
|
Win32 console version}
|
||||||
|
|
||||||
|
|
||||||
function({name}) *function()* *E700*
|
*function()* *E700* *E922* *E923*
|
||||||
|
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
|
||||||
|
114
src/channel.c
114
src/channel.c
@@ -1025,8 +1025,9 @@ find_buffer(char_u *name, int err)
|
|||||||
void
|
void
|
||||||
channel_set_options(channel_T *channel, jobopt_T *opt)
|
channel_set_options(channel_T *channel, jobopt_T *opt)
|
||||||
{
|
{
|
||||||
int part;
|
int part;
|
||||||
char_u **cbp;
|
char_u **cbp;
|
||||||
|
partial_T **pp;
|
||||||
|
|
||||||
if (opt->jo_set & JO_MODE)
|
if (opt->jo_set & JO_MODE)
|
||||||
for (part = PART_SOCK; part <= PART_IN; ++part)
|
for (part = PART_SOCK; part <= PART_IN; ++part)
|
||||||
@@ -1049,38 +1050,58 @@ channel_set_options(channel_T *channel, jobopt_T *opt)
|
|||||||
if (opt->jo_set & JO_CALLBACK)
|
if (opt->jo_set & JO_CALLBACK)
|
||||||
{
|
{
|
||||||
cbp = &channel->ch_callback;
|
cbp = &channel->ch_callback;
|
||||||
|
pp = &channel->ch_partial;
|
||||||
vim_free(*cbp);
|
vim_free(*cbp);
|
||||||
|
partial_unref(*pp);
|
||||||
if (opt->jo_callback != NULL && *opt->jo_callback != NUL)
|
if (opt->jo_callback != NULL && *opt->jo_callback != NUL)
|
||||||
*cbp = vim_strsave(opt->jo_callback);
|
*cbp = vim_strsave(opt->jo_callback);
|
||||||
else
|
else
|
||||||
*cbp = NULL;
|
*cbp = NULL;
|
||||||
|
*pp = opt->jo_partial;
|
||||||
|
if (*pp != NULL)
|
||||||
|
++(*pp)->pt_refcount;
|
||||||
}
|
}
|
||||||
if (opt->jo_set & JO_OUT_CALLBACK)
|
if (opt->jo_set & JO_OUT_CALLBACK)
|
||||||
{
|
{
|
||||||
cbp = &channel->ch_part[PART_OUT].ch_callback;
|
cbp = &channel->ch_part[PART_OUT].ch_callback;
|
||||||
|
pp = &channel->ch_part[PART_OUT].ch_partial;
|
||||||
vim_free(*cbp);
|
vim_free(*cbp);
|
||||||
|
partial_unref(*pp);
|
||||||
if (opt->jo_out_cb != NULL && *opt->jo_out_cb != NUL)
|
if (opt->jo_out_cb != NULL && *opt->jo_out_cb != NUL)
|
||||||
*cbp = vim_strsave(opt->jo_out_cb);
|
*cbp = vim_strsave(opt->jo_out_cb);
|
||||||
else
|
else
|
||||||
*cbp = NULL;
|
*cbp = NULL;
|
||||||
|
*pp = opt->jo_out_partial;
|
||||||
|
if (*pp != NULL)
|
||||||
|
++(*pp)->pt_refcount;
|
||||||
}
|
}
|
||||||
if (opt->jo_set & JO_ERR_CALLBACK)
|
if (opt->jo_set & JO_ERR_CALLBACK)
|
||||||
{
|
{
|
||||||
cbp = &channel->ch_part[PART_ERR].ch_callback;
|
cbp = &channel->ch_part[PART_ERR].ch_callback;
|
||||||
|
pp = &channel->ch_part[PART_ERR].ch_partial;
|
||||||
vim_free(*cbp);
|
vim_free(*cbp);
|
||||||
|
partial_unref(*pp);
|
||||||
if (opt->jo_err_cb != NULL && *opt->jo_err_cb != NUL)
|
if (opt->jo_err_cb != NULL && *opt->jo_err_cb != NUL)
|
||||||
*cbp = vim_strsave(opt->jo_err_cb);
|
*cbp = vim_strsave(opt->jo_err_cb);
|
||||||
else
|
else
|
||||||
*cbp = NULL;
|
*cbp = NULL;
|
||||||
|
*pp = opt->jo_err_partial;
|
||||||
|
if (*pp != NULL)
|
||||||
|
++(*pp)->pt_refcount;
|
||||||
}
|
}
|
||||||
if (opt->jo_set & JO_CLOSE_CALLBACK)
|
if (opt->jo_set & JO_CLOSE_CALLBACK)
|
||||||
{
|
{
|
||||||
cbp = &channel->ch_close_cb;
|
cbp = &channel->ch_close_cb;
|
||||||
|
pp = &channel->ch_close_partial;
|
||||||
vim_free(*cbp);
|
vim_free(*cbp);
|
||||||
|
partial_unref(*pp);
|
||||||
if (opt->jo_close_cb != NULL && *opt->jo_close_cb != NUL)
|
if (opt->jo_close_cb != NULL && *opt->jo_close_cb != NUL)
|
||||||
*cbp = vim_strsave(opt->jo_close_cb);
|
*cbp = vim_strsave(opt->jo_close_cb);
|
||||||
else
|
else
|
||||||
*cbp = NULL;
|
*cbp = NULL;
|
||||||
|
*pp = opt->jo_err_partial;
|
||||||
|
if (*pp != NULL)
|
||||||
|
++(*pp)->pt_refcount;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((opt->jo_set & JO_OUT_IO) && opt->jo_io[PART_OUT] == JIO_BUFFER)
|
if ((opt->jo_set & JO_OUT_IO) && opt->jo_io[PART_OUT] == JIO_BUFFER)
|
||||||
@@ -1124,10 +1145,11 @@ channel_set_options(channel_T *channel, jobopt_T *opt)
|
|||||||
*/
|
*/
|
||||||
void
|
void
|
||||||
channel_set_req_callback(
|
channel_set_req_callback(
|
||||||
channel_T *channel,
|
channel_T *channel,
|
||||||
int part,
|
int part,
|
||||||
char_u *callback,
|
char_u *callback,
|
||||||
int id)
|
partial_T *partial,
|
||||||
|
int id)
|
||||||
{
|
{
|
||||||
cbq_T *head = &channel->ch_part[part].ch_cb_head;
|
cbq_T *head = &channel->ch_part[part].ch_cb_head;
|
||||||
cbq_T *item = (cbq_T *)alloc((int)sizeof(cbq_T));
|
cbq_T *item = (cbq_T *)alloc((int)sizeof(cbq_T));
|
||||||
@@ -1135,6 +1157,9 @@ channel_set_req_callback(
|
|||||||
if (item != NULL)
|
if (item != NULL)
|
||||||
{
|
{
|
||||||
item->cq_callback = vim_strsave(callback);
|
item->cq_callback = vim_strsave(callback);
|
||||||
|
item->cq_partial = partial;
|
||||||
|
if (partial != NULL)
|
||||||
|
++partial->pt_refcount;
|
||||||
item->cq_seq_nr = id;
|
item->cq_seq_nr = id;
|
||||||
item->cq_prev = head->cq_prev;
|
item->cq_prev = head->cq_prev;
|
||||||
head->cq_prev = item;
|
head->cq_prev = item;
|
||||||
@@ -1247,7 +1272,8 @@ channel_write_new_lines(buf_T *buf)
|
|||||||
* Invoke the "callback" on channel "channel".
|
* Invoke the "callback" on channel "channel".
|
||||||
*/
|
*/
|
||||||
static void
|
static void
|
||||||
invoke_callback(channel_T *channel, char_u *callback, typval_T *argv)
|
invoke_callback(channel_T *channel, char_u *callback, partial_T *partial,
|
||||||
|
typval_T *argv)
|
||||||
{
|
{
|
||||||
typval_T rettv;
|
typval_T rettv;
|
||||||
int dummy;
|
int dummy;
|
||||||
@@ -1256,7 +1282,7 @@ invoke_callback(channel_T *channel, char_u *callback, typval_T *argv)
|
|||||||
argv[0].vval.v_channel = channel;
|
argv[0].vval.v_channel = channel;
|
||||||
|
|
||||||
call_func(callback, (int)STRLEN(callback),
|
call_func(callback, (int)STRLEN(callback),
|
||||||
&rettv, 2, argv, 0L, 0L, &dummy, TRUE, NULL);
|
&rettv, 2, argv, 0L, 0L, &dummy, TRUE, partial, NULL);
|
||||||
clear_tv(&rettv);
|
clear_tv(&rettv);
|
||||||
|
|
||||||
/* If an echo command was used the cursor needs to be put back where
|
/* If an echo command was used the cursor needs to be put back where
|
||||||
@@ -1629,7 +1655,7 @@ channel_exe_cmd(channel_T *channel, int part, typval_T *argv)
|
|||||||
++emsg_skip;
|
++emsg_skip;
|
||||||
if (!is_call)
|
if (!is_call)
|
||||||
tv = eval_expr(arg, NULL);
|
tv = eval_expr(arg, NULL);
|
||||||
else if (func_call(arg, &argv[2], NULL, &res_tv) == OK)
|
else if (func_call(arg, &argv[2], NULL, NULL, &res_tv) == OK)
|
||||||
tv = &res_tv;
|
tv = &res_tv;
|
||||||
else
|
else
|
||||||
tv = NULL;
|
tv = NULL;
|
||||||
@@ -1685,8 +1711,9 @@ invoke_one_time_callback(
|
|||||||
/* Remove the item from the list first, if the callback
|
/* Remove the item from the list first, if the callback
|
||||||
* invokes ch_close() the list will be cleared. */
|
* invokes ch_close() the list will be cleared. */
|
||||||
remove_cb_node(cbhead, item);
|
remove_cb_node(cbhead, item);
|
||||||
invoke_callback(channel, item->cq_callback, argv);
|
invoke_callback(channel, item->cq_callback, item->cq_partial, argv);
|
||||||
vim_free(item->cq_callback);
|
vim_free(item->cq_callback);
|
||||||
|
partial_unref(item->cq_partial);
|
||||||
vim_free(item);
|
vim_free(item);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1775,6 +1802,7 @@ may_invoke_callback(channel_T *channel, int part)
|
|||||||
cbq_T *cbhead = &channel->ch_part[part].ch_cb_head;
|
cbq_T *cbhead = &channel->ch_part[part].ch_cb_head;
|
||||||
cbq_T *cbitem;
|
cbq_T *cbitem;
|
||||||
char_u *callback = NULL;
|
char_u *callback = NULL;
|
||||||
|
partial_T *partial = NULL;
|
||||||
buf_T *buffer = NULL;
|
buf_T *buffer = NULL;
|
||||||
|
|
||||||
if (channel->ch_nb_close_cb != NULL)
|
if (channel->ch_nb_close_cb != NULL)
|
||||||
@@ -1786,11 +1814,20 @@ may_invoke_callback(channel_T *channel, int part)
|
|||||||
if (cbitem->cq_seq_nr == 0)
|
if (cbitem->cq_seq_nr == 0)
|
||||||
break;
|
break;
|
||||||
if (cbitem != NULL)
|
if (cbitem != NULL)
|
||||||
|
{
|
||||||
callback = cbitem->cq_callback;
|
callback = cbitem->cq_callback;
|
||||||
|
partial = cbitem->cq_partial;
|
||||||
|
}
|
||||||
else if (channel->ch_part[part].ch_callback != NULL)
|
else if (channel->ch_part[part].ch_callback != NULL)
|
||||||
|
{
|
||||||
callback = channel->ch_part[part].ch_callback;
|
callback = channel->ch_part[part].ch_callback;
|
||||||
|
partial = channel->ch_part[part].ch_partial;
|
||||||
|
}
|
||||||
else
|
else
|
||||||
|
{
|
||||||
callback = channel->ch_callback;
|
callback = channel->ch_callback;
|
||||||
|
partial = channel->ch_partial;
|
||||||
|
}
|
||||||
|
|
||||||
buffer = channel->ch_part[part].ch_buffer;
|
buffer = channel->ch_part[part].ch_buffer;
|
||||||
if (buffer != NULL && !buf_valid(buffer))
|
if (buffer != NULL && !buf_valid(buffer))
|
||||||
@@ -1936,7 +1973,7 @@ may_invoke_callback(channel_T *channel, int part)
|
|||||||
/* invoke the channel callback */
|
/* invoke the channel callback */
|
||||||
ch_logs(channel, "Invoking channel callback %s",
|
ch_logs(channel, "Invoking channel callback %s",
|
||||||
(char *)callback);
|
(char *)callback);
|
||||||
invoke_callback(channel, callback, argv);
|
invoke_callback(channel, callback, partial, argv);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -2024,13 +2061,16 @@ channel_close(channel_T *channel, int invoke_close_cb)
|
|||||||
argv[0].vval.v_channel = channel;
|
argv[0].vval.v_channel = channel;
|
||||||
++channel->ch_refcount;
|
++channel->ch_refcount;
|
||||||
call_func(channel->ch_close_cb, (int)STRLEN(channel->ch_close_cb),
|
call_func(channel->ch_close_cb, (int)STRLEN(channel->ch_close_cb),
|
||||||
&rettv, 1, argv, 0L, 0L, &dummy, TRUE, NULL);
|
&rettv, 1, argv, 0L, 0L, &dummy, TRUE,
|
||||||
|
channel->ch_close_partial, NULL);
|
||||||
clear_tv(&rettv);
|
clear_tv(&rettv);
|
||||||
--channel->ch_refcount;
|
--channel->ch_refcount;
|
||||||
|
|
||||||
/* the callback is only called once */
|
/* the callback is only called once */
|
||||||
vim_free(channel->ch_close_cb);
|
vim_free(channel->ch_close_cb);
|
||||||
channel->ch_close_cb = NULL;
|
channel->ch_close_cb = NULL;
|
||||||
|
partial_unref(channel->ch_close_partial);
|
||||||
|
channel->ch_close_partial = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
channel->ch_nb_close_cb = NULL;
|
channel->ch_nb_close_cb = NULL;
|
||||||
@@ -2068,6 +2108,7 @@ channel_clear_one(channel_T *channel, int part)
|
|||||||
|
|
||||||
remove_cb_node(cb_head, node);
|
remove_cb_node(cb_head, node);
|
||||||
vim_free(node->cq_callback);
|
vim_free(node->cq_callback);
|
||||||
|
partial_unref(node->cq_partial);
|
||||||
vim_free(node);
|
vim_free(node);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2079,6 +2120,8 @@ channel_clear_one(channel_T *channel, int part)
|
|||||||
|
|
||||||
vim_free(channel->ch_part[part].ch_callback);
|
vim_free(channel->ch_part[part].ch_callback);
|
||||||
channel->ch_part[part].ch_callback = NULL;
|
channel->ch_part[part].ch_callback = NULL;
|
||||||
|
partial_unref(channel->ch_part[part].ch_partial);
|
||||||
|
channel->ch_part[part].ch_partial = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -2093,8 +2136,12 @@ channel_clear(channel_T *channel)
|
|||||||
channel_clear_one(channel, PART_ERR);
|
channel_clear_one(channel, PART_ERR);
|
||||||
vim_free(channel->ch_callback);
|
vim_free(channel->ch_callback);
|
||||||
channel->ch_callback = NULL;
|
channel->ch_callback = NULL;
|
||||||
|
partial_unref(channel->ch_partial);
|
||||||
|
channel->ch_partial = NULL;
|
||||||
vim_free(channel->ch_close_cb);
|
vim_free(channel->ch_close_cb);
|
||||||
channel->ch_close_cb = NULL;
|
channel->ch_close_cb = NULL;
|
||||||
|
partial_unref(channel->ch_close_partial);
|
||||||
|
channel->ch_close_partial = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if defined(EXITFREE) || defined(PROTO)
|
#if defined(EXITFREE) || defined(PROTO)
|
||||||
@@ -2592,7 +2639,8 @@ send_common(
|
|||||||
EMSG2(_("E917: Cannot use a callback with %s()"), fun);
|
EMSG2(_("E917: Cannot use a callback with %s()"), fun);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
channel_set_req_callback(channel, part_send, opt->jo_callback, id);
|
channel_set_req_callback(channel, part_send,
|
||||||
|
opt->jo_callback, opt->jo_partial, id);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (channel_send(channel, part_send, text, fun) == OK
|
if (channel_send(channel, part_send, text, fun) == OK
|
||||||
@@ -2982,13 +3030,19 @@ channel_get_timeout(channel_T *channel, int part)
|
|||||||
* Return NULL for an invalid argument.
|
* Return NULL for an invalid argument.
|
||||||
*/
|
*/
|
||||||
static char_u *
|
static char_u *
|
||||||
get_callback(typval_T *arg)
|
get_callback(typval_T *arg, partial_T **pp)
|
||||||
{
|
{
|
||||||
|
if (arg->v_type == VAR_PARTIAL && arg->vval.v_partial != NULL)
|
||||||
|
{
|
||||||
|
*pp = arg->vval.v_partial;
|
||||||
|
return (*pp)->pt_name;
|
||||||
|
}
|
||||||
|
*pp = NULL;
|
||||||
if (arg->v_type == VAR_FUNC || arg->v_type == VAR_STRING)
|
if (arg->v_type == VAR_FUNC || arg->v_type == VAR_STRING)
|
||||||
return arg->vval.v_string;
|
return arg->vval.v_string;
|
||||||
if (arg->v_type == VAR_NUMBER && arg->vval.v_number == 0)
|
if (arg->v_type == VAR_NUMBER && arg->vval.v_number == 0)
|
||||||
return (char_u *)"";
|
return (char_u *)"";
|
||||||
EMSG(_("E999: Invalid callback argument"));
|
EMSG(_("E921: Invalid callback argument"));
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -3201,7 +3255,7 @@ get_job_options(typval_T *tv, jobopt_T *opt, int supported)
|
|||||||
if (!(supported & JO_CALLBACK))
|
if (!(supported & JO_CALLBACK))
|
||||||
break;
|
break;
|
||||||
opt->jo_set |= JO_CALLBACK;
|
opt->jo_set |= JO_CALLBACK;
|
||||||
opt->jo_callback = get_callback(item);
|
opt->jo_callback = get_callback(item, &opt->jo_partial);
|
||||||
if (opt->jo_callback == NULL)
|
if (opt->jo_callback == NULL)
|
||||||
{
|
{
|
||||||
EMSG2(_(e_invarg2), "callback");
|
EMSG2(_(e_invarg2), "callback");
|
||||||
@@ -3213,7 +3267,7 @@ get_job_options(typval_T *tv, jobopt_T *opt, int supported)
|
|||||||
if (!(supported & JO_OUT_CALLBACK))
|
if (!(supported & JO_OUT_CALLBACK))
|
||||||
break;
|
break;
|
||||||
opt->jo_set |= JO_OUT_CALLBACK;
|
opt->jo_set |= JO_OUT_CALLBACK;
|
||||||
opt->jo_out_cb = get_callback(item);
|
opt->jo_out_cb = get_callback(item, &opt->jo_out_partial);
|
||||||
if (opt->jo_out_cb == NULL)
|
if (opt->jo_out_cb == NULL)
|
||||||
{
|
{
|
||||||
EMSG2(_(e_invarg2), "out-cb");
|
EMSG2(_(e_invarg2), "out-cb");
|
||||||
@@ -3225,7 +3279,7 @@ get_job_options(typval_T *tv, jobopt_T *opt, int supported)
|
|||||||
if (!(supported & JO_ERR_CALLBACK))
|
if (!(supported & JO_ERR_CALLBACK))
|
||||||
break;
|
break;
|
||||||
opt->jo_set |= JO_ERR_CALLBACK;
|
opt->jo_set |= JO_ERR_CALLBACK;
|
||||||
opt->jo_err_cb = get_callback(item);
|
opt->jo_err_cb = get_callback(item, &opt->jo_err_partial);
|
||||||
if (opt->jo_err_cb == NULL)
|
if (opt->jo_err_cb == NULL)
|
||||||
{
|
{
|
||||||
EMSG2(_(e_invarg2), "err-cb");
|
EMSG2(_(e_invarg2), "err-cb");
|
||||||
@@ -3237,7 +3291,7 @@ get_job_options(typval_T *tv, jobopt_T *opt, int supported)
|
|||||||
if (!(supported & JO_CLOSE_CALLBACK))
|
if (!(supported & JO_CLOSE_CALLBACK))
|
||||||
break;
|
break;
|
||||||
opt->jo_set |= JO_CLOSE_CALLBACK;
|
opt->jo_set |= JO_CLOSE_CALLBACK;
|
||||||
opt->jo_close_cb = get_callback(item);
|
opt->jo_close_cb = get_callback(item, &opt->jo_close_partial);
|
||||||
if (opt->jo_close_cb == NULL)
|
if (opt->jo_close_cb == NULL)
|
||||||
{
|
{
|
||||||
EMSG2(_(e_invarg2), "close-cb");
|
EMSG2(_(e_invarg2), "close-cb");
|
||||||
@@ -3311,7 +3365,14 @@ get_job_options(typval_T *tv, jobopt_T *opt, int supported)
|
|||||||
if (!(supported & JO_EXIT_CB))
|
if (!(supported & JO_EXIT_CB))
|
||||||
break;
|
break;
|
||||||
opt->jo_set |= JO_EXIT_CB;
|
opt->jo_set |= JO_EXIT_CB;
|
||||||
opt->jo_exit_cb = get_tv_string_buf_chk(item, opt->jo_ecb_buf);
|
if (item->v_type == VAR_PARTIAL && item->vval.v_partial != NULL)
|
||||||
|
{
|
||||||
|
opt->jo_exit_partial = item->vval.v_partial;
|
||||||
|
opt->jo_exit_cb = item->vval.v_partial->pt_name;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
opt->jo_exit_cb = get_tv_string_buf_chk(
|
||||||
|
item, opt->jo_ecb_buf);
|
||||||
if (opt->jo_exit_cb == NULL)
|
if (opt->jo_exit_cb == NULL)
|
||||||
{
|
{
|
||||||
EMSG2(_(e_invarg2), "exit-cb");
|
EMSG2(_(e_invarg2), "exit-cb");
|
||||||
@@ -3390,6 +3451,7 @@ job_free(job_T *job)
|
|||||||
|
|
||||||
vim_free(job->jv_stoponexit);
|
vim_free(job->jv_stoponexit);
|
||||||
vim_free(job->jv_exit_cb);
|
vim_free(job->jv_exit_cb);
|
||||||
|
partial_unref(job->jv_exit_partial);
|
||||||
vim_free(job);
|
vim_free(job);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -3454,10 +3516,19 @@ job_set_options(job_T *job, jobopt_T *opt)
|
|||||||
if (opt->jo_set & JO_EXIT_CB)
|
if (opt->jo_set & JO_EXIT_CB)
|
||||||
{
|
{
|
||||||
vim_free(job->jv_exit_cb);
|
vim_free(job->jv_exit_cb);
|
||||||
|
partial_unref(job->jv_exit_partial);
|
||||||
if (opt->jo_exit_cb == NULL || *opt->jo_exit_cb == NUL)
|
if (opt->jo_exit_cb == NULL || *opt->jo_exit_cb == NUL)
|
||||||
|
{
|
||||||
job->jv_exit_cb = NULL;
|
job->jv_exit_cb = NULL;
|
||||||
|
job->jv_exit_partial = NULL;
|
||||||
|
}
|
||||||
else
|
else
|
||||||
|
{
|
||||||
job->jv_exit_cb = vim_strsave(opt->jo_exit_cb);
|
job->jv_exit_cb = vim_strsave(opt->jo_exit_cb);
|
||||||
|
job->jv_exit_partial = opt->jo_exit_partial;
|
||||||
|
if (job->jv_exit_partial != NULL)
|
||||||
|
++job->jv_exit_partial->pt_refcount;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -3721,7 +3792,8 @@ job_status(job_T *job)
|
|||||||
argv[1].v_type = VAR_NUMBER;
|
argv[1].v_type = VAR_NUMBER;
|
||||||
argv[1].vval.v_number = job->jv_exitval;
|
argv[1].vval.v_number = job->jv_exitval;
|
||||||
call_func(job->jv_exit_cb, (int)STRLEN(job->jv_exit_cb),
|
call_func(job->jv_exit_cb, (int)STRLEN(job->jv_exit_cb),
|
||||||
&rettv, 2, argv, 0L, 0L, &dummy, TRUE, NULL);
|
&rettv, 2, argv, 0L, 0L, &dummy, TRUE,
|
||||||
|
job->jv_exit_partial, NULL);
|
||||||
clear_tv(&rettv);
|
clear_tv(&rettv);
|
||||||
--job->jv_refcount;
|
--job->jv_refcount;
|
||||||
}
|
}
|
||||||
|
318
src/eval.c
318
src/eval.c
@@ -452,8 +452,8 @@ static char_u *tv2string(typval_T *tv, char_u **tofree, char_u *numbuf, int copy
|
|||||||
static char_u *string_quote(char_u *str, int function);
|
static char_u *string_quote(char_u *str, int function);
|
||||||
static int get_env_tv(char_u **arg, typval_T *rettv, int evaluate);
|
static int get_env_tv(char_u **arg, typval_T *rettv, int evaluate);
|
||||||
static int find_internal_func(char_u *name);
|
static int find_internal_func(char_u *name);
|
||||||
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);
|
||||||
static int get_func_tv(char_u *name, int len, typval_T *rettv, char_u **arg, linenr_T firstline, linenr_T lastline, int *doesrange, int evaluate, dict_T *selfdict);
|
static int get_func_tv(char_u *name, int len, typval_T *rettv, char_u **arg, linenr_T firstline, linenr_T lastline, int *doesrange, int evaluate, partial_T *partial, dict_T *selfdict);
|
||||||
static void emsg_funcname(char *ermsg, char_u *name);
|
static void emsg_funcname(char *ermsg, char_u *name);
|
||||||
static int non_zero_arg(typval_T *argvars);
|
static int non_zero_arg(typval_T *argvars);
|
||||||
|
|
||||||
@@ -1675,7 +1675,7 @@ 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;
|
||||||
@@ -3091,6 +3091,7 @@ tv_op(typval_T *tv1, typval_T *tv2, char_u *op)
|
|||||||
case VAR_UNKNOWN:
|
case VAR_UNKNOWN:
|
||||||
case VAR_DICT:
|
case VAR_DICT:
|
||||||
case VAR_FUNC:
|
case VAR_FUNC:
|
||||||
|
case VAR_PARTIAL:
|
||||||
case VAR_SPECIAL:
|
case VAR_SPECIAL:
|
||||||
case VAR_JOB:
|
case VAR_JOB:
|
||||||
case VAR_CHANNEL:
|
case VAR_CHANNEL:
|
||||||
@@ -3456,6 +3457,7 @@ ex_call(exarg_T *eap)
|
|||||||
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)
|
||||||
{
|
{
|
||||||
@@ -3486,7 +3488,7 @@ 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. */
|
||||||
@@ -3525,7 +3527,7 @@ 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;
|
||||||
@@ -3870,6 +3872,7 @@ item_lock(typval_T *tv, int deep, int lock)
|
|||||||
case VAR_NUMBER:
|
case VAR_NUMBER:
|
||||||
case VAR_STRING:
|
case VAR_STRING:
|
||||||
case VAR_FUNC:
|
case VAR_FUNC:
|
||||||
|
case VAR_PARTIAL:
|
||||||
case VAR_FLOAT:
|
case VAR_FLOAT:
|
||||||
case VAR_SPECIAL:
|
case VAR_SPECIAL:
|
||||||
case VAR_JOB:
|
case VAR_JOB:
|
||||||
@@ -4542,7 +4545,8 @@ eval4(char_u **arg, typval_T *rettv, int evaluate)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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))
|
||||||
@@ -4555,6 +4559,12 @@ eval4(char_u **arg, typval_T *rettv, int evaluate)
|
|||||||
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. */
|
||||||
@@ -4564,9 +4574,9 @@ eval4(char_u **arg, typval_T *rettv, int evaluate)
|
|||||||
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)
|
|
||||||
n1 = !n1;
|
|
||||||
}
|
}
|
||||||
|
if (type == TYPE_NEQUAL)
|
||||||
|
n1 = !n1;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef FEAT_FLOAT
|
#ifdef FEAT_FLOAT
|
||||||
@@ -5230,14 +5240,16 @@ eval7(
|
|||||||
{
|
{
|
||||||
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
|
||||||
@@ -5359,6 +5371,7 @@ eval_index(
|
|||||||
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"));
|
||||||
return FAIL;
|
return FAIL;
|
||||||
@@ -5480,6 +5493,7 @@ eval_index(
|
|||||||
{
|
{
|
||||||
case VAR_UNKNOWN:
|
case VAR_UNKNOWN:
|
||||||
case VAR_FUNC:
|
case VAR_FUNC:
|
||||||
|
case VAR_PARTIAL:
|
||||||
case VAR_FLOAT:
|
case VAR_FLOAT:
|
||||||
case VAR_SPECIAL:
|
case VAR_SPECIAL:
|
||||||
case VAR_JOB:
|
case VAR_JOB:
|
||||||
@@ -6218,6 +6232,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;
|
||||||
|
|
||||||
@@ -7793,6 +7811,12 @@ echo_string(
|
|||||||
r = tv->vval.v_string;
|
r = tv->vval.v_string;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case VAR_PARTIAL:
|
||||||
|
*tofree = NULL;
|
||||||
|
/* TODO: arguments */
|
||||||
|
r = tv->vval.v_partial == NULL ? NULL : tv->vval.v_partial->pt_name;
|
||||||
|
break;
|
||||||
|
|
||||||
case VAR_LIST:
|
case VAR_LIST:
|
||||||
if (tv->vval.v_list == NULL)
|
if (tv->vval.v_list == NULL)
|
||||||
{
|
{
|
||||||
@@ -7878,6 +7902,10 @@ tv2string(
|
|||||||
case VAR_FUNC:
|
case VAR_FUNC:
|
||||||
*tofree = string_quote(tv->vval.v_string, TRUE);
|
*tofree = string_quote(tv->vval.v_string, TRUE);
|
||||||
return *tofree;
|
return *tofree;
|
||||||
|
case VAR_PARTIAL:
|
||||||
|
*tofree = string_quote(tv->vval.v_partial == NULL ? NULL
|
||||||
|
: tv->vval.v_partial->pt_name, TRUE);
|
||||||
|
return *tofree;
|
||||||
case VAR_STRING:
|
case VAR_STRING:
|
||||||
*tofree = string_quote(tv->vval.v_string, FALSE);
|
*tofree = string_quote(tv->vval.v_string, FALSE);
|
||||||
return *tofree;
|
return *tofree;
|
||||||
@@ -8146,7 +8174,7 @@ static struct fst
|
|||||||
{"foldtext", 0, 0, f_foldtext},
|
{"foldtext", 0, 0, f_foldtext},
|
||||||
{"foldtextresult", 1, 1, f_foldtextresult},
|
{"foldtextresult", 1, 1, f_foldtextresult},
|
||||||
{"foreground", 0, 0, f_foreground},
|
{"foreground", 0, 0, f_foreground},
|
||||||
{"function", 1, 1, f_function},
|
{"function", 1, 3, f_function},
|
||||||
{"garbagecollect", 0, 1, f_garbagecollect},
|
{"garbagecollect", 0, 1, f_garbagecollect},
|
||||||
{"get", 2, 3, f_get},
|
{"get", 2, 3, f_get},
|
||||||
{"getbufline", 2, 3, f_getbufline},
|
{"getbufline", 2, 3, f_getbufline},
|
||||||
@@ -8524,13 +8552,16 @@ find_internal_func(
|
|||||||
/*
|
/*
|
||||||
* 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 *
|
static char_u *
|
||||||
deref_func_name(char_u *name, int *lenp, int no_autoload)
|
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);
|
||||||
@@ -8546,6 +8577,18 @@ 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;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -8563,6 +8606,7 @@ 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,
|
||||||
|
partial_T *partial, /* for extra arguments */
|
||||||
dict_T *selfdict) /* Dictionary for "self" */
|
dict_T *selfdict) /* Dictionary for "self" */
|
||||||
{
|
{
|
||||||
char_u *argp;
|
char_u *argp;
|
||||||
@@ -8574,7 +8618,7 @@ 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)
|
||||||
@@ -8595,7 +8639,7 @@ get_func_tv(
|
|||||||
|
|
||||||
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, partial, selfdict);
|
||||||
else if (!aborting())
|
else if (!aborting())
|
||||||
{
|
{
|
||||||
if (argcount == MAX_FUNC_ARGS)
|
if (argcount == MAX_FUNC_ARGS)
|
||||||
@@ -8622,14 +8666,15 @@ 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;
|
||||||
#define ERROR_UNKNOWN 0
|
#define ERROR_UNKNOWN 0
|
||||||
@@ -8639,6 +8684,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 i;
|
int i;
|
||||||
int llen;
|
int llen;
|
||||||
@@ -8647,6 +8693,11 @@ 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. */
|
||||||
@@ -8698,6 +8749,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)
|
||||||
@@ -8841,9 +8913,15 @@ 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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
while (argv_clear > 0)
|
||||||
|
clear_tv(&argv[--argv_clear]);
|
||||||
if (fname != name && fname != fname_buf)
|
if (fname != name && fname != fname_buf)
|
||||||
vim_free(fname);
|
vim_free(fname);
|
||||||
vim_free(name);
|
vim_free(name);
|
||||||
@@ -9737,6 +9815,7 @@ f_byteidxcomp(typval_T *argvars, typval_T *rettv)
|
|||||||
func_call(
|
func_call(
|
||||||
char_u *name,
|
char_u *name,
|
||||||
typval_T *args,
|
typval_T *args,
|
||||||
|
partial_T *partial,
|
||||||
dict_T *selfdict,
|
dict_T *selfdict,
|
||||||
typval_T *rettv)
|
typval_T *rettv)
|
||||||
{
|
{
|
||||||
@@ -9749,7 +9828,7 @@ func_call(
|
|||||||
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;
|
||||||
@@ -9763,7 +9842,7 @@ func_call(
|
|||||||
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)
|
||||||
@@ -9773,12 +9852,13 @@ func_call(
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* "call(func, arglist)" function
|
* "call(func, arglist [, dict])" function
|
||||||
*/
|
*/
|
||||||
static void
|
static void
|
||||||
f_call(typval_T *argvars, typval_T *rettv)
|
f_call(typval_T *argvars, typval_T *rettv)
|
||||||
{
|
{
|
||||||
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)
|
||||||
@@ -9791,6 +9871,11 @@ f_call(typval_T *argvars, typval_T *rettv)
|
|||||||
|
|
||||||
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 if (argvars[0].v_type == VAR_PARTIAL)
|
||||||
|
{
|
||||||
|
partial = argvars[0].vval.v_partial;
|
||||||
|
func = partial->pt_name;
|
||||||
|
}
|
||||||
else
|
else
|
||||||
func = get_tv_string(&argvars[0]);
|
func = get_tv_string(&argvars[0]);
|
||||||
if (*func == NUL)
|
if (*func == NUL)
|
||||||
@@ -9806,7 +9891,7 @@ f_call(typval_T *argvars, typval_T *rettv)
|
|||||||
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);
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef FEAT_FLOAT
|
#ifdef FEAT_FLOAT
|
||||||
@@ -10627,6 +10712,9 @@ f_empty(typval_T *argvars, typval_T *rettv)
|
|||||||
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;
|
||||||
@@ -11688,6 +11776,7 @@ f_foreground(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
|
|||||||
f_function(typval_T *argvars, typval_T *rettv)
|
f_function(typval_T *argvars, typval_T *rettv)
|
||||||
{
|
{
|
||||||
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 || VIM_ISDIGIT(*s))
|
if (s == NULL || *s == NUL || VIM_ISDIGIT(*s))
|
||||||
@@ -11707,20 +11796,120 @@ f_function(typval_T *argvars, typval_T *rettv)
|
|||||||
* 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>%ld_", (long)current_SID);
|
sprintf(sid_buf, "<SNR>%ld_", (long)current_SID);
|
||||||
rettv->vval.v_string =
|
name = alloc((int)(STRLEN(sid_buf) + STRLEN(s + off) + 1));
|
||||||
alloc((int)(STRLEN(sid_buf) + STRLEN(s + off) + 1));
|
if (name != NULL)
|
||||||
if (rettv->vval.v_string != NULL)
|
|
||||||
{
|
{
|
||||||
STRCPY(rettv->vval.v_string, sid_buf);
|
STRCPY(name, sid_buf);
|
||||||
STRCAT(rettv->vval.v_string, s + off);
|
STRCAT(name, s + off);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
rettv->vval.v_string = vim_strsave(s);
|
name = vim_strsave(s);
|
||||||
rettv->v_type = VAR_FUNC;
|
|
||||||
|
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"));
|
||||||
|
vim_free(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"));
|
||||||
|
vim_free(name);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
pt = (partial_T *)alloc_clear(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 *)alloc(
|
||||||
|
sizeof(typval_T) * list->lv_len);
|
||||||
|
if (pt->pt_argv == NULL)
|
||||||
|
{
|
||||||
|
vim_free(pt);
|
||||||
|
vim_free(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)
|
||||||
|
{
|
||||||
|
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]);
|
||||||
|
vim_free(pt->pt_argv);
|
||||||
|
func_unref(pt->pt_name);
|
||||||
|
vim_free(pt->pt_name);
|
||||||
|
vim_free(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
|
* "garbagecollect()" function
|
||||||
*/
|
*/
|
||||||
@@ -14598,6 +14787,7 @@ f_len(typval_T *argvars, typval_T *rettv)
|
|||||||
case VAR_SPECIAL:
|
case VAR_SPECIAL:
|
||||||
case VAR_FLOAT:
|
case VAR_FLOAT:
|
||||||
case VAR_FUNC:
|
case VAR_FUNC:
|
||||||
|
case VAR_PARTIAL:
|
||||||
case VAR_JOB:
|
case VAR_JOB:
|
||||||
case VAR_CHANNEL:
|
case VAR_CHANNEL:
|
||||||
EMSG(_("E701: Invalid type for len()"));
|
EMSG(_("E701: Invalid type for len()"));
|
||||||
@@ -18169,6 +18359,7 @@ typedef struct
|
|||||||
int item_compare_float;
|
int item_compare_float;
|
||||||
#endif
|
#endif
|
||||||
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;
|
||||||
int item_compare_keep_zero;
|
int item_compare_keep_zero;
|
||||||
@@ -18278,6 +18469,8 @@ item_compare2(const void *s1, const void *s2)
|
|||||||
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)
|
||||||
@@ -18286,16 +18479,20 @@ item_compare2(const void *s1, const void *s2)
|
|||||||
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(func_name),
|
||||||
(int)STRLEN(sortinfo->item_compare_func),
|
|
||||||
&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]);
|
||||||
|
|
||||||
@@ -18358,12 +18555,15 @@ do_sort_uniq(typval_T *argvars, typval_T *rettv, int sort)
|
|||||||
info.item_compare_float = FALSE;
|
info.item_compare_float = FALSE;
|
||||||
#endif
|
#endif
|
||||||
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;
|
||||||
@@ -18443,7 +18643,8 @@ do_sort_uniq(typval_T *argvars, typval_T *rettv, int sort)
|
|||||||
info.item_compare_func_err = FALSE;
|
info.item_compare_func_err = FALSE;
|
||||||
info.item_compare_keep_zero = FALSE;
|
info.item_compare_keep_zero = 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((void *)&ptrs[0], (void *)&ptrs[1])
|
&& item_compare2((void *)&ptrs[0], (void *)&ptrs[1])
|
||||||
== ITEM_COMPARE_FAIL)
|
== ITEM_COMPARE_FAIL)
|
||||||
EMSG(_("E702: Sort compare function failed"));
|
EMSG(_("E702: Sort compare function failed"));
|
||||||
@@ -18452,6 +18653,7 @@ do_sort_uniq(typval_T *argvars, typval_T *rettv, int sort)
|
|||||||
/* Sort the array with item pointers. */
|
/* Sort the array with item pointers. */
|
||||||
qsort((void *)ptrs, (size_t)len, sizeof(sortItem_T),
|
qsort((void *)ptrs, (size_t)len, sizeof(sortItem_T),
|
||||||
info.item_compare_func == NULL
|
info.item_compare_func == NULL
|
||||||
|
&& info.item_compare_partial == NULL
|
||||||
? item_compare : item_compare2);
|
? item_compare : item_compare2);
|
||||||
|
|
||||||
if (!info.item_compare_func_err)
|
if (!info.item_compare_func_err)
|
||||||
@@ -18471,7 +18673,8 @@ do_sort_uniq(typval_T *argvars, typval_T *rettv, int 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;
|
||||||
info.item_compare_keep_zero = TRUE;
|
info.item_compare_keep_zero = TRUE;
|
||||||
item_compare_func_ptr = info.item_compare_func
|
item_compare_func_ptr = info.item_compare_func != NULL
|
||||||
|
|| info.item_compare_partial != NULL
|
||||||
? item_compare2 : item_compare;
|
? item_compare2 : item_compare;
|
||||||
|
|
||||||
for (li = l->lv_first; li != NULL && li->li_next != NULL;
|
for (li = l->lv_first; li != NULL && li->li_next != NULL;
|
||||||
@@ -20045,6 +20248,7 @@ f_type(typval_T *argvars, typval_T *rettv)
|
|||||||
break;
|
break;
|
||||||
case VAR_JOB: n = 8; break;
|
case VAR_JOB: n = 8; break;
|
||||||
case VAR_CHANNEL: n = 9; break;
|
case VAR_CHANNEL: n = 9; break;
|
||||||
|
case VAR_PARTIAL: n = 10; break;
|
||||||
case VAR_UNKNOWN:
|
case VAR_UNKNOWN:
|
||||||
EMSG2(_(e_intern2), "f_type(UNKNOWN)");
|
EMSG2(_(e_intern2), "f_type(UNKNOWN)");
|
||||||
n = -1;
|
n = -1;
|
||||||
@@ -21295,11 +21499,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)))
|
||||||
&& !vim_iswhite(*(*arg - 1)))
|
&& !vim_iswhite(*(*arg - 1)))
|
||||||
{
|
{
|
||||||
if (**arg == '(')
|
if (**arg == '(')
|
||||||
@@ -21311,13 +21517,19 @@ handle_subscript(
|
|||||||
rettv->v_type = VAR_UNKNOWN;
|
rettv->v_type = VAR_UNKNOWN;
|
||||||
|
|
||||||
/* Invoke the function. Recursive! */
|
/* Invoke the function. Recursive! */
|
||||||
s = functv.vval.v_string;
|
if (rettv->v_type == VAR_PARTIAL)
|
||||||
|
{
|
||||||
|
pt = functv.vval.v_partial;
|
||||||
|
s = pt->pt_name;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
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). */
|
||||||
@@ -21405,6 +21617,9 @@ free_tv(typval_T *varp)
|
|||||||
case VAR_STRING:
|
case VAR_STRING:
|
||||||
vim_free(varp->vval.v_string);
|
vim_free(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;
|
||||||
@@ -21448,6 +21663,10 @@ clear_tv(typval_T *varp)
|
|||||||
vim_free(varp->vval.v_string);
|
vim_free(varp->vval.v_string);
|
||||||
varp->vval.v_string = NULL;
|
varp->vval.v_string = NULL;
|
||||||
break;
|
break;
|
||||||
|
case VAR_PARTIAL:
|
||||||
|
partial_unref(varp->vval.v_partial);
|
||||||
|
varp->vval.v_partial = NULL;
|
||||||
|
break;
|
||||||
case VAR_LIST:
|
case VAR_LIST:
|
||||||
list_unref(varp->vval.v_list);
|
list_unref(varp->vval.v_list);
|
||||||
varp->vval.v_list = NULL;
|
varp->vval.v_list = NULL;
|
||||||
@@ -21524,6 +21743,7 @@ get_tv_number_chk(typval_T *varp, int *denote)
|
|||||||
break;
|
break;
|
||||||
#endif
|
#endif
|
||||||
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:
|
||||||
@@ -21572,6 +21792,7 @@ get_tv_float(typval_T *varp)
|
|||||||
case VAR_FLOAT:
|
case VAR_FLOAT:
|
||||||
return varp->vval.v_float;
|
return varp->vval.v_float;
|
||||||
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:
|
||||||
@@ -21688,6 +21909,7 @@ get_tv_string_buf_chk(typval_T *varp, char_u *buf)
|
|||||||
sprintf((char *)buf, "%ld", (long)varp->vval.v_number);
|
sprintf((char *)buf, "%ld", (long)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:
|
||||||
@@ -22087,7 +22309,7 @@ list_one_var_a(
|
|||||||
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)
|
||||||
{
|
{
|
||||||
@@ -22106,7 +22328,7 @@ 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)
|
||||||
{
|
{
|
||||||
@@ -22138,7 +22360,8 @@ 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)
|
||||||
@@ -22383,6 +22606,15 @@ copy_tv(typval_T *from, typval_T *to)
|
|||||||
func_ref(to->vval.v_string);
|
func_ref(to->vval.v_string);
|
||||||
}
|
}
|
||||||
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 = NULL;
|
to->vval.v_list = NULL;
|
||||||
@@ -22437,6 +22669,7 @@ item_copy(
|
|||||||
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:
|
||||||
case VAR_JOB:
|
case VAR_JOB:
|
||||||
case VAR_CHANNEL:
|
case VAR_CHANNEL:
|
||||||
@@ -23415,6 +23648,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)
|
||||||
vim_memset(fdp, 0, sizeof(funcdict_T));
|
vim_memset(fdp, 0, sizeof(funcdict_T));
|
||||||
@@ -23499,14 +23733,15 @@ trans_function_name(
|
|||||||
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,
|
||||||
|
flags & TFN_NO_AUTOLOAD);
|
||||||
if (name == lv.ll_exp_name)
|
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;
|
||||||
}
|
}
|
||||||
@@ -25111,6 +25346,7 @@ write_viminfo_varlist(FILE *fp)
|
|||||||
|
|
||||||
case VAR_UNKNOWN:
|
case VAR_UNKNOWN:
|
||||||
case VAR_FUNC:
|
case VAR_FUNC:
|
||||||
|
case VAR_PARTIAL:
|
||||||
case VAR_JOB:
|
case VAR_JOB:
|
||||||
case VAR_CHANNEL:
|
case VAR_CHANNEL:
|
||||||
continue;
|
continue;
|
||||||
|
@@ -2944,7 +2944,7 @@ FunctionCall(FunctionObject *self, PyObject *argsObject, PyObject *kwargs)
|
|||||||
Python_Lock_Vim();
|
Python_Lock_Vim();
|
||||||
|
|
||||||
VimTryStart();
|
VimTryStart();
|
||||||
error = func_call(name, &args, selfdict, &rettv);
|
error = func_call(name, &args, NULL, selfdict, &rettv);
|
||||||
|
|
||||||
Python_Release_Vim();
|
Python_Release_Vim();
|
||||||
Py_END_ALLOW_THREADS
|
Py_END_ALLOW_THREADS
|
||||||
|
@@ -1561,6 +1561,7 @@ do_pyeval (char_u *str, typval_T *rettv)
|
|||||||
case VAR_DICT: ++rettv->vval.v_dict->dv_refcount; break;
|
case VAR_DICT: ++rettv->vval.v_dict->dv_refcount; break;
|
||||||
case VAR_LIST: ++rettv->vval.v_list->lv_refcount; break;
|
case VAR_LIST: ++rettv->vval.v_list->lv_refcount; break;
|
||||||
case VAR_FUNC: func_ref(rettv->vval.v_string); break;
|
case VAR_FUNC: func_ref(rettv->vval.v_string); break;
|
||||||
|
case VAR_PARTIAL: ++rettv->vval.v_partial->pt_refcount; break;
|
||||||
case VAR_UNKNOWN:
|
case VAR_UNKNOWN:
|
||||||
rettv->v_type = VAR_NUMBER;
|
rettv->v_type = VAR_NUMBER;
|
||||||
rettv->vval.v_number = 0;
|
rettv->vval.v_number = 0;
|
||||||
|
@@ -1654,6 +1654,7 @@ do_py3eval (char_u *str, typval_T *rettv)
|
|||||||
case VAR_DICT: ++rettv->vval.v_dict->dv_refcount; break;
|
case VAR_DICT: ++rettv->vval.v_dict->dv_refcount; break;
|
||||||
case VAR_LIST: ++rettv->vval.v_list->lv_refcount; break;
|
case VAR_LIST: ++rettv->vval.v_list->lv_refcount; break;
|
||||||
case VAR_FUNC: func_ref(rettv->vval.v_string); break;
|
case VAR_FUNC: func_ref(rettv->vval.v_string); break;
|
||||||
|
case VAR_PARTIAL: ++rettv->vval.v_partial->pt_refcount; break;
|
||||||
case VAR_UNKNOWN:
|
case VAR_UNKNOWN:
|
||||||
rettv->v_type = VAR_NUMBER;
|
rettv->v_type = VAR_NUMBER;
|
||||||
rettv->vval.v_number = 0;
|
rettv->vval.v_number = 0;
|
||||||
|
@@ -212,6 +212,7 @@ json_encode_item(garray_T *gap, typval_T *val, int copyID, int options)
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case VAR_FUNC:
|
case VAR_FUNC:
|
||||||
|
case VAR_PARTIAL:
|
||||||
case VAR_JOB:
|
case VAR_JOB:
|
||||||
case VAR_CHANNEL:
|
case VAR_CHANNEL:
|
||||||
/* no JSON equivalent TODO: better error */
|
/* no JSON equivalent TODO: better error */
|
||||||
|
@@ -83,10 +83,11 @@ long get_dict_number(dict_T *d, char_u *key);
|
|||||||
int string2float(char_u *text, float_T *value);
|
int string2float(char_u *text, float_T *value);
|
||||||
char_u *get_function_name(expand_T *xp, int idx);
|
char_u *get_function_name(expand_T *xp, int idx);
|
||||||
char_u *get_expr_name(expand_T *xp, int idx);
|
char_u *get_expr_name(expand_T *xp, int idx);
|
||||||
int call_func(char_u *funcname, int len, typval_T *rettv, int argcount, typval_T *argvars, linenr_T firstline, linenr_T lastline, int *doesrange, int evaluate, dict_T *selfdict);
|
int call_func(char_u *funcname, int len, typval_T *rettv, int argcount_in, typval_T *argvars_in, linenr_T firstline, linenr_T lastline, int *doesrange, int evaluate, partial_T *partial, dict_T *selfdict_in);
|
||||||
buf_T *buflist_find_by_name(char_u *name, int curtab_only);
|
buf_T *buflist_find_by_name(char_u *name, int curtab_only);
|
||||||
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);
|
||||||
void dict_extend(dict_T *d1, dict_T *d2, char_u *action);
|
void dict_extend(dict_T *d1, dict_T *d2, char_u *action);
|
||||||
|
void partial_unref(partial_T *pt);
|
||||||
void mzscheme_call_vim(char_u *name, typval_T *args, typval_T *rettv);
|
void mzscheme_call_vim(char_u *name, typval_T *args, typval_T *rettv);
|
||||||
float_T vim_round(float_T f);
|
float_T vim_round(float_T f);
|
||||||
long do_searchpair(char_u *spat, char_u *mpat, char_u *epat, int dir, char_u *skip, int flags, pos_T *match_pos, linenr_T lnum_stop, long time_limit);
|
long do_searchpair(char_u *spat, char_u *mpat, char_u *epat, int dir, char_u *skip, int flags, pos_T *match_pos, linenr_T lnum_stop, long time_limit);
|
||||||
|
@@ -1110,6 +1110,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;
|
||||||
|
|
||||||
typedef struct jobvar_S job_T;
|
typedef struct jobvar_S job_T;
|
||||||
typedef struct readq_S readq_T;
|
typedef struct readq_S readq_T;
|
||||||
@@ -1123,6 +1124,7 @@ typedef enum
|
|||||||
VAR_NUMBER, /* "v_number" is used */
|
VAR_NUMBER, /* "v_number" is used */
|
||||||
VAR_STRING, /* "v_string" is used */
|
VAR_STRING, /* "v_string" is used */
|
||||||
VAR_FUNC, /* "v_string" is function name */
|
VAR_FUNC, /* "v_string" is function name */
|
||||||
|
VAR_PARTIAL, /* "v_partial" is used */
|
||||||
VAR_LIST, /* "v_list" is used */
|
VAR_LIST, /* "v_list" is used */
|
||||||
VAR_DICT, /* "v_dict" is used */
|
VAR_DICT, /* "v_dict" is used */
|
||||||
VAR_FLOAT, /* "v_float" is used */
|
VAR_FLOAT, /* "v_float" is used */
|
||||||
@@ -1147,6 +1149,7 @@ typedef struct
|
|||||||
char_u *v_string; /* string value (can be NULL!) */
|
char_u *v_string; /* string value (can be NULL!) */
|
||||||
list_T *v_list; /* list value (can be NULL!) */
|
list_T *v_list; /* list value (can be NULL!) */
|
||||||
dict_T *v_dict; /* dict value (can be NULL!) */
|
dict_T *v_dict; /* dict value (can be NULL!) */
|
||||||
|
partial_T *v_partial; /* closure: function with args */
|
||||||
#ifdef FEAT_JOB_CHANNEL
|
#ifdef FEAT_JOB_CHANNEL
|
||||||
job_T *v_job; /* job value (can be NULL!) */
|
job_T *v_job; /* job value (can be NULL!) */
|
||||||
channel_T *v_channel; /* channel value (can be NULL!) */
|
channel_T *v_channel; /* channel value (can be NULL!) */
|
||||||
@@ -1239,6 +1242,15 @@ struct dictvar_S
|
|||||||
dict_T *dv_used_prev; /* previous dict in used dicts list */
|
dict_T *dv_used_prev; /* previous dict in used dicts list */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
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" */
|
||||||
|
};
|
||||||
|
|
||||||
typedef enum
|
typedef enum
|
||||||
{
|
{
|
||||||
JOB_FAILED,
|
JOB_FAILED,
|
||||||
@@ -1264,6 +1276,7 @@ struct jobvar_S
|
|||||||
char_u *jv_stoponexit; /* allocated */
|
char_u *jv_stoponexit; /* allocated */
|
||||||
int jv_exitval;
|
int jv_exitval;
|
||||||
char_u *jv_exit_cb; /* allocated */
|
char_u *jv_exit_cb; /* allocated */
|
||||||
|
partial_T *jv_exit_partial;
|
||||||
|
|
||||||
buf_T *jv_in_buf; /* buffer from "in-name" */
|
buf_T *jv_in_buf; /* buffer from "in-name" */
|
||||||
|
|
||||||
@@ -1291,6 +1304,7 @@ struct jsonq_S
|
|||||||
struct cbq_S
|
struct cbq_S
|
||||||
{
|
{
|
||||||
char_u *cq_callback;
|
char_u *cq_callback;
|
||||||
|
partial_T *cq_partial;
|
||||||
int cq_seq_nr;
|
int cq_seq_nr;
|
||||||
cbq_T *cq_next;
|
cbq_T *cq_next;
|
||||||
cbq_T *cq_prev;
|
cbq_T *cq_prev;
|
||||||
@@ -1346,6 +1360,7 @@ typedef struct {
|
|||||||
|
|
||||||
cbq_T ch_cb_head; /* dummy node for per-request callbacks */
|
cbq_T ch_cb_head; /* dummy node for per-request callbacks */
|
||||||
char_u *ch_callback; /* call when a msg is not handled */
|
char_u *ch_callback; /* call when a msg is not handled */
|
||||||
|
partial_T *ch_partial;
|
||||||
|
|
||||||
buf_T *ch_buffer; /* buffer to read from or write to */
|
buf_T *ch_buffer; /* buffer to read from or write to */
|
||||||
linenr_T ch_buf_top; /* next line to send */
|
linenr_T ch_buf_top; /* next line to send */
|
||||||
@@ -1371,7 +1386,9 @@ struct channel_S {
|
|||||||
* closed */
|
* closed */
|
||||||
|
|
||||||
char_u *ch_callback; /* call when any msg is not handled */
|
char_u *ch_callback; /* call when any msg is not handled */
|
||||||
|
partial_T *ch_partial;
|
||||||
char_u *ch_close_cb; /* call when channel is closed */
|
char_u *ch_close_cb; /* call when channel is closed */
|
||||||
|
partial_T *ch_close_partial;
|
||||||
|
|
||||||
job_T *ch_job; /* Job that uses this channel; this does not
|
job_T *ch_job; /* Job that uses this channel; this does not
|
||||||
* count as a reference to avoid a circular
|
* count as a reference to avoid a circular
|
||||||
@@ -1447,9 +1464,15 @@ typedef struct
|
|||||||
linenr_T jo_in_bot;
|
linenr_T jo_in_bot;
|
||||||
|
|
||||||
char_u *jo_callback; /* not allocated! */
|
char_u *jo_callback; /* not allocated! */
|
||||||
|
partial_T *jo_partial; /* not referenced! */
|
||||||
char_u *jo_out_cb; /* not allocated! */
|
char_u *jo_out_cb; /* not allocated! */
|
||||||
|
partial_T *jo_out_partial; /* not referenced! */
|
||||||
char_u *jo_err_cb; /* not allocated! */
|
char_u *jo_err_cb; /* not allocated! */
|
||||||
|
partial_T *jo_err_partial; /* not referenced! */
|
||||||
char_u *jo_close_cb; /* not allocated! */
|
char_u *jo_close_cb; /* not allocated! */
|
||||||
|
partial_T *jo_close_partial; /* not referenced! */
|
||||||
|
char_u *jo_exit_cb; /* not allocated! */
|
||||||
|
partial_T *jo_exit_partial; /* not referenced! */
|
||||||
int jo_waittime;
|
int jo_waittime;
|
||||||
int jo_timeout;
|
int jo_timeout;
|
||||||
int jo_out_timeout;
|
int jo_out_timeout;
|
||||||
@@ -1459,7 +1482,6 @@ typedef struct
|
|||||||
char_u jo_soe_buf[NUMBUFLEN];
|
char_u jo_soe_buf[NUMBUFLEN];
|
||||||
char_u *jo_stoponexit;
|
char_u *jo_stoponexit;
|
||||||
char_u jo_ecb_buf[NUMBUFLEN];
|
char_u jo_ecb_buf[NUMBUFLEN];
|
||||||
char_u *jo_exit_cb;
|
|
||||||
} jobopt_T;
|
} jobopt_T;
|
||||||
|
|
||||||
|
|
||||||
|
@@ -12,6 +12,7 @@ source test_glob2regpat.vim
|
|||||||
source test_join.vim
|
source test_join.vim
|
||||||
source test_lispwords.vim
|
source test_lispwords.vim
|
||||||
source test_menu.vim
|
source test_menu.vim
|
||||||
|
source test_partial.vim
|
||||||
source test_reltime.vim
|
source test_reltime.vim
|
||||||
source test_searchpos.vim
|
source test_searchpos.vim
|
||||||
source test_set.vim
|
source test_set.vim
|
||||||
|
43
src/testdir/test_partial.vim
Normal file
43
src/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
|
@@ -743,6 +743,8 @@ static char *(features[]) =
|
|||||||
|
|
||||||
static int included_patches[] =
|
static int included_patches[] =
|
||||||
{ /* Add new patch number below this line */
|
{ /* Add new patch number below this line */
|
||||||
|
/**/
|
||||||
|
1559,
|
||||||
/**/
|
/**/
|
||||||
1558,
|
1558,
|
||||||
/**/
|
/**/
|
||||||
|
Reference in New Issue
Block a user