aboutsummaryrefslogtreecommitdiff
path: root/src/nvim/eval.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/nvim/eval.c')
-rw-r--r--src/nvim/eval.c71
1 files changed, 53 insertions, 18 deletions
diff --git a/src/nvim/eval.c b/src/nvim/eval.c
index bfb332a149..d0af4b8249 100644
--- a/src/nvim/eval.c
+++ b/src/nvim/eval.c
@@ -18,6 +18,8 @@
#include <stdbool.h>
#include <math.h>
+#include "nvim/lib/klist.h"
+
#include "nvim/assert.h"
#include "nvim/vim.h"
#include "nvim/ascii.h"
@@ -81,11 +83,12 @@
#include "nvim/os/rstream.h"
#include "nvim/os/rstream_defs.h"
#include "nvim/os/time.h"
-#include "nvim/os/channel.h"
+#include "nvim/msgpack_rpc/channel.h"
#include "nvim/api/private/helpers.h"
#include "nvim/api/vim.h"
#include "nvim/os/dl.h"
#include "nvim/os/provider.h"
+#include "nvim/os/event.h"
#define DICT_MAXNEST 100 /* maximum nesting of lists and dicts */
@@ -421,7 +424,8 @@ static struct vimvar {
{VV_NAME("oldfiles", VAR_LIST), 0},
{VV_NAME("windowid", VAR_NUMBER), VV_RO},
{VV_NAME("progpath", VAR_STRING), VV_RO},
- {VV_NAME("job_data", VAR_LIST), 0}
+ {VV_NAME("job_data", VAR_LIST), 0},
+ {VV_NAME("command_output", VAR_STRING), 0}
};
/* shorthand */
@@ -443,6 +447,15 @@ static dictitem_T vimvars_var; /* variable used for v: */
#define FNE_CHECK_START 2 /* find_name_end(): check name starts with
valid character */
+// Memory pool for reusing JobEvent structures
+typedef struct {
+ int id;
+ char *name, *type, *received;
+} JobEvent;
+#define JobEventFreer(x)
+KMEMPOOL_INIT(JobEventPool, JobEvent, JobEventFreer)
+kmempool_t(JobEventPool) *job_event_pool = NULL;
+
/*
* Initialize the global and v: variables.
*/
@@ -478,6 +491,7 @@ void eval_init(void)
set_vim_var_nr(VV_HLSEARCH, 1L);
set_reg_var(0); /* default for v:register is not 0 but '"' */
+ job_event_pool = kmp_init(JobEventPool);
}
#if defined(EXITFREE) || defined(PROTO)
@@ -19508,49 +19522,65 @@ char_u *do_string_sub(char_u *str, char_u *pat, char_u *sub, char_u *flags)
return ret;
}
+// JobActivity autocommands will execute vimscript code, so it must be executed
+// on Nvim main loop
+#define push_job_event(j, r, t) \
+ do { \
+ JobEvent *event_data = kmp_alloc(JobEventPool, job_event_pool); \
+ event_data->received = NULL; \
+ if (r) { \
+ size_t read_count = rstream_pending(r); \
+ event_data->received = xmalloc(read_count + 1); \
+ rstream_read(r, event_data->received, read_count); \
+ event_data->received[read_count] = NUL; \
+ } \
+ event_data->id = job_id(j); \
+ event_data->name = job_data(j); \
+ event_data->type = t; \
+ event_push((Event) { \
+ .handler = on_job_event, \
+ .data = event_data \
+ }); \
+ } while(0)
+
static void on_job_stdout(RStream *rstream, void *data, bool eof)
{
if (!eof) {
- on_job_data(rstream, data, eof, "stdout");
+ push_job_event(data, rstream, "stdout");
}
}
static void on_job_stderr(RStream *rstream, void *data, bool eof)
{
if (!eof) {
- on_job_data(rstream, data, eof, "stderr");
+ push_job_event(data, rstream, "stderr");
}
}
static void on_job_exit(Job *job, void *data)
{
- apply_job_autocmds(job, data, "exit", NULL);
- free(data);
+ push_job_event(job, NULL, "exit");
}
-static void on_job_data(RStream *rstream, void *data, bool eof, char *type)
+static void on_job_event(Event event)
{
- Job *job = data;
- uint32_t read_count = rstream_pending(rstream);
- char *str = xmalloc(read_count + 1);
-
- rstream_read(rstream, str, read_count);
- str[read_count] = NUL;
- apply_job_autocmds(job, job_data(job), type, str);
+ JobEvent *data = event.data;
+ apply_job_autocmds(data->id, data->name, data->type, data->received);
+ kmp_free(JobEventPool, job_event_pool, data);
}
-static void apply_job_autocmds(Job *job, char *name, char *type, char *str)
+static void apply_job_autocmds(int id, char *name, char *type, char *received)
{
// Create the list which will be set to v:job_data
list_T *list = list_alloc();
- list_append_number(list, job_id(job));
+ list_append_number(list, id);
list_append_string(list, (uint8_t *)type, -1);
- if (str) {
+ if (received) {
listitem_T *str_slot = listitem_alloc();
str_slot->li_tv.v_type = VAR_STRING;
str_slot->li_tv.v_lock = 0;
- str_slot->li_tv.vval.v_string = (uint8_t *)str;
+ str_slot->li_tv.vval.v_string = (uint8_t *)received;
list_append(list, str_slot);
}
@@ -19558,6 +19588,11 @@ static void apply_job_autocmds(Job *job, char *name, char *type, char *str)
set_vim_var_list(VV_JOB_DATA, list);
// Call JobActivity autocommands
apply_autocmds(EVENT_JOBACTIVITY, (uint8_t *)name, NULL, TRUE, NULL);
+
+ if (!received) {
+ // This must be the exit event. Free the name.
+ free(name);
+ }
}
static void script_host_eval(char *method, typval_T *argvars, typval_T *rettv)