aboutsummaryrefslogtreecommitdiff
path: root/src/nvim/eval/funcs.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/nvim/eval/funcs.c')
-rw-r--r--src/nvim/eval/funcs.c68
1 files changed, 60 insertions, 8 deletions
diff --git a/src/nvim/eval/funcs.c b/src/nvim/eval/funcs.c
index 4e409cca50..99f9f17e0a 100644
--- a/src/nvim/eval/funcs.c
+++ b/src/nvim/eval/funcs.c
@@ -175,6 +175,53 @@ const VimLFuncDef *find_internal_func(const char *const name)
return find_internal_func_gperf(name, len);
}
+int call_internal_func(const char_u *const fname, const int argcount,
+ typval_T *const argvars, typval_T *const rettv)
+ FUNC_ATTR_NONNULL_ALL
+{
+ const VimLFuncDef *const fdef = find_internal_func((const char *)fname);
+ if (fdef == NULL) {
+ return ERROR_UNKNOWN;
+ } else if (argcount < fdef->min_argc) {
+ return ERROR_TOOFEW;
+ } else if (argcount > fdef->max_argc) {
+ return ERROR_TOOMANY;
+ }
+ argvars[argcount].v_type = VAR_UNKNOWN;
+ fdef->func(argvars, rettv, fdef->data);
+ return ERROR_NONE;
+}
+
+/// Invoke a method for base->method().
+int call_internal_method(const char_u *const fname, const int argcount,
+ typval_T *const argvars, typval_T *const rettv,
+ typval_T *const basetv)
+ FUNC_ATTR_NONNULL_ALL
+{
+ const VimLFuncDef *const fdef = find_internal_func((const char *)fname);
+ if (fdef == NULL) {
+ return ERROR_UNKNOWN;
+ } else if (fdef->base_arg == BASE_NONE) {
+ return ERROR_NOTMETHOD;
+ } else if (argcount + 1 < fdef->min_argc) {
+ return ERROR_TOOFEW;
+ } else if (argcount + 1 > fdef->max_argc) {
+ return ERROR_TOOMANY;
+ }
+
+ typval_T argv[MAX_FUNC_ARGS + 1];
+ const ptrdiff_t base_index
+ = fdef->base_arg == BASE_LAST ? argcount : fdef->base_arg - 1;
+ memcpy(argv, argvars, base_index * sizeof(typval_T));
+ argv[base_index] = *basetv;
+ memcpy(argv + base_index + 1, argvars + base_index,
+ (argcount - base_index) * sizeof(typval_T));
+ argv[argcount + 1].v_type = VAR_UNKNOWN;
+
+ fdef->func(argv, rettv, fdef->data);
+ return ERROR_NONE;
+}
+
/*
* Return TRUE for a non-zero Number and a non-empty String.
*/
@@ -5357,14 +5404,19 @@ static void f_jobwait(typval_T *argvars, typval_T *rettv, FunPtr fptr)
TV_LIST_ITER_CONST(args, arg, {
Channel *chan = NULL;
if (TV_LIST_ITEM_TV(arg)->v_type != VAR_NUMBER
- || !(chan = find_job(TV_LIST_ITEM_TV(arg)->vval.v_number, false))) {
+ || !(chan = find_channel(TV_LIST_ITEM_TV(arg)->vval.v_number))
+ || chan->streamtype != kChannelStreamProc) {
+ jobs[i] = NULL; // Invalid job.
+ } else if (process_is_stopped(&chan->stream.proc)) {
+ // Job is stopped but not fully destroyed.
+ // Ensure all callbacks on its event queue are executed. #15402
+ process_wait(&chan->stream.proc, -1, NULL);
jobs[i] = NULL; // Invalid job.
} else {
jobs[i] = chan;
channel_incref(chan);
if (chan->stream.proc.status < 0) {
- // Process any pending events on the job's queue before temporarily
- // replacing it.
+ // Flush any events in the job's queue before temporarily replacing it.
multiqueue_process_events(chan->events);
multiqueue_replace_parent(chan->events, waiting_jobs);
}
@@ -9420,7 +9472,6 @@ static int item_compare2(const void *s1, const void *s2, bool keep_zero)
int res;
typval_T rettv;
typval_T argv[3];
- int dummy;
const char *func_name;
partial_T *partial = sortinfo->item_compare_partial;
@@ -9444,10 +9495,11 @@ static int item_compare2(const void *s1, const void *s2, bool keep_zero)
tv_copy(TV_LIST_ITEM_TV(si2->item), &argv[1]);
rettv.v_type = VAR_UNKNOWN; // tv_clear() uses this
- res = call_func((const char_u *)func_name,
- -1,
- &rettv, 2, argv, NULL, 0L, 0L, &dummy, true,
- partial, sortinfo->item_compare_selfdict);
+ funcexe_T funcexe = FUNCEXE_INIT;
+ funcexe.evaluate = true;
+ funcexe.partial = partial;
+ funcexe.selfdict = sortinfo->item_compare_selfdict;
+ res = call_func((const char_u *)func_name, -1, &rettv, 2, argv, &funcexe);
tv_clear(&argv[0]);
tv_clear(&argv[1]);