aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/nvim/api/private/dispatch.c8
-rw-r--r--src/nvim/api/vim.c3
-rw-r--r--src/nvim/globals.h3
-rw-r--r--src/nvim/main.c168
-rw-r--r--src/nvim/msgpack_rpc/channel.c5
-rw-r--r--src/nvim/ui_client.c70
-rw-r--r--src/nvim/ui_client.h9
7 files changed, 192 insertions, 74 deletions
diff --git a/src/nvim/api/private/dispatch.c b/src/nvim/api/private/dispatch.c
index f670f06357..ba2e560d63 100644
--- a/src/nvim/api/private/dispatch.c
+++ b/src/nvim/api/private/dispatch.c
@@ -30,6 +30,7 @@
#include "nvim/api/vimscript.h"
#include "nvim/api/win_config.h"
#include "nvim/api/window.h"
+#include "nvim/ui_client.h"
static Map(String, MsgpackRpcRequestHandler) methods = MAP_INIT;
@@ -38,6 +39,13 @@ static void msgpack_rpc_add_method_handler(String method, MsgpackRpcRequestHandl
map_put(String, MsgpackRpcRequestHandler)(&methods, method, handler);
}
+void msgpack_rpc_add_redraw(void)
+{
+ msgpack_rpc_add_method_handler(STATIC_CSTR_AS_STRING("redraw"),
+ (MsgpackRpcRequestHandler) { .fn = ui_client_handle_redraw,
+ .fast = true });
+}
+
/// @param name API method name
/// @param name_len name size (includes terminating NUL)
MsgpackRpcRequestHandler msgpack_rpc_get_handler_for(const char *name, size_t name_len,
diff --git a/src/nvim/api/vim.c b/src/nvim/api/vim.c
index b691dee2ef..a942c94f46 100644
--- a/src/nvim/api/vim.c
+++ b/src/nvim/api/vim.c
@@ -1997,9 +1997,8 @@ Array nvim_get_proc_children(Integer pid, Error *err)
DLOG("fallback to vim._os_proc_children()");
Array a = ARRAY_DICT_INIT;
ADD(a, INTEGER_OBJ(pid));
- String s = cstr_to_string("return vim._os_proc_children(...)");
+ String s = STATIC_CSTR_AS_STRING("return vim._os_proc_children(...)");
Object o = nlua_exec(s, a, err);
- api_free_string(s);
api_free_array(a);
if (o.type == kObjectTypeArray) {
rvobj = o.data.array;
diff --git a/src/nvim/globals.h b/src/nvim/globals.h
index 35ad57906b..b64ed7c758 100644
--- a/src/nvim/globals.h
+++ b/src/nvim/globals.h
@@ -342,6 +342,9 @@ EXTERN sctx_T current_sctx INIT(= { 0 COMMA 0 COMMA 0 });
// ID of the current channel making a client API call
EXTERN uint64_t current_channel_id INIT(= 0);
+// ID of the client channel. Used by ui client
+EXTERN uint64_t ui_client_channel_id INIT(= 0);
+
EXTERN bool did_source_packages INIT(= false);
// Scope information for the code that indirectly triggered the current
diff --git a/src/nvim/main.c b/src/nvim/main.c
index 230be9d9b9..95ef306745 100644
--- a/src/nvim/main.c
+++ b/src/nvim/main.c
@@ -29,6 +29,7 @@
#include "nvim/if_cscope.h"
#include "nvim/lua/executor.h"
#include "nvim/main.h"
+#include "nvim/ui_client.h"
#include "nvim/vim.h"
#ifdef HAVE_LOCALE_H
# include <locale.h>
@@ -269,8 +270,7 @@ int main(int argc, char **argv)
server_init(params.listen_addr);
if (params.remote) {
- handle_remote_client(&params, params.remote,
- params.server_addr, argc, argv);
+ remote_request(&params, params.remote, params.server_addr, argc, argv);
}
if (GARGCOUNT > 0) {
@@ -807,91 +807,115 @@ static void init_locale(void)
}
#endif
+
+static uint64_t server_connect(char *server_addr, const char **errmsg)
+{
+ if (server_addr == NULL) {
+ *errmsg = "no address specified";
+ return 0;
+ }
+ CallbackReader on_data = CALLBACK_READER_INIT;
+ const char *error = NULL;
+ bool is_tcp = strrchr(server_addr, ':') ? true : false;
+ // connected to channel
+ uint64_t chan = channel_connect(is_tcp, server_addr, true, on_data, 50, &error);
+ if (error) {
+ *errmsg = error;
+ return 0;
+ }
+ return chan;
+}
+
/// Handle remote subcommands
-static void handle_remote_client(mparm_T *params, int remote_args,
- char *server_addr, int argc, char **argv)
+static void remote_request(mparm_T *params, int remote_args,
+ char *server_addr, int argc, char **argv)
{
- Object rvobj = OBJECT_INIT;
- rvobj.data.dictionary = (Dictionary)ARRAY_DICT_INIT;
- rvobj.type = kObjectTypeDictionary;
- CallbackReader on_data = CALLBACK_READER_INIT;
- const char *connect_error = NULL;
- uint64_t rc_id = 0;
- if (server_addr != NULL) {
- rc_id = channel_connect(false, server_addr, true, on_data, 50, &connect_error);
+ const char *connect_error = NULL;
+ uint64_t chan = server_connect(server_addr, &connect_error);
+ Object rvobj = OBJECT_INIT;
+
+ if (strequal(argv[remote_args], "--remote-ui-test")) {
+ if (!chan) {
+ emsg(connect_error);
+ exit(1);
}
- int t_argc = remote_args;
- Array args = ARRAY_DICT_INIT;
- String arg_s;
- for (; t_argc < argc; t_argc++) {
- arg_s = cstr_to_string(argv[t_argc]);
- ADD(args, STRING_OBJ(arg_s));
- }
+ ui_client_init(chan);
+ ui_client_execute(chan);
+ abort(); // unreachable
+ }
- Error err = ERROR_INIT;
- Array a = ARRAY_DICT_INIT;
- ADD(a, INTEGER_OBJ((int)rc_id));
- ADD(a, CSTR_TO_OBJ(server_addr));
- ADD(a, CSTR_TO_OBJ(connect_error));
- ADD(a, ARRAY_OBJ(args));
- String s = STATIC_CSTR_AS_STRING("return vim._cs_remote(...)");
- Object o = nlua_exec(s, a, &err);
- api_free_array(a);
- if (ERROR_SET(&err)) {
- mch_errmsg(err.msg);
- mch_errmsg("\n");
- os_exit(2);
- }
+ Array args = ARRAY_DICT_INIT;
+ String arg_s;
+ for (int t_argc = remote_args; t_argc < argc; t_argc++) {
+ arg_s = cstr_to_string(argv[t_argc]);
+ ADD(args, STRING_OBJ(arg_s));
+ }
- if (o.type == kObjectTypeDictionary) {
- rvobj.data.dictionary = o.data.dictionary;
- } else {
- mch_errmsg("vim._cs_remote returned unexpected value\n");
- os_exit(2);
- }
+ Error err = ERROR_INIT;
+ Array a = ARRAY_DICT_INIT;
+ ADD(a, INTEGER_OBJ((int)chan));
+ ADD(a, CSTR_TO_OBJ(server_addr));
+ ADD(a, CSTR_TO_OBJ(connect_error));
+ ADD(a, ARRAY_OBJ(args));
+ String s = STATIC_CSTR_AS_STRING("return vim._cs_remote(...)");
+ Object o = nlua_exec(s, a, &err);
+ api_free_array(a);
+ if (ERROR_SET(&err)) {
+ mch_errmsg(err.msg);
+ mch_errmsg("\n");
+ os_exit(2);
+ }
- TriState should_exit = kNone;
- TriState tabbed = kNone;
+ if (o.type == kObjectTypeDictionary) {
+ rvobj.data.dictionary = o.data.dictionary;
+ } else {
+ mch_errmsg("vim._cs_remote returned unexpected value\n");
+ os_exit(2);
+ }
- for (size_t i = 0; i < rvobj.data.dictionary.size ; i++) {
- if (strcmp(rvobj.data.dictionary.items[i].key.data, "errmsg") == 0) {
- if (rvobj.data.dictionary.items[i].value.type != kObjectTypeString) {
- mch_errmsg("vim._cs_remote returned an unexpected type for 'errmsg'\n");
- os_exit(2);
- }
- mch_errmsg(rvobj.data.dictionary.items[i].value.data.string.data);
- mch_errmsg("\n");
+ TriState should_exit = kNone;
+ TriState tabbed = kNone;
+
+ for (size_t i = 0; i < rvobj.data.dictionary.size ; i++) {
+ if (strcmp(rvobj.data.dictionary.items[i].key.data, "errmsg") == 0) {
+ if (rvobj.data.dictionary.items[i].value.type != kObjectTypeString) {
+ mch_errmsg("vim._cs_remote returned an unexpected type for 'errmsg'\n");
os_exit(2);
- } else if (strcmp(rvobj.data.dictionary.items[i].key.data, "tabbed") == 0) {
- if (rvobj.data.dictionary.items[i].value.type != kObjectTypeBoolean) {
- mch_errmsg("vim._cs_remote returned an unexpected type for 'tabbed'\n");
- os_exit(2);
- }
- tabbed = rvobj.data.dictionary.items[i].value.data.boolean ? kTrue : kFalse;
- } else if (strcmp(rvobj.data.dictionary.items[i].key.data, "should_exit") == 0) {
- if (rvobj.data.dictionary.items[i].value.type != kObjectTypeBoolean) {
- mch_errmsg("vim._cs_remote returned an unexpected type for 'should_exit'\n");
- os_exit(2);
- }
- should_exit = rvobj.data.dictionary.items[i].value.data.boolean ? kTrue : kFalse;
}
- }
- if (should_exit == kNone || tabbed == kNone) {
- mch_errmsg("vim._cs_remote didn't return a value for should_exit or tabbed, bailing\n");
+ mch_errmsg(rvobj.data.dictionary.items[i].value.data.string.data);
+ mch_errmsg("\n");
os_exit(2);
+ } else if (strcmp(rvobj.data.dictionary.items[i].key.data, "tabbed") == 0) {
+ if (rvobj.data.dictionary.items[i].value.type != kObjectTypeBoolean) {
+ mch_errmsg("vim._cs_remote returned an unexpected type for 'tabbed'\n");
+ os_exit(2);
+ }
+ tabbed = rvobj.data.dictionary.items[i].value.data.boolean ? kTrue : kFalse;
+ } else if (strcmp(rvobj.data.dictionary.items[i].key.data, "should_exit") == 0) {
+ if (rvobj.data.dictionary.items[i].value.type != kObjectTypeBoolean) {
+ mch_errmsg("vim._cs_remote returned an unexpected type for 'should_exit'\n");
+ os_exit(2);
+ }
+ should_exit = rvobj.data.dictionary.items[i].value.data.boolean ? kTrue : kFalse;
}
- api_free_object(o);
+ }
+ if (should_exit == kNone || tabbed == kNone) {
+ mch_errmsg("vim._cs_remote didn't return a value for should_exit or tabbed, bailing\n");
+ os_exit(2);
+ }
+ api_free_object(o);
- if (should_exit == kTrue) {
- os_exit(0);
- }
- if (tabbed == kTrue) {
- params->window_count = argc - remote_args - 1;
- params->window_layout = WIN_TABS;
- }
+ if (should_exit == kTrue) {
+ os_exit(0);
+ }
+ if (tabbed == kTrue) {
+ params->window_count = argc - remote_args - 1;
+ params->window_layout = WIN_TABS;
+ }
}
+
/// Decides whether text (as opposed to commands) will be read from stdin.
/// @see EDIT_STDIN
static bool edit_stdin(bool explicit, mparm_T *parmp)
diff --git a/src/nvim/msgpack_rpc/channel.c b/src/nvim/msgpack_rpc/channel.c
index 299651ee97..f4e836fa81 100644
--- a/src/nvim/msgpack_rpc/channel.c
+++ b/src/nvim/msgpack_rpc/channel.c
@@ -547,6 +547,11 @@ void rpc_close(Channel *channel)
channel->rpc.closed = true;
channel_decref(channel);
+ if (channel->id == ui_client_channel_id) {
+ // TODO(bfredl): handle this in ui_client, where os_exit() is safe
+ exit(0);
+ }
+
if (channel->streamtype == kChannelStreamStdio) {
multiqueue_put(main_loop.fast_events, exit_event, 0);
}
diff --git a/src/nvim/ui_client.c b/src/nvim/ui_client.c
new file mode 100644
index 0000000000..4a435aac4d
--- /dev/null
+++ b/src/nvim/ui_client.c
@@ -0,0 +1,70 @@
+// This is an open source non-commercial project. Dear PVS-Studio, please check
+// it. PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com
+
+#include <stdbool.h>
+#include <stdint.h>
+#include <assert.h>
+
+#include "nvim/vim.h"
+#include "nvim/ui_client.h"
+#include "nvim/api/private/helpers.h"
+#include "nvim/msgpack_rpc/channel.h"
+#include "nvim/api/private/dispatch.h"
+#include "nvim/ui.h"
+
+void ui_client_init(uint64_t chan)
+{
+ Array args = ARRAY_DICT_INIT;
+ int width = 80;
+ int height = 25;
+ Dictionary opts = ARRAY_DICT_INIT;
+
+ PUT(opts, "rgb", BOOLEAN_OBJ(true));
+ PUT(opts, "ext_linegrid", BOOLEAN_OBJ(true));
+ PUT(opts, "ext_termcolors", BOOLEAN_OBJ(true));
+
+ // TODO(bfredl): use the size of the client UI
+ ADD(args, INTEGER_OBJ((int)width));
+ ADD(args, INTEGER_OBJ((int)height));
+ ADD(args, DICTIONARY_OBJ(opts));
+
+ rpc_send_event(chan, "nvim_ui_attach", args);
+ msgpack_rpc_add_redraw(); // GAME!
+ ui_client_channel_id = chan;
+}
+
+/// Handler for "redraw" events sent by the NVIM server
+///
+/// This is just a stub. The mentioned functionality will be implemented.
+///
+/// This function will be called by handle_request (in msgpack_rpc/channle.c)
+/// The individual ui_events sent by the server are individually handled
+/// by their respective handlers defined in ui_events_redraw.generated.h
+///
+/// @note The "flush" event is called only once and only after handling all
+/// the other events
+/// @param channel_id: The id of the rpc channel
+/// @param uidata: The dense array containing the ui_events sent by the server
+/// @param[out] err Error details, if any
+Object ui_client_handle_redraw(uint64_t channel_id, Array args, Error *error)
+{
+ for (size_t i = 0; i < args.size; i++) {
+ Array call = args.items[i].data.array;
+ char *method_name = call.items[0].data.string.data;
+
+ fprintf(stderr, "%s: %zu\n", method_name, call.size-1);
+ }
+ return NIL;
+}
+
+/// run the main thread in ui client mode
+///
+/// This is just a stub. the full version will handle input, resizing, etc
+void ui_client_execute(uint64_t chan)
+{
+ while (true) {
+ loop_poll_events(&main_loop, -1);
+ }
+
+ getout(0);
+}
diff --git a/src/nvim/ui_client.h b/src/nvim/ui_client.h
new file mode 100644
index 0000000000..067f78d5c5
--- /dev/null
+++ b/src/nvim/ui_client.h
@@ -0,0 +1,9 @@
+#ifndef NVIM_UI_CLIENT_H
+#define NVIM_UI_CLIENT_H
+
+#include "nvim/api/private/defs.h"
+
+#ifdef INCLUDE_GENERATED_DECLARATIONS
+#include "ui_client.h.generated.h"
+#endif
+#endif // NVIM_UI_CLIENT_H