aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/nvim/api/private/defs.h18
-rw-r--r--src/nvim/api/private/helpers.c2
-rw-r--r--src/nvim/api/private/helpers.h51
-rw-r--r--src/nvim/os/channel.c26
-rw-r--r--src/nvim/os/msgpack_rpc.c162
-rw-r--r--src/nvim/os/msgpack_rpc.h13
-rw-r--r--src/nvim/os/msgpack_rpc_helpers.c55
7 files changed, 230 insertions, 97 deletions
diff --git a/src/nvim/api/private/defs.h b/src/nvim/api/private/defs.h
index ee0fc02c4d..b049412014 100644
--- a/src/nvim/api/private/defs.h
+++ b/src/nvim/api/private/defs.h
@@ -65,8 +65,16 @@ typedef enum {
kObjectTypeInteger,
kObjectTypeFloat,
kObjectTypeString,
+ kObjectTypeBuffer,
+ kObjectTypeWindow,
+ kObjectTypeTabpage,
kObjectTypeArray,
- kObjectTypeDictionary
+ kObjectTypeDictionary,
+ kObjectTypePosition,
+ kObjectTypeStringArray,
+ kObjectTypeBufferArray,
+ kObjectTypeWindowArray,
+ kObjectTypeTabpageArray,
} ObjectType;
struct object {
@@ -76,8 +84,16 @@ struct object {
Integer integer;
Float floating;
String string;
+ Buffer buffer;
+ Window window;
+ Tabpage tabpage;
Array array;
Dictionary dictionary;
+ Position position;
+ StringArray stringarray;
+ BufferArray bufferarray;
+ WindowArray windowarray;
+ TabpageArray tabpagearray;
} data;
};
diff --git a/src/nvim/api/private/helpers.c b/src/nvim/api/private/helpers.c
index d5ebc93f7c..024f0c2405 100644
--- a/src/nvim/api/private/helpers.c
+++ b/src/nvim/api/private/helpers.c
@@ -426,6 +426,8 @@ bool object_to_vim(Object obj, typval_T *tv, Error *err)
}
tv->vval.v_dict->dv_refcount++;
break;
+ default:
+ abort();
}
return true;
diff --git a/src/nvim/api/private/helpers.h b/src/nvim/api/private/helpers.h
index e1e1a35490..f1b9dc3bc8 100644
--- a/src/nvim/api/private/helpers.h
+++ b/src/nvim/api/private/helpers.h
@@ -14,7 +14,9 @@
err->set = true; \
} while (0)
-#define BOOL_OBJ(b) ((Object) { \
+#define OBJECT_OBJ(o) o
+
+#define BOOLEAN_OBJ(b) ((Object) { \
.type = kObjectTypeBoolean, \
.data.boolean = b \
})
@@ -26,26 +28,59 @@
#define STRING_OBJ(s) ((Object) { \
.type = kObjectTypeString, \
- .data.string = cstr_to_string(s) \
+ .data.string = s \
})
-#define STRINGL_OBJ(d, s) ((Object) { \
- .type = kObjectTypeString, \
- .data.string = (String) { \
- .size = s, \
- .data = xmemdup(d, s) \
- }})
+#define BUFFER_OBJ(s) ((Object) { \
+ .type = kObjectTypeBuffer, \
+ .data.buffer = s \
+ })
+
+#define WINDOW_OBJ(s) ((Object) { \
+ .type = kObjectTypeWindow, \
+ .data.window = s \
+ })
+
+#define TABPAGE_OBJ(s) ((Object) { \
+ .type = kObjectTypeTabpage, \
+ .data.tabpage = s \
+ })
#define ARRAY_OBJ(a) ((Object) { \
.type = kObjectTypeArray, \
.data.array = a \
})
+#define STRINGARRAY_OBJ(a) ((Object) { \
+ .type = kObjectTypeStringArray, \
+ .data.stringarray = a \
+ })
+
+#define BUFFERARRAY_OBJ(a) ((Object) { \
+ .type = kObjectTypeBufferArray, \
+ .data.bufferarray = a \
+ })
+
+#define WINDOWARRAY_OBJ(a) ((Object) { \
+ .type = kObjectTypeWindowArray, \
+ .data.windowarray = a \
+ })
+
+#define TABPAGEARRAY_OBJ(a) ((Object) { \
+ .type = kObjectTypeTabpageArray, \
+ .data.tabpagearray = a \
+ })
+
#define DICTIONARY_OBJ(d) ((Object) { \
.type = kObjectTypeDictionary, \
.data.dictionary = d \
})
+#define POSITION_OBJ(p) ((Object) { \
+ .type = kObjectTypePosition, \
+ .data.position = p \
+ })
+
#define NIL ((Object) {.type = kObjectTypeNil})
#define PUT(dict, k, v) \
diff --git a/src/nvim/os/channel.c b/src/nvim/os/channel.c
index b44b1d13a4..9bba247a7b 100644
--- a/src/nvim/os/channel.c
+++ b/src/nvim/os/channel.c
@@ -31,7 +31,6 @@ typedef struct {
PMap(cstr_t) *subscribed_events;
bool is_job, enabled;
msgpack_unpacker *unpacker;
- msgpack_sbuffer *sbuffer;
union {
Job *job;
struct {
@@ -168,7 +167,7 @@ bool channel_send_call(uint64_t id,
"Channel %" PRIu64 " was closed due to a high stack depth "
"while processing a RPC call",
channel->id);
- *result = STRING_OBJ(buf);
+ *result = STRING_OBJ(cstr_to_string(buf));
}
uint64_t request_id = channel->next_request_id++;
@@ -319,20 +318,12 @@ static void parse_msgpack(RStream *rstream, void *data, bool eof)
goto end;
}
- // 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);
- WBuffer *buffer = wstream_new_buffer(xmemdup(channel->sbuffer->data,
- channel->sbuffer->size),
- channel->sbuffer->size,
- free);
- if (!channel_write(channel, buffer)) {
+ WBuffer *resp = msgpack_rpc_call(channel->id, &unpacked.data, &out_buffer);
+ // write the response
+ if (!channel_write(channel, resp)) {
goto end;
}
- // Clear the buffer for future calls
- msgpack_sbuffer_clear(channel->sbuffer);
}
if (result == kUnpackResultFail) {
@@ -379,10 +370,9 @@ static bool channel_write(Channel *channel, WBuffer *buffer)
return success;
}
-static void send_error(Channel *channel, uint64_t id, char *err_msg)
+static void send_error(Channel *channel, uint64_t id, char *err)
{
- String err = {.size = strlen(err_msg), .data = err_msg};
- channel_write(channel, serialize_response(id, err, NIL, channel->sbuffer));
+ channel_write(channel, serialize_response(id, err, NIL, &out_buffer));
}
static void send_request(Channel *channel,
@@ -449,7 +439,6 @@ static void unsubscribe(Channel *channel, char *event)
static void close_channel(Channel *channel)
{
pmap_del(uint64_t)(channels, channel->id);
- msgpack_sbuffer_free(channel->sbuffer);
msgpack_unpacker_free(channel->unpacker);
if (channel->is_job) {
@@ -485,7 +474,6 @@ static Channel *register_channel()
rv->enabled = true;
rv->rpc_call_level = 0;
rv->unpacker = msgpack_unpacker_new(MSGPACK_UNPACKER_INIT_BUFFER_SIZE);
- rv->sbuffer = msgpack_sbuffer_new();
rv->id = next_id++;
rv->subscribed_events = pmap_new(cstr_t)();
rv->next_request_id = 1;
@@ -530,7 +518,7 @@ static void call_stack_unwind(Channel *channel, char *msg, int count)
while (kv_size(channel->call_stack) && count--) {
ChannelCallFrame *frame = kv_pop(channel->call_stack);
frame->errored = true;
- frame->result = STRING_OBJ(msg);
+ frame->result = STRING_OBJ(cstr_to_string(msg));
}
}
diff --git a/src/nvim/os/msgpack_rpc.c b/src/nvim/os/msgpack_rpc.c
index 5e2ec6aa10..85569372da 100644
--- a/src/nvim/os/msgpack_rpc.c
+++ b/src/nvim/os/msgpack_rpc.c
@@ -8,77 +8,53 @@
#include "nvim/os/wstream.h"
#include "nvim/os/msgpack_rpc.h"
#include "nvim/os/msgpack_rpc_helpers.h"
+#include "nvim/api/private/helpers.h"
#include "nvim/func_attr.h"
#ifdef INCLUDE_GENERATED_DECLARATIONS
# include "os/msgpack_rpc.c.generated.h"
#endif
+extern const uint8_t msgpack_metadata[];
+extern const unsigned int msgpack_metadata_size;
+
/// Validates the basic structure of the msgpack-rpc call and fills `res`
/// with the basic response structure.
///
-/// @param id The channel id
+/// @param channel_id The channel id
/// @param req The parsed request object
/// @param res A packer that contains the response
-void msgpack_rpc_call(uint64_t id, msgpack_object *req, msgpack_packer *res)
- FUNC_ATTR_NONNULL_ARG(2) FUNC_ATTR_NONNULL_ARG(3)
+WBuffer *msgpack_rpc_call(uint64_t channel_id,
+ msgpack_object *req,
+ msgpack_sbuffer *sbuffer)
+ FUNC_ATTR_NONNULL_ARG(2)
+ FUNC_ATTR_NONNULL_ARG(3)
{
- // The initial response structure is the same no matter what happens,
- // we set it up here
- // Array of size 4
- msgpack_pack_array(res, 4);
- // Response type is 1
- msgpack_pack_int(res, 1);
-
- // Validate the basic structure of the msgpack-rpc payload
- if (req->type != MSGPACK_OBJECT_ARRAY) {
- msgpack_pack_int(res, 0); // no message id yet
- msgpack_rpc_error("Request is not an array", res);
- return;
- }
-
- if (req->via.array.size != 4) {
- msgpack_pack_int(res, 0); // no message id yet
- char error_msg[256];
- snprintf(error_msg,
- sizeof(error_msg),
- "Request array size is %u, it should be 4",
- req->via.array.size);
- msgpack_rpc_error(error_msg, res);
- return;
- }
+ uint64_t response_id;
+ char *err = msgpack_rpc_validate(&response_id, req);
- if (req->via.array.ptr[1].type != MSGPACK_OBJECT_POSITIVE_INTEGER) {
- msgpack_pack_int(res, 0); // no message id yet
- msgpack_rpc_error("Id must be a positive integer", res);
- return;
+ if (err) {
+ return serialize_response(response_id, err, NIL, sbuffer);
}
- // Set the response id, which is the same as the request
- msgpack_pack_uint64(res, req->via.array.ptr[1].via.u64);
+ uint64_t method_id = req->via.array.ptr[2].via.u64;
- if (req->via.array.ptr[0].type != MSGPACK_OBJECT_POSITIVE_INTEGER) {
- msgpack_rpc_error("Message type must be an integer", res);
- return;
+ if (method_id == 0) {
+ return serialize_metadata(response_id, channel_id, sbuffer);
}
- if (req->via.array.ptr[0].via.u64 != 0) {
- msgpack_rpc_error("Message type must be 0", res);
- return;
- }
+ // dispatch the call
+ Error error = { .set = false };
+ Object rv = msgpack_rpc_dispatch(channel_id, method_id, req, &error);
+ // send the response
+ msgpack_packer response;
+ msgpack_packer_init(&response, sbuffer, msgpack_sbuffer_write);
- if (req->via.array.ptr[2].type != MSGPACK_OBJECT_POSITIVE_INTEGER) {
- msgpack_rpc_error("Method id must be a positive integer", res);
- return;
+ if (error.set) {
+ return serialize_response(response_id, error.msg, NIL, sbuffer);
}
- if (req->via.array.ptr[3].type != MSGPACK_OBJECT_ARRAY) {
- msgpack_rpc_error("Paremeters must be an array", res);
- return;
- }
-
- // dispatch the message
- msgpack_rpc_dispatch(id, req, res);
+ return serialize_response(response_id, NULL, rv, sbuffer);
}
/// Try to unpack a msgpack document from the data in the unpacker buffer. This
@@ -134,19 +110,19 @@ void msgpack_rpc_error(char *msg, msgpack_packer *res)
}
/// Serializes a msgpack-rpc request or notification(id == 0)
-WBuffer *serialize_request(uint64_t id,
+WBuffer *serialize_request(uint64_t request_id,
String method,
Object arg,
msgpack_sbuffer *sbuffer)
- FUNC_ATTR_NONNULL_ALL
+ FUNC_ATTR_NONNULL_ARG(4)
{
msgpack_packer pac;
msgpack_packer_init(&pac, sbuffer, msgpack_sbuffer_write);
- msgpack_pack_array(&pac, id ? 4 : 3);
- msgpack_pack_int(&pac, id ? 0 : 2);
+ msgpack_pack_array(&pac, request_id ? 4 : 3);
+ msgpack_pack_int(&pac, request_id ? 0 : 2);
- if (id) {
- msgpack_pack_uint64(&pac, id);
+ if (request_id) {
+ msgpack_pack_uint64(&pac, request_id);
}
msgpack_pack_raw(&pac, method.size);
@@ -161,19 +137,20 @@ WBuffer *serialize_request(uint64_t id,
}
/// Serializes a msgpack-rpc response
-WBuffer *serialize_response(uint64_t id,
- String err,
+WBuffer *serialize_response(uint64_t response_id,
+ char *err_msg,
Object arg,
msgpack_sbuffer *sbuffer)
- FUNC_ATTR_NONNULL_ALL
+ FUNC_ATTR_NONNULL_ARG(4)
{
msgpack_packer pac;
msgpack_packer_init(&pac, sbuffer, msgpack_sbuffer_write);
msgpack_pack_array(&pac, 4);
msgpack_pack_int(&pac, 1);
- msgpack_pack_uint64(&pac, id);
+ msgpack_pack_uint64(&pac, response_id);
- if (err.size) {
+ if (err_msg) {
+ String err = {.size = strlen(err_msg), .data = err_msg};
// error message
msgpack_pack_raw(&pac, err.size);
msgpack_pack_raw_body(&pac, err.data, err.size);
@@ -194,3 +171,66 @@ WBuffer *serialize_response(uint64_t id,
return rv;
}
+WBuffer *serialize_metadata(uint64_t id,
+ uint64_t channel_id,
+ msgpack_sbuffer *sbuffer)
+ FUNC_ATTR_NONNULL_ALL
+{
+ msgpack_packer pac;
+ msgpack_packer_init(&pac, sbuffer, msgpack_sbuffer_write);
+ msgpack_pack_array(&pac, 4);
+ msgpack_pack_int(&pac, 1);
+ msgpack_pack_uint64(&pac, id);
+ // Nil error
+ msgpack_pack_nil(&pac);
+ // The result is the [channel_id, metadata] array
+ msgpack_pack_array(&pac, 2);
+ msgpack_pack_uint64(&pac, channel_id);
+ msgpack_pack_raw(&pac, msgpack_metadata_size);
+ msgpack_pack_raw_body(&pac, msgpack_metadata, msgpack_metadata_size);
+ WBuffer *rv = wstream_new_buffer(xmemdup(sbuffer->data, sbuffer->size),
+ sbuffer->size,
+ free);
+ msgpack_sbuffer_clear(sbuffer);
+ return rv;
+}
+
+static char *msgpack_rpc_validate(uint64_t *response_id, msgpack_object *req)
+{
+ // response id not known yet
+
+ *response_id = 0;
+ // Validate the basic structure of the msgpack-rpc payload
+ if (req->type != MSGPACK_OBJECT_ARRAY) {
+ return "Request is not an array";
+ }
+
+ if (req->via.array.size != 4) {
+ return "Request array size should be 4";
+ }
+
+ if (req->via.array.ptr[1].type != MSGPACK_OBJECT_POSITIVE_INTEGER) {
+ return "Id must be a positive integer";
+ }
+
+ // Set the response id, which is the same as the request
+ *response_id = req->via.array.ptr[1].via.u64;
+
+ if (req->via.array.ptr[0].type != MSGPACK_OBJECT_POSITIVE_INTEGER) {
+ return "Message type must be an integer";
+ }
+
+ if (req->via.array.ptr[0].via.u64 != 0) {
+ return "Message type must be 0";
+ }
+
+ if (req->via.array.ptr[2].type != MSGPACK_OBJECT_POSITIVE_INTEGER) {
+ return "Method id must be a positive integer";
+ }
+
+ if (req->via.array.ptr[3].type != MSGPACK_OBJECT_ARRAY) {
+ return "Paremeters must be an array";
+ }
+
+ return NULL;
+}
diff --git a/src/nvim/os/msgpack_rpc.h b/src/nvim/os/msgpack_rpc.h
index cbb487b44a..b8b947c0ec 100644
--- a/src/nvim/os/msgpack_rpc.h
+++ b/src/nvim/os/msgpack_rpc.h
@@ -22,12 +22,15 @@ typedef enum {
/// The implementation is generated at compile time with metadata extracted
/// from the api/*.h headers,
///
-/// @param id The channel id
+/// @param channel_id The channel id
+/// @param method_id The method id
/// @param req The parsed request object
-/// @param res A packer that contains the response
-void msgpack_rpc_dispatch(uint64_t id,
- msgpack_object *req,
- msgpack_packer *res)
+/// @param err Pointer to error structure
+/// @return Some object
+Object msgpack_rpc_dispatch(uint64_t channel_id,
+ uint64_t method_id,
+ msgpack_object *req,
+ Error *err)
FUNC_ATTR_NONNULL_ARG(2) FUNC_ATTR_NONNULL_ARG(3);
#ifdef INCLUDE_GENERATED_DECLARATIONS
diff --git a/src/nvim/os/msgpack_rpc_helpers.c b/src/nvim/os/msgpack_rpc_helpers.c
index 3af6794169..e2c277abe4 100644
--- a/src/nvim/os/msgpack_rpc_helpers.c
+++ b/src/nvim/os/msgpack_rpc_helpers.c
@@ -231,12 +231,41 @@ void msgpack_rpc_from_object(Object result, msgpack_packer *res)
msgpack_rpc_from_array(result.data.array, res);
break;
+ case kObjectTypePosition:
+ msgpack_rpc_from_position(result.data.position, res);
+ break;
+
+ case kObjectTypeBuffer:
+ msgpack_rpc_from_buffer(result.data.buffer, res);
+ break;
+
+ case kObjectTypeWindow:
+ msgpack_rpc_from_window(result.data.window, res);
+ break;
+
+ case kObjectTypeTabpage:
+ msgpack_rpc_from_tabpage(result.data.tabpage, res);
+ break;
+
+ case kObjectTypeStringArray:
+ msgpack_rpc_from_stringarray(result.data.stringarray, res);
+ break;
+
+ case kObjectTypeBufferArray:
+ msgpack_rpc_from_bufferarray(result.data.bufferarray, res);
+ break;
+
+ case kObjectTypeWindowArray:
+ msgpack_rpc_from_windowarray(result.data.windowarray, res);
+ break;
+
+ case kObjectTypeTabpageArray:
+ msgpack_rpc_from_tabpagearray(result.data.tabpagearray, res);
+ break;
+
case kObjectTypeDictionary:
msgpack_rpc_from_dictionary(result.data.dictionary, res);
break;
-
- default:
- abort();
}
}
@@ -282,6 +311,10 @@ void msgpack_rpc_free_object(Object value)
case kObjectTypeBoolean:
case kObjectTypeInteger:
case kObjectTypeFloat:
+ case kObjectTypePosition:
+ case kObjectTypeBuffer:
+ case kObjectTypeWindow:
+ case kObjectTypeTabpage:
break;
case kObjectTypeString:
@@ -292,6 +325,22 @@ void msgpack_rpc_free_object(Object value)
msgpack_rpc_free_array(value.data.array);
break;
+ case kObjectTypeStringArray:
+ msgpack_rpc_free_stringarray(value.data.stringarray);
+ break;
+
+ case kObjectTypeBufferArray:
+ msgpack_rpc_free_bufferarray(value.data.bufferarray);
+ break;
+
+ case kObjectTypeWindowArray:
+ msgpack_rpc_free_windowarray(value.data.windowarray);
+ break;
+
+ case kObjectTypeTabpageArray:
+ msgpack_rpc_free_tabpagearray(value.data.tabpagearray);
+ break;
+
case kObjectTypeDictionary:
msgpack_rpc_free_dictionary(value.data.dictionary);
break;