aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorbfredl <bjorn.linse@gmail.com>2023-08-26 13:39:31 +0200
committerGitHub <noreply@github.com>2023-08-26 13:39:31 +0200
commit965ed579fe3ab9ded0e5ab20b54a5a8607188dac (patch)
treef399c58853201cbe319a61a076862a00184548ba
parent362df0f7938a0e6147ecf886655a0689430d426d (diff)
parentb641fc38749a2a52e40fa7eca6c7c41b1d9b031c (diff)
downloadrneovim-965ed579fe3ab9ded0e5ab20b54a5a8607188dac.tar.gz
rneovim-965ed579fe3ab9ded0e5ab20b54a5a8607188dac.tar.bz2
rneovim-965ed579fe3ab9ded0e5ab20b54a5a8607188dac.zip
Merge pull request #24399 from lambdalisue/fix-messagepack-rpc
feat(msgpack_rpc): add a new `msgpack-rpc` client type to fix behavior with MessagePack-RPC compliant clients
-rw-r--r--runtime/doc/api.txt6
-rw-r--r--runtime/doc/news.txt3
-rw-r--r--runtime/lua/vim/_meta/api.lua6
-rw-r--r--src/nvim/api/vim.c5
-rw-r--r--src/nvim/eval/funcs.c2
-rw-r--r--src/nvim/msgpack_rpc/channel.c47
-rw-r--r--src/nvim/msgpack_rpc/channel_defs.h11
7 files changed, 69 insertions, 11 deletions
diff --git a/runtime/doc/api.txt b/runtime/doc/api.txt
index 793fcd703b..343c63f4b0 100644
--- a/runtime/doc/api.txt
+++ b/runtime/doc/api.txt
@@ -1336,7 +1336,11 @@ nvim_set_client_info({name}, {version}, {type}, {methods}, {attributes})
• {type} Must be one of the following values. Client libraries
should default to "remote" unless overridden by the
user.
- • "remote" remote client connected to Nvim.
+ • "remote" remote client connected "Nvim flavored"
+ MessagePack-RPC (responses must be in reverse order of
+ requests). |msgpack-rpc|
+ • "msgpack-rpc" remote client connected to Nvim via
+ fully MessagePack-RPC compliant protocol.
• "ui" gui frontend
• "embedder" application using Nvim as a component (for
example, IDE/editor implementing a vim mode).
diff --git a/runtime/doc/news.txt b/runtime/doc/news.txt
index 637a33b555..56bdd07171 100644
--- a/runtime/doc/news.txt
+++ b/runtime/doc/news.txt
@@ -152,6 +152,9 @@ The following new APIs and features were added.
• Functions that take a severity as an optional parameter (e.g.
|vim.diagnostic.get()|) now also accept a list of severities |vim.diagnostic.severity|
+• New RPC client type `msgpack-rpc` is added for `nvim_set_client_info` to
+ support fully MessagePack-RPC compliant clients.
+
==============================================================================
CHANGED FEATURES *news-changed*
diff --git a/runtime/lua/vim/_meta/api.lua b/runtime/lua/vim/_meta/api.lua
index c0e4e35e7d..fdf5016b68 100644
--- a/runtime/lua/vim/_meta/api.lua
+++ b/runtime/lua/vim/_meta/api.lua
@@ -1679,7 +1679,11 @@ function vim.api.nvim_select_popupmenu_item(item, insert, finish, opts) end
--- @param type string Must be one of the following values. Client libraries
--- should default to "remote" unless overridden by the
--- user.
---- • "remote" remote client connected to Nvim.
+--- • "remote" remote client connected "Nvim flavored"
+--- MessagePack-RPC (responses must be in reverse order of
+--- requests). `msgpack-rpc`
+--- • "msgpack-rpc" remote client connected to Nvim via
+--- fully MessagePack-RPC compliant protocol.
--- • "ui" gui frontend
--- • "embedder" application using Nvim as a component (for
--- example, IDE/editor implementing a vim mode).
diff --git a/src/nvim/api/vim.c b/src/nvim/api/vim.c
index b278a21d8e..411d63b921 100644
--- a/src/nvim/api/vim.c
+++ b/src/nvim/api/vim.c
@@ -1500,7 +1500,10 @@ Array nvim_get_api_info(uint64_t channel_id, Arena *arena)
/// - "commit" hash or similar identifier of commit
/// @param type Must be one of the following values. Client libraries should
/// default to "remote" unless overridden by the user.
-/// - "remote" remote client connected to Nvim.
+/// - "remote" remote client connected "Nvim flavored" MessagePack-RPC (responses
+/// must be in reverse order of requests). |msgpack-rpc|
+/// - "msgpack-rpc" remote client connected to Nvim via fully MessagePack-RPC
+/// compliant protocol.
/// - "ui" gui frontend
/// - "embedder" application using Nvim as a component (for example,
/// IDE/editor implementing a vim mode).
diff --git a/src/nvim/eval/funcs.c b/src/nvim/eval/funcs.c
index cf8525e66a..1ed0994222 100644
--- a/src/nvim/eval/funcs.c
+++ b/src/nvim/eval/funcs.c
@@ -6730,7 +6730,7 @@ static void f_rpcrequest(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
const char *name = NULL;
Channel *chan = find_channel(chan_id);
if (chan) {
- name = rpc_client_name(chan);
+ name = get_client_info(chan, "name");
}
msg_ext_set_kind("rpc_error");
if (name) {
diff --git a/src/nvim/msgpack_rpc/channel.c b/src/nvim/msgpack_rpc/channel.c
index 1772b0497b..095e392092 100644
--- a/src/nvim/msgpack_rpc/channel.c
+++ b/src/nvim/msgpack_rpc/channel.c
@@ -306,6 +306,17 @@ end:
channel_decref(channel);
}
+static ChannelCallFrame *find_call_frame(RpcState *rpc, uint32_t request_id)
+{
+ for (size_t i = 0; i < kv_size(rpc->call_stack); i++) {
+ ChannelCallFrame *frame = kv_Z(rpc->call_stack, i);
+ if (frame->request_id == request_id) {
+ return frame;
+ }
+ }
+ return NULL;
+}
+
static void parse_msgpack(Channel *channel)
{
Unpacker *p = channel->rpc.unpacker;
@@ -321,13 +332,15 @@ static void parse_msgpack(Channel *channel)
}
arena_mem_free(arena_finish(&p->arena));
} else if (p->type == kMessageTypeResponse) {
- ChannelCallFrame *frame = kv_last(channel->rpc.call_stack);
- if (p->request_id != frame->request_id) {
+ ChannelCallFrame *frame = channel->rpc.client_type == kClientTypeMsgpackRpc
+ ? find_call_frame(&channel->rpc, p->request_id)
+ : kv_last(channel->rpc.call_stack);
+ if (frame == NULL || p->request_id != frame->request_id) {
char buf[256];
snprintf(buf, sizeof(buf),
- "ch %" PRIu64 " returned a response with an unknown request "
- "id. Ensure the client is properly synchronized",
- channel->id);
+ "ch %" PRIu64 " (type=%" PRIu32 ") returned a response with an unknown request "
+ "id %" PRIu32 ". Ensure the client is properly synchronized",
+ channel->id, (unsigned)channel->rpc.client_type, p->request_id);
chan_close_with_error(channel, buf, LOGLVL_ERR);
}
frame->returned = true;
@@ -691,6 +704,25 @@ void rpc_set_client_info(uint64_t id, Dictionary info)
api_free_dictionary(chan->rpc.info);
chan->rpc.info = info;
+
+ // Parse "type" on "info" and set "client_type"
+ const char *type = get_client_info(chan, "type");
+ if (type == NULL || strequal(type, "remote")) {
+ chan->rpc.client_type = kClientTypeRemote;
+ } else if (strequal(type, "msgpack-rpc")) {
+ chan->rpc.client_type = kClientTypeMsgpackRpc;
+ } else if (strequal(type, "ui")) {
+ chan->rpc.client_type = kClientTypeUi;
+ } else if (strequal(type, "embedder")) {
+ chan->rpc.client_type = kClientTypeEmbedder;
+ } else if (strequal(type, "host")) {
+ chan->rpc.client_type = kClientTypeHost;
+ } else if (strequal(type, "plugin")) {
+ chan->rpc.client_type = kClientTypePlugin;
+ } else {
+ chan->rpc.client_type = kClientTypeUnknown;
+ }
+
channel_info_changed(chan, false);
}
@@ -699,14 +731,15 @@ Dictionary rpc_client_info(Channel *chan)
return copy_dictionary(chan->rpc.info, NULL);
}
-const char *rpc_client_name(Channel *chan)
+const char *get_client_info(Channel *chan, const char *key)
+ FUNC_ATTR_NONNULL_ALL
{
if (!chan->is_rpc) {
return NULL;
}
Dictionary info = chan->rpc.info;
for (size_t i = 0; i < info.size; i++) {
- if (strequal("name", info.items[i].key.data)
+ if (strequal(key, info.items[i].key.data)
&& info.items[i].value.type == kObjectTypeString) {
return info.items[i].value.data.string.data;
}
diff --git a/src/nvim/msgpack_rpc/channel_defs.h b/src/nvim/msgpack_rpc/channel_defs.h
index 1b5f0bb298..79aa8c1b13 100644
--- a/src/nvim/msgpack_rpc/channel_defs.h
+++ b/src/nvim/msgpack_rpc/channel_defs.h
@@ -14,6 +14,16 @@
typedef struct Channel Channel;
typedef struct Unpacker Unpacker;
+typedef enum {
+ kClientTypeUnknown = -1,
+ kClientTypeRemote = 0,
+ kClientTypeMsgpackRpc = 5,
+ kClientTypeUi = 1,
+ kClientTypeEmbedder = 2,
+ kClientTypeHost = 3,
+ kClientTypePlugin = 4,
+} ClientType;
+
typedef struct {
uint32_t request_id;
bool returned, errored;
@@ -37,6 +47,7 @@ typedef struct {
uint32_t next_request_id;
kvec_t(ChannelCallFrame *) call_stack;
Dictionary info;
+ ClientType client_type;
} RpcState;
#endif // NVIM_MSGPACK_RPC_CHANNEL_DEFS_H