aboutsummaryrefslogtreecommitdiff
path: root/src/nvim
diff options
context:
space:
mode:
Diffstat (limited to 'src/nvim')
-rw-r--r--src/nvim/api/buffer.c24
-rw-r--r--src/nvim/api/private/defs.h4
-rw-r--r--src/nvim/api/private/helpers.c21
-rw-r--r--src/nvim/api/private/helpers.h43
-rw-r--r--src/nvim/api/tabpage.c10
-rw-r--r--src/nvim/api/vim.c6
-rw-r--r--src/nvim/api/window.c28
-rw-r--r--src/nvim/edit.c2
-rw-r--r--src/nvim/eval.c32
-rw-r--r--src/nvim/ex_getln.c6
-rw-r--r--src/nvim/lib/kvec.h48
-rw-r--r--src/nvim/message.c2
-rw-r--r--src/nvim/normal.c2
-rw-r--r--src/nvim/os/channel.c89
-rw-r--r--src/nvim/os/channel.h2
-rw-r--r--src/nvim/os/event.c87
-rw-r--r--src/nvim/os/input.c6
-rw-r--r--src/nvim/os/job.c146
-rw-r--r--src/nvim/os/job.h2
-rw-r--r--src/nvim/os/msgpack_rpc.c27
-rw-r--r--src/nvim/os/msgpack_rpc.h19
-rw-r--r--src/nvim/os/rstream.c38
-rw-r--r--src/nvim/os/signal.c2
-rw-r--r--src/nvim/os/wstream.c21
-rw-r--r--src/nvim/os/wstream_defs.h1
25 files changed, 419 insertions, 249 deletions
diff --git a/src/nvim/api/buffer.c b/src/nvim/api/buffer.c
index adcdc6da94..034ced184a 100644
--- a/src/nvim/api/buffer.c
+++ b/src/nvim/api/buffer.c
@@ -31,7 +31,7 @@
/// @return The line count
Integer buffer_get_length(Buffer buffer, Error *err)
{
- buf_T *buf = find_buffer(buffer, err);
+ buf_T *buf = find_buffer_by_handle(buffer, err);
if (!buf) {
return 0;
@@ -100,7 +100,7 @@ StringArray buffer_get_slice(Buffer buffer,
Error *err)
{
StringArray rv = ARRAY_DICT_INIT;
- buf_T *buf = find_buffer(buffer, err);
+ buf_T *buf = find_buffer_by_handle(buffer, err);
if (!buf) {
return rv;
@@ -160,7 +160,7 @@ void buffer_set_slice(Buffer buffer,
StringArray replacement,
Error *err)
{
- buf_T *buf = find_buffer(buffer, err);
+ buf_T *buf = find_buffer_by_handle(buffer, err);
if (!buf) {
return;
@@ -283,7 +283,7 @@ end:
/// @return The variable value
Object buffer_get_var(Buffer buffer, String name, Error *err)
{
- buf_T *buf = find_buffer(buffer, err);
+ buf_T *buf = find_buffer_by_handle(buffer, err);
if (!buf) {
return (Object) OBJECT_INIT;
@@ -301,7 +301,7 @@ Object buffer_get_var(Buffer buffer, String name, Error *err)
/// @return The old value
Object buffer_set_var(Buffer buffer, String name, Object value, Error *err)
{
- buf_T *buf = find_buffer(buffer, err);
+ buf_T *buf = find_buffer_by_handle(buffer, err);
if (!buf) {
return (Object) OBJECT_INIT;
@@ -318,7 +318,7 @@ Object buffer_set_var(Buffer buffer, String name, Object value, Error *err)
/// @return The option value
Object buffer_get_option(Buffer buffer, String name, Error *err)
{
- buf_T *buf = find_buffer(buffer, err);
+ buf_T *buf = find_buffer_by_handle(buffer, err);
if (!buf) {
return (Object) OBJECT_INIT;
@@ -336,7 +336,7 @@ Object buffer_get_option(Buffer buffer, String name, Error *err)
/// @param[out] err Details of an error that may have occurred
void buffer_set_option(Buffer buffer, String name, Object value, Error *err)
{
- buf_T *buf = find_buffer(buffer, err);
+ buf_T *buf = find_buffer_by_handle(buffer, err);
if (!buf) {
return;
@@ -353,7 +353,7 @@ void buffer_set_option(Buffer buffer, String name, Object value, Error *err)
Integer buffer_get_number(Buffer buffer, Error *err)
{
Integer rv = 0;
- buf_T *buf = find_buffer(buffer, err);
+ buf_T *buf = find_buffer_by_handle(buffer, err);
if (!buf) {
return rv;
@@ -370,7 +370,7 @@ Integer buffer_get_number(Buffer buffer, Error *err)
String buffer_get_name(Buffer buffer, Error *err)
{
String rv = STRING_INIT;
- buf_T *buf = find_buffer(buffer, err);
+ buf_T *buf = find_buffer_by_handle(buffer, err);
if (!buf || buf->b_ffname == NULL) {
return rv;
@@ -386,7 +386,7 @@ String buffer_get_name(Buffer buffer, Error *err)
/// @param[out] err Details of an error that may have occurred
void buffer_set_name(Buffer buffer, String name, Error *err)
{
- buf_T *buf = find_buffer(buffer, err);
+ buf_T *buf = find_buffer_by_handle(buffer, err);
if (!buf) {
return;
@@ -416,7 +416,7 @@ void buffer_set_name(Buffer buffer, String name, Error *err)
Boolean buffer_is_valid(Buffer buffer)
{
Error stub = {.set = false};
- return find_buffer(buffer, &stub) != NULL;
+ return find_buffer_by_handle(buffer, &stub) != NULL;
}
/// Inserts a sequence of lines to a buffer at a certain index
@@ -440,7 +440,7 @@ void buffer_insert(Buffer buffer, Integer lnum, StringArray lines, Error *err)
Position buffer_get_mark(Buffer buffer, String name, Error *err)
{
Position rv = POSITION_INIT;
- buf_T *buf = find_buffer(buffer, err);
+ buf_T *buf = find_buffer_by_handle(buffer, err);
if (!buf) {
return rv;
diff --git a/src/nvim/api/private/defs.h b/src/nvim/api/private/defs.h
index ab806941f4..ee0fc02c4d 100644
--- a/src/nvim/api/private/defs.h
+++ b/src/nvim/api/private/defs.h
@@ -49,14 +49,14 @@ typedef struct {
typedef struct {
Object *items;
- size_t size;
+ size_t size, capacity;
} Array;
typedef struct key_value_pair KeyValuePair;
typedef struct {
KeyValuePair *items;
- size_t size;
+ size_t size, capacity;
} Dictionary;
typedef enum {
diff --git a/src/nvim/api/private/helpers.c b/src/nvim/api/private/helpers.c
index 264ac7a507..30301e9368 100644
--- a/src/nvim/api/private/helpers.c
+++ b/src/nvim/api/private/helpers.c
@@ -288,12 +288,7 @@ Object vim_to_object(typval_T *obj)
return rv;
}
-/// Finds the pointer for a window number
-///
-/// @param window the window number
-/// @param[out] err Details of an error that may have occurred
-/// @return the window pointer
-buf_T *find_buffer(Buffer buffer, Error *err)
+buf_T *find_buffer_by_handle(Buffer buffer, Error *err)
{
buf_T *rv = handle_get_buffer(buffer);
@@ -304,12 +299,7 @@ buf_T *find_buffer(Buffer buffer, Error *err)
return rv;
}
-/// Finds the pointer for a window number
-///
-/// @param window the window number
-/// @param[out] err Details of an error that may have occurred
-/// @return the window pointer
-win_T * find_window(Window window, Error *err)
+win_T * find_window_by_handle(Window window, Error *err)
{
win_T *rv = handle_get_window(window);
@@ -320,12 +310,7 @@ win_T * find_window(Window window, Error *err)
return rv;
}
-/// Finds the pointer for a tabpage number
-///
-/// @param tabpage the tabpage number
-/// @param[out] err Details of an error that may have occurred
-/// @return the tabpage pointer
-tabpage_T * find_tab(Tabpage tabpage, Error *err)
+tabpage_T * find_tab_by_handle(Tabpage tabpage, Error *err)
{
tabpage_T *rv = handle_get_tabpage(tabpage);
diff --git a/src/nvim/api/private/helpers.h b/src/nvim/api/private/helpers.h
index 68ab4ff614..e1e1a35490 100644
--- a/src/nvim/api/private/helpers.h
+++ b/src/nvim/api/private/helpers.h
@@ -6,6 +6,7 @@
#include "nvim/api/private/defs.h"
#include "nvim/vim.h"
#include "nvim/memory.h"
+#include "nvim/lib/kvec.h"
#define set_api_error(message, err) \
do { \
@@ -13,6 +14,48 @@
err->set = true; \
} while (0)
+#define BOOL_OBJ(b) ((Object) { \
+ .type = kObjectTypeBoolean, \
+ .data.boolean = b \
+ })
+
+#define INTEGER_OBJ(i) ((Object) { \
+ .type = kObjectTypeInteger, \
+ .data.integer = i \
+ })
+
+#define STRING_OBJ(s) ((Object) { \
+ .type = kObjectTypeString, \
+ .data.string = cstr_to_string(s) \
+ })
+
+#define STRINGL_OBJ(d, s) ((Object) { \
+ .type = kObjectTypeString, \
+ .data.string = (String) { \
+ .size = s, \
+ .data = xmemdup(d, s) \
+ }})
+
+#define ARRAY_OBJ(a) ((Object) { \
+ .type = kObjectTypeArray, \
+ .data.array = a \
+ })
+
+#define DICTIONARY_OBJ(d) ((Object) { \
+ .type = kObjectTypeDictionary, \
+ .data.dictionary = d \
+ })
+
+#define NIL ((Object) {.type = kObjectTypeNil})
+
+#define PUT(dict, k, v) \
+ kv_push(KeyValuePair, \
+ dict, \
+ ((KeyValuePair) {.key = cstr_to_string(k), .value = v}))
+
+#define ADD(array, item) \
+ kv_push(Object, array, item)
+
#ifdef INCLUDE_GENERATED_DECLARATIONS
# include "api/private/helpers.h.generated.h"
#endif
diff --git a/src/nvim/api/tabpage.c b/src/nvim/api/tabpage.c
index 8d92b01cf9..535722c087 100644
--- a/src/nvim/api/tabpage.c
+++ b/src/nvim/api/tabpage.c
@@ -16,7 +16,7 @@
WindowArray tabpage_get_windows(Tabpage tabpage, Error *err)
{
WindowArray rv = ARRAY_DICT_INIT;
- tabpage_T *tab = find_tab(tabpage, err);
+ tabpage_T *tab = find_tab_by_handle(tabpage, err);
if (!tab) {
return rv;
@@ -53,7 +53,7 @@ WindowArray tabpage_get_windows(Tabpage tabpage, Error *err)
/// @return The variable value
Object tabpage_get_var(Tabpage tabpage, String name, Error *err)
{
- tabpage_T *tab = find_tab(tabpage, err);
+ tabpage_T *tab = find_tab_by_handle(tabpage, err);
if (!tab) {
return (Object) OBJECT_INIT;
@@ -71,7 +71,7 @@ Object tabpage_get_var(Tabpage tabpage, String name, Error *err)
/// @return The tab page handle
Object tabpage_set_var(Tabpage tabpage, String name, Object value, Error *err)
{
- tabpage_T *tab = find_tab(tabpage, err);
+ tabpage_T *tab = find_tab_by_handle(tabpage, err);
if (!tab) {
return (Object) OBJECT_INIT;
@@ -88,7 +88,7 @@ Object tabpage_set_var(Tabpage tabpage, String name, Object value, Error *err)
Window tabpage_get_window(Tabpage tabpage, Error *err)
{
Window rv = 0;
- tabpage_T *tab = find_tab(tabpage, err);
+ tabpage_T *tab = find_tab_by_handle(tabpage, err);
if (!tab) {
return rv;
@@ -117,6 +117,6 @@ Window tabpage_get_window(Tabpage tabpage, Error *err)
Boolean tabpage_is_valid(Tabpage tabpage)
{
Error stub = {.set = false};
- return find_tab(tabpage, &stub) != NULL;
+ return find_tab_by_handle(tabpage, &stub) != NULL;
}
diff --git a/src/nvim/api/vim.c b/src/nvim/api/vim.c
index b99311a61a..e7261e1096 100644
--- a/src/nvim/api/vim.c
+++ b/src/nvim/api/vim.c
@@ -291,7 +291,7 @@ Buffer vim_get_current_buffer(void)
/// @param[out] err Details of an error that may have occurred
void vim_set_current_buffer(Buffer buffer, Error *err)
{
- buf_T *buf = find_buffer(buffer, err);
+ buf_T *buf = find_buffer_by_handle(buffer, err);
if (!buf) {
return;
@@ -348,7 +348,7 @@ Window vim_get_current_window(void)
/// @param handle The window handle
void vim_set_current_window(Window window, Error *err)
{
- win_T *win = find_window(window, err);
+ win_T *win = find_window_by_handle(window, err);
if (!win) {
return;
@@ -407,7 +407,7 @@ Tabpage vim_get_current_tabpage(void)
/// @param[out] err Details of an error that may have occurred
void vim_set_current_tabpage(Tabpage tabpage, Error *err)
{
- tabpage_T *tp = find_tab(tabpage, err);
+ tabpage_T *tp = find_tab_by_handle(tabpage, err);
if (!tp) {
return;
diff --git a/src/nvim/api/window.c b/src/nvim/api/window.c
index 2b81afdb0c..548d8171a5 100644
--- a/src/nvim/api/window.c
+++ b/src/nvim/api/window.c
@@ -19,7 +19,7 @@
/// @return The buffer handle
Buffer window_get_buffer(Window window, Error *err)
{
- win_T *win = find_window(window, err);
+ win_T *win = find_window_by_handle(window, err);
if (!win) {
return 0;
@@ -36,7 +36,7 @@ Buffer window_get_buffer(Window window, Error *err)
Position window_get_cursor(Window window, Error *err)
{
Position rv = {.row = 0, .col = 0};
- win_T *win = find_window(window, err);
+ win_T *win = find_window_by_handle(window, err);
if (win) {
rv.row = win->w_cursor.lnum;
@@ -53,7 +53,7 @@ Position window_get_cursor(Window window, Error *err)
/// @param[out] err Details of an error that may have occurred
void window_set_cursor(Window window, Position pos, Error *err)
{
- win_T *win = find_window(window, err);
+ win_T *win = find_window_by_handle(window, err);
if (!win) {
return;
@@ -89,7 +89,7 @@ void window_set_cursor(Window window, Position pos, Error *err)
/// @return the height in rows
Integer window_get_height(Window window, Error *err)
{
- win_T *win = find_window(window, err);
+ win_T *win = find_window_by_handle(window, err);
if (!win) {
return 0;
@@ -106,7 +106,7 @@ Integer window_get_height(Window window, Error *err)
/// @param[out] err Details of an error that may have occurred
void window_set_height(Window window, Integer height, Error *err)
{
- win_T *win = find_window(window, err);
+ win_T *win = find_window_by_handle(window, err);
if (!win) {
return;
@@ -132,7 +132,7 @@ void window_set_height(Window window, Integer height, Error *err)
/// @return the width in columns
Integer window_get_width(Window window, Error *err)
{
- win_T *win = find_window(window, err);
+ win_T *win = find_window_by_handle(window, err);
if (!win) {
return 0;
@@ -149,7 +149,7 @@ Integer window_get_width(Window window, Error *err)
/// @param[out] err Details of an error that may have occurred
void window_set_width(Window window, Integer width, Error *err)
{
- win_T *win = find_window(window, err);
+ win_T *win = find_window_by_handle(window, err);
if (!win) {
return;
@@ -176,7 +176,7 @@ void window_set_width(Window window, Integer width, Error *err)
/// @return The variable value
Object window_get_var(Window window, String name, Error *err)
{
- win_T *win = find_window(window, err);
+ win_T *win = find_window_by_handle(window, err);
if (!win) {
return (Object) OBJECT_INIT;
@@ -194,7 +194,7 @@ Object window_get_var(Window window, String name, Error *err)
/// @return The old value
Object window_set_var(Window window, String name, Object value, Error *err)
{
- win_T *win = find_window(window, err);
+ win_T *win = find_window_by_handle(window, err);
if (!win) {
return (Object) OBJECT_INIT;
@@ -211,7 +211,7 @@ Object window_set_var(Window window, String name, Object value, Error *err)
/// @return The option value
Object window_get_option(Window window, String name, Error *err)
{
- win_T *win = find_window(window, err);
+ win_T *win = find_window_by_handle(window, err);
if (!win) {
return (Object) OBJECT_INIT;
@@ -229,7 +229,7 @@ Object window_get_option(Window window, String name, Error *err)
/// @param[out] err Details of an error that may have occurred
void window_set_option(Window window, String name, Object value, Error *err)
{
- win_T *win = find_window(window, err);
+ win_T *win = find_window_by_handle(window, err);
if (!win) {
return;
@@ -246,7 +246,7 @@ void window_set_option(Window window, String name, Object value, Error *err)
Position window_get_position(Window window, Error *err)
{
Position rv;
- win_T *win = find_window(window, err);
+ win_T *win = find_window_by_handle(window, err);
if (win) {
rv.col = win->w_wincol;
@@ -264,7 +264,7 @@ Position window_get_position(Window window, Error *err)
Tabpage window_get_tabpage(Window window, Error *err)
{
Tabpage rv = 0;
- win_T *win = find_window(window, err);
+ win_T *win = find_window_by_handle(window, err);
if (win) {
rv = win_find_tabpage(win)->handle;
@@ -280,6 +280,6 @@ Tabpage window_get_tabpage(Window window, Error *err)
Boolean window_is_valid(Window window)
{
Error stub = {.set = false};
- return find_window(window, &stub) != NULL;
+ return find_window_by_handle(window, &stub) != NULL;
}
diff --git a/src/nvim/edit.c b/src/nvim/edit.c
index 5a70964d57..c0a99baf0f 100644
--- a/src/nvim/edit.c
+++ b/src/nvim/edit.c
@@ -939,7 +939,7 @@ doESCkey:
break;
case K_EVENT:
- event_process();
+ event_process(true);
break;
case K_HOME: /* <Home> */
diff --git a/src/nvim/eval.c b/src/nvim/eval.c
index 1de2b7bbf1..0df0c1e4f4 100644
--- a/src/nvim/eval.c
+++ b/src/nvim/eval.c
@@ -70,6 +70,7 @@
#include "nvim/os/rstream_defs.h"
#include "nvim/os/time.h"
#include "nvim/os/channel.h"
+#include "nvim/api/private/helpers.h"
#define DICT_MAXNEST 100 /* maximum nesting of lists and dicts */
@@ -10471,11 +10472,13 @@ static void f_job_start(typval_T *argvars, typval_T *rettv)
// The last item of argv must be NULL
argv[i] = NULL;
- rettv->vval.v_number = job_start(argv,
- xstrdup((char *)argvars[0].vval.v_string),
- on_job_stdout,
- on_job_stderr,
- on_job_exit);
+ job_start(argv,
+ xstrdup((char *)argvars[0].vval.v_string),
+ on_job_stdout,
+ on_job_stderr,
+ on_job_exit,
+ true,
+ &rettv->vval.v_number);
if (rettv->vval.v_number <= 0) {
if (rettv->vval.v_number == 0) {
@@ -10502,19 +10505,21 @@ static void f_job_stop(typval_T *argvars, typval_T *rettv)
return;
}
- if (!job_stop(argvars[0].vval.v_number)) {
+ Job *job = job_find(argvars[0].vval.v_number);
+
+ if (!job) {
// Probably an invalid job id
EMSG(_(e_invjob));
return;
}
+ job_stop(job);
rettv->vval.v_number = 1;
}
// "jobwrite()" function
static void f_job_write(typval_T *argvars, typval_T *rettv)
{
- bool res;
rettv->v_type = VAR_NUMBER;
rettv->vval.v_number = 0;
@@ -10529,16 +10534,17 @@ static void f_job_write(typval_T *argvars, typval_T *rettv)
return;
}
- res = job_write(argvars[0].vval.v_number,
- xstrdup((char *)argvars[1].vval.v_string),
- strlen((char *)argvars[1].vval.v_string));
+ Job *job = job_find(argvars[0].vval.v_number);
- if (!res) {
+ if (!job) {
// Invalid job id
EMSG(_(e_invjob));
}
- rettv->vval.v_number = 1;
+ WBuffer *buf = wstream_new_buffer(xstrdup((char *)argvars[1].vval.v_string),
+ strlen((char *)argvars[1].vval.v_string),
+ free);
+ rettv->vval.v_number = job_write(job, buf);
}
/*
@@ -12550,7 +12556,7 @@ static void f_send_event(typval_T *argvars, typval_T *rettv)
if (!channel_send_event((uint64_t)argvars[0].vval.v_number,
(char *)argvars[1].vval.v_string,
- &argvars[2])) {
+ vim_to_object(&argvars[2]))) {
EMSG2(_(e_invarg2), "Channel doesn't exist");
return;
}
diff --git a/src/nvim/ex_getln.c b/src/nvim/ex_getln.c
index 02c82eaf21..9b09abb1b7 100644
--- a/src/nvim/ex_getln.c
+++ b/src/nvim/ex_getln.c
@@ -758,7 +758,7 @@ getcmdline (
*/
switch (c) {
case K_EVENT:
- event_process();
+ event_process(true);
// Force a redraw even though the command line didn't change
shell_resized();
goto cmdline_not_changed;
@@ -1873,8 +1873,8 @@ redraw:
}
if (IS_SPECIAL(c1)) {
- // Process pending events
- event_process();
+ // Process deferred events
+ event_process(true);
// Ignore other special key codes
continue;
}
diff --git a/src/nvim/lib/kvec.h b/src/nvim/lib/kvec.h
index fe17afb7c2..982b5d6f1c 100644
--- a/src/nvim/lib/kvec.h
+++ b/src/nvim/lib/kvec.h
@@ -53,39 +53,39 @@ int main() {
#define kv_roundup32(x) (--(x), (x)|=(x)>>1, (x)|=(x)>>2, (x)|=(x)>>4, (x)|=(x)>>8, (x)|=(x)>>16, ++(x))
-#define kvec_t(type) struct { size_t n, m; type *a; }
-#define kv_init(v) ((v).n = (v).m = 0, (v).a = 0)
-#define kv_destroy(v) free((v).a)
-#define kv_A(v, i) ((v).a[(i)])
-#define kv_pop(v) ((v).a[--(v).n])
-#define kv_size(v) ((v).n)
-#define kv_max(v) ((v).m)
+#define kvec_t(type) struct { size_t size, capacity; type *items; }
+#define kv_init(v) ((v).size = (v).capacity = 0, (v).items = 0)
+#define kv_destroy(v) free((v).items)
+#define kv_A(v, i) ((v).items[(i)])
+#define kv_pop(v) ((v).items[--(v).size])
+#define kv_size(v) ((v).size)
+#define kv_max(v) ((v).capacity)
-#define kv_resize(type, v, s) ((v).m = (s), (v).a = (type*)xrealloc((v).a, sizeof(type) * (v).m))
+#define kv_resize(type, v, s) ((v).capacity = (s), (v).items = (type*)xrealloc((v).items, sizeof(type) * (v).capacity))
#define kv_copy(type, v1, v0) do { \
- if ((v1).m < (v0).n) kv_resize(type, v1, (v0).n); \
- (v1).n = (v0).n; \
- memcpy((v1).a, (v0).a, sizeof(type) * (v0).n); \
+ if ((v1).capacity < (v0).size) kv_resize(type, v1, (v0).size); \
+ (v1).size = (v0).size; \
+ memcpy((v1).items, (v0).items, sizeof(type) * (v0).size); \
} while (0) \
#define kv_push(type, v, x) do { \
- if ((v).n == (v).m) { \
- (v).m = (v).m? (v).m<<1 : 2; \
- (v).a = (type*)xrealloc((v).a, sizeof(type) * (v).m); \
+ if ((v).size == (v).capacity) { \
+ (v).capacity = (v).capacity? (v).capacity<<1 : 8; \
+ (v).items = (type*)xrealloc((v).items, sizeof(type) * (v).capacity); \
} \
- (v).a[(v).n++] = (x); \
+ (v).items[(v).size++] = (x); \
} while (0)
-#define kv_pushp(type, v) (((v).n == (v).m)? \
- ((v).m = ((v).m? (v).m<<1 : 2), \
- (v).a = (type*)xrealloc((v).a, sizeof(type) * (v).m), 0) \
- : 0), ((v).a + ((v).n++))
+#define kv_pushp(type, v) (((v).size == (v).capacity)? \
+ ((v).capacity = ((v).capacity? (v).capacity<<1 : 8), \
+ (v).items = (type*)xrealloc((v).items, sizeof(type) * (v).capacity), 0) \
+ : 0), ((v).items + ((v).size++))
-#define kv_a(type, v, i) (((v).m <= (size_t)(i)? \
- ((v).m = (v).n = (i) + 1, kv_roundup32((v).m), \
- (v).a = (type*)xrealloc((v).a, sizeof(type) * (v).m), 0) \
- : (v).n <= (size_t)(i)? (v).n = (i) + 1 \
- : 0), (v).a[(i)])
+#define kv_a(type, v, i) (((v).capacity <= (size_t)(i)? \
+ ((v).capacity = (v).size = (i) + 1, kv_roundup32((v).capacity), \
+ (v).items = (type*)xrealloc((v).items, sizeof(type) * (v).capacity), 0) \
+ : (v).size <= (size_t)(i)? (v).size = (i) + 1 \
+ : 0), (v).items[(i)])
#endif
diff --git a/src/nvim/message.c b/src/nvim/message.c
index 281270155a..1571e8678f 100644
--- a/src/nvim/message.c
+++ b/src/nvim/message.c
@@ -2064,7 +2064,7 @@ static int do_more_prompt(int typed_char)
toscroll = 0;
switch (c) {
case K_EVENT:
- event_process();
+ event_process(true);
break;
case BS: /* scroll one line back */
case K_BS:
diff --git a/src/nvim/normal.c b/src/nvim/normal.c
index f4f03f4ff8..9fb096f7d2 100644
--- a/src/nvim/normal.c
+++ b/src/nvim/normal.c
@@ -7368,5 +7368,5 @@ static void nv_cursorhold(cmdarg_T *cap)
static void nv_event(cmdarg_T *cap)
{
- event_process();
+ event_process(true);
}
diff --git a/src/nvim/os/channel.c b/src/nvim/os/channel.c
index 9a692cf9fe..653f09756a 100644
--- a/src/nvim/os/channel.c
+++ b/src/nvim/os/channel.c
@@ -24,7 +24,7 @@ typedef struct {
msgpack_unpacker *unpacker;
msgpack_sbuffer *sbuffer;
union {
- int job_id;
+ Job *job;
struct {
RStream *read;
WStream *write;
@@ -68,11 +68,26 @@ void channel_teardown()
/// stdin/stdout. stderr is forwarded to the editor error stream.
///
/// @param argv The argument vector for the process
-void channel_from_job(char **argv)
+bool channel_from_job(char **argv)
{
Channel *channel = register_channel();
channel->is_job = true;
- channel->data.job_id = job_start(argv, channel, job_out, job_err, NULL);
+
+ int status;
+ channel->data.job = job_start(argv,
+ channel,
+ job_out,
+ job_err,
+ job_exit,
+ true,
+ &status);
+
+ if (status <= 0) {
+ close_channel(channel);
+ return false;
+ }
+
+ return true;
}
/// Creates an API channel from a libuv stream representing a tcp or
@@ -101,12 +116,13 @@ void channel_from_stream(uv_stream_t *stream)
/// @param type The event type, an arbitrary string
/// @param obj The event data
/// @return True if the data was sent successfully, false otherwise.
-bool channel_send_event(uint64_t id, char *type, typval_T *data)
+bool channel_send_event(uint64_t id, char *type, Object data)
{
Channel *channel = NULL;
if (id > 0) {
if (!(channel = pmap_get(uint64_t)(channels, id))) {
+ msgpack_rpc_free_object(data);
return false;
}
send_event(channel, type, data);
@@ -126,7 +142,7 @@ void channel_subscribe(uint64_t id, char *event)
Channel *channel;
if (!(channel = pmap_get(uint64_t)(channels, id))) {
- return;
+ abort();
}
char *event_string = pmap_get(cstr_t)(event_strings, event);
@@ -148,7 +164,7 @@ void channel_unsubscribe(uint64_t id, char *event)
Channel *channel;
if (!(channel = pmap_get(uint64_t)(channels, id))) {
- return;
+ abort();
}
unsubscribe(channel, event);
@@ -165,6 +181,11 @@ static void job_err(RStream *rstream, void *data, bool eof)
// TODO(tarruda): plugin error messages should be sent to the error buffer
}
+static void job_exit(Job *job, void *data)
+{
+ // TODO(tarruda): what should be done here?
+}
+
static void parse_msgpack(RStream *rstream, void *data, bool eof)
{
Channel *channel = data;
@@ -183,30 +204,57 @@ static void parse_msgpack(RStream *rstream, void *data, bool eof)
msgpack_unpacked unpacked;
msgpack_unpacked_init(&unpacked);
+ UnpackResult result;
+ msgpack_packer response;
// Deserialize everything we can.
- while (msgpack_unpacker_next(channel->unpacker, &unpacked)) {
+ while ((result = msgpack_rpc_unpack(channel->unpacker, &unpacked))
+ == kUnpackResultOk) {
// Each object is a new msgpack-rpc request and requires an empty response
- msgpack_packer response;
msgpack_packer_init(&response, channel->sbuffer, msgpack_sbuffer_write);
// Perform the call
msgpack_rpc_call(channel->id, &unpacked.data, &response);
wstream_write(channel->data.streams.write,
- wstream_new_buffer(channel->sbuffer->data,
+ wstream_new_buffer(xmemdup(channel->sbuffer->data,
+ channel->sbuffer->size),
channel->sbuffer->size,
- true));
+ free));
// Clear the buffer for future calls
msgpack_sbuffer_clear(channel->sbuffer);
}
+
+ if (result == kUnpackResultFail) {
+ // See src/msgpack/unpack_template.h in msgpack source tree for
+ // causes for this error(search for 'goto _failed')
+ //
+ // A not so uncommon cause for this might be deserializing objects with
+ // a high nesting level: msgpack will break when it's internal parse stack
+ // size exceeds MSGPACK_EMBED_STACK_SIZE(defined as 32 by default)
+ msgpack_packer_init(&response, channel->sbuffer, msgpack_sbuffer_write);
+ msgpack_pack_array(&response, 4);
+ msgpack_pack_int(&response, 1);
+ msgpack_pack_int(&response, 0);
+ msgpack_rpc_error("Invalid msgpack payload. "
+ "This error can also happen when deserializing "
+ "an object with high level of nesting",
+ &response);
+ wstream_write(channel->data.streams.write,
+ wstream_new_buffer(xmemdup(channel->sbuffer->data,
+ channel->sbuffer->size),
+ channel->sbuffer->size,
+ free));
+ // Clear the buffer for future calls
+ msgpack_sbuffer_clear(channel->sbuffer);
+ }
}
-static void send_event(Channel *channel, char *type, typval_T *data)
+static void send_event(Channel *channel, char *type, Object data)
{
wstream_write(channel->data.streams.write, serialize_event(type, data));
}
-static void broadcast_event(char *type, typval_T *data)
+static void broadcast_event(char *type, Object data)
{
kvec_t(Channel *) subscribed;
kv_init(subscribed);
@@ -219,6 +267,7 @@ static void broadcast_event(char *type, typval_T *data)
});
if (!kv_size(subscribed)) {
+ msgpack_rpc_free_object(data);
goto end;
}
@@ -255,7 +304,9 @@ static void close_channel(Channel *channel)
msgpack_unpacker_free(channel->unpacker);
if (channel->is_job) {
- job_stop(channel->data.job_id);
+ if (channel->data.job) {
+ job_stop(channel->data.job);
+ }
} else {
rstream_free(channel->data.streams.read);
wstream_free(channel->data.streams.write);
@@ -278,17 +329,17 @@ static void close_cb(uv_handle_t *handle)
free(handle);
}
-static WBuffer *serialize_event(char *type, typval_T *data)
+static WBuffer *serialize_event(char *type, Object data)