From 5862176764c7a86d5fdd2685122810e14a3d5b02 Mon Sep 17 00:00:00 2001 From: Charlie Groves Date: Wed, 16 Feb 2022 17:11:50 -0500 Subject: feat(remote): add basic --remote support This is starting from @geekodour's work at https://github.com/neovim/neovim/pull/8326 --- src/nvim/api/vim.c | 2 +- src/nvim/main.c | 79 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ src/nvim/main.h | 2 ++ 3 files changed, 82 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/nvim/api/vim.c b/src/nvim/api/vim.c index ebf4f65c91..b82a7553cb 100644 --- a/src/nvim/api/vim.c +++ b/src/nvim/api/vim.c @@ -1997,7 +1997,7 @@ 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(select(1, ...))"); + String s = cstr_to_string("return vim._os_proc_children(select(...))"); Object o = nlua_exec(s, a, err); api_free_string(s); api_free_array(a); diff --git a/src/nvim/main.c b/src/nvim/main.c index a575aba50a..3a1ca2988a 100644 --- a/src/nvim/main.c +++ b/src/nvim/main.c @@ -268,6 +268,10 @@ int main(int argc, char **argv) } server_init(params.listen_addr); + if (params.remote) { + handle_remote_client(¶ms, params.remote, + params.server_addr, argc, argv); + } if (GARGCOUNT > 0) { fname = get_fname(¶ms, cwd); @@ -803,6 +807,67 @@ static void init_locale(void) } #endif +/// Handle remote subcommands +static void handle_remote_client(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 *error = NULL; + uint64_t rc_id = server_addr == NULL ? 0 : channel_connect(false, + server_addr, true, on_data, 50, &error); + + Boolean should_exit = true; + Boolean tabbed; + int files; + + 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)); + } + + Error err = ERROR_INIT; + Array a = ARRAY_DICT_INIT; + ADD(a, INTEGER_OBJ((int)rc_id)); + ADD(a, ARRAY_OBJ(args)); + String s = cstr_to_string("return vim._cs_remote(...)"); + Object o = executor_exec_lua_api(s, a, &err); + api_free_string(s); + api_free_array(a); + + if (o.type == kObjectTypeDictionary) { + rvobj.data.dictionary = o.data.dictionary; + } else if (!ERROR_SET(&err)) { + api_set_error(&err, kErrorTypeException, + "Function returned unexpected value"); + } + + for (size_t i = 0; i < rvobj.data.dictionary.size ; i++) { + if (strcmp(rvobj.data.dictionary.items[i].key.data, "tabbed") == 0) { + // should we check items[i].value.type here? + tabbed = rvobj.data.dictionary.items[i].value.data.boolean; + } else if (strcmp(rvobj.data.dictionary.items[i].key.data, "should_exit") == 0) { + should_exit = rvobj.data.dictionary.items[i].value.data.boolean; + } else if (strcmp(rvobj.data.dictionary.items[i].key.data, "files") == 0) { + files = (int)rvobj.data.dictionary.items[i].value.data.integer; + } + } + + if (should_exit) { + mch_exit(0); + } else { + if (tabbed) { + params->window_count = files; + 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) @@ -868,6 +933,8 @@ static void command_line_scan(mparm_T *parmp) // "--version" give version message // "--noplugin[s]" skip plugins // "--cmd " execute cmd before vimrc + // "--remote" execute commands remotey on a server + // "--server" name of vim server to send remote commands to if (STRICMP(argv[0] + argv_idx, "help") == 0) { usage(); os_exit(0); @@ -906,6 +973,11 @@ static void command_line_scan(mparm_T *parmp) argv_idx += 6; } else if (STRNICMP(argv[0] + argv_idx, "literal", 7) == 0) { // Do nothing: file args are always literal. #7679 + } else if (STRNICMP(argv[0] + argv_idx, "remote", 6) == 0) { + parmp->remote = parmp->argc - argc; + } else if (STRNICMP(argv[0] + argv_idx, "server", 6) == 0) { + want_argument = true; + argv_idx += 6; } else if (STRNICMP(argv[0] + argv_idx, "noplugin", 8) == 0) { p_lpl = false; } else if (STRNICMP(argv[0] + argv_idx, "cmd", 3) == 0) { @@ -1137,6 +1209,9 @@ static void command_line_scan(mparm_T *parmp) } else if (strequal(argv[-1], "--listen")) { // "--listen {address}" parmp->listen_addr = argv[0]; + } else if (strequal(argv[-1], "--server")) { + // "--server {address}" + parmp->server_addr = argv[0]; } // "--startuptime " already handled break; @@ -1291,6 +1366,8 @@ static void init_params(mparm_T *paramp, int argc, char **argv) paramp->use_debug_break_level = -1; paramp->window_count = -1; paramp->listen_addr = NULL; + paramp->server_addr = NULL; + paramp->remote = 0; } /// Initialize global startuptime file if "--startuptime" passed as an argument. @@ -2041,6 +2118,8 @@ static void usage(void) mch_msg(_(" --headless Don't start a user interface\n")); mch_msg(_(" --listen
Serve RPC API from this address\n")); mch_msg(_(" --noplugin Don't load plugins\n")); + mch_msg(_(" --remote[-subcommand] Execute commands remotely on a server\n")); + mch_msg(_(" --server
Specify RPC server to send commands to\n")); mch_msg(_(" --startuptime Write startup timing messages to \n")); mch_msg(_("\nSee \":help startup-options\" for all options.\n")); } diff --git a/src/nvim/main.h b/src/nvim/main.h index f73af5c288..e55bef6e33 100644 --- a/src/nvim/main.h +++ b/src/nvim/main.h @@ -39,6 +39,8 @@ typedef struct { int diff_mode; // start with 'diff' set char *listen_addr; // --listen {address} + int remote; // --remote-[subcmd] {file1} {file2} + char *server_addr; // --server {address} } mparm_T; #ifdef INCLUDE_GENERATED_DECLARATIONS -- cgit From 70d2ab158320e72542dc2a845858d6f97da86e00 Mon Sep 17 00:00:00 2001 From: Charlie Groves Date: Wed, 16 Feb 2022 17:19:41 -0500 Subject: fix(remote): make compile again --- src/nvim/main.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/nvim/main.c b/src/nvim/main.c index 3a1ca2988a..843ca5f855 100644 --- a/src/nvim/main.c +++ b/src/nvim/main.c @@ -836,7 +836,7 @@ static void handle_remote_client(mparm_T *params, int remote_args, ADD(a, INTEGER_OBJ((int)rc_id)); ADD(a, ARRAY_OBJ(args)); String s = cstr_to_string("return vim._cs_remote(...)"); - Object o = executor_exec_lua_api(s, a, &err); + Object o = nlua_exec(s, a, &err); api_free_string(s); api_free_array(a); @@ -859,7 +859,7 @@ static void handle_remote_client(mparm_T *params, int remote_args, } if (should_exit) { - mch_exit(0); + os_exit(0); } else { if (tabbed) { params->window_count = files; -- cgit From 039e94f491d2f8576cbef1aeacd5ea1f7bc0982a Mon Sep 17 00:00:00 2001 From: Charlie Groves Date: Thu, 24 Feb 2022 10:47:41 -0500 Subject: test(remote): add tests for --remote This also fixes a fair number of issues found in running the tests --- src/nvim/api/vim.c | 2 +- src/nvim/main.c | 23 ++++++++++++----------- 2 files changed, 13 insertions(+), 12 deletions(-) (limited to 'src') diff --git a/src/nvim/api/vim.c b/src/nvim/api/vim.c index b82a7553cb..b691dee2ef 100644 --- a/src/nvim/api/vim.c +++ b/src/nvim/api/vim.c @@ -1997,7 +1997,7 @@ 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(select(...))"); + String s = cstr_to_string("return vim._os_proc_children(...)"); Object o = nlua_exec(s, a, err); api_free_string(s); api_free_array(a); diff --git a/src/nvim/main.c b/src/nvim/main.c index 843ca5f855..a3588ac5df 100644 --- a/src/nvim/main.c +++ b/src/nvim/main.c @@ -821,7 +821,6 @@ static void handle_remote_client(mparm_T *params, int remote_args, Boolean should_exit = true; Boolean tabbed; - int files; int t_argc = remote_args; Array args = ARRAY_DICT_INIT; @@ -839,12 +838,17 @@ static void handle_remote_client(mparm_T *params, int remote_args, Object o = nlua_exec(s, a, &err); api_free_string(s); api_free_array(a); + if (ERROR_SET(&err)) { + mch_errmsg(err.msg); + mch_errmsg("\n"); + os_exit(2); + } if (o.type == kObjectTypeDictionary) { rvobj.data.dictionary = o.data.dictionary; - } else if (!ERROR_SET(&err)) { - api_set_error(&err, kErrorTypeException, - "Function returned unexpected value"); + } else { + mch_errmsg("vim._cs_remote returned unexpected value\n"); + os_exit(3); } for (size_t i = 0; i < rvobj.data.dictionary.size ; i++) { @@ -853,18 +857,15 @@ static void handle_remote_client(mparm_T *params, int remote_args, tabbed = rvobj.data.dictionary.items[i].value.data.boolean; } else if (strcmp(rvobj.data.dictionary.items[i].key.data, "should_exit") == 0) { should_exit = rvobj.data.dictionary.items[i].value.data.boolean; - } else if (strcmp(rvobj.data.dictionary.items[i].key.data, "files") == 0) { - files = (int)rvobj.data.dictionary.items[i].value.data.integer; } } if (should_exit) { os_exit(0); - } else { - if (tabbed) { - params->window_count = files; - params->window_layout = WIN_TABS; - } + } + if (tabbed) { + params->window_count = argc - remote_args - 1; + params->window_layout = WIN_TABS; } } -- cgit From 29c36322857b37263b07eb1301d71ccd8a2ae044 Mon Sep 17 00:00:00 2001 From: Charlie Groves Date: Thu, 3 Mar 2022 16:33:27 -0500 Subject: fix(remote): report on missing wait commands, typecheck lua results Clean up lint errors, too --- src/nvim/main.c | 28 +++++++++++++++++++++++----- 1 file changed, 23 insertions(+), 5 deletions(-) (limited to 'src') diff --git a/src/nvim/main.c b/src/nvim/main.c index a3588ac5df..eb60d51b9b 100644 --- a/src/nvim/main.c +++ b/src/nvim/main.c @@ -816,8 +816,10 @@ static void handle_remote_client(mparm_T *params, int remote_args, rvobj.type = kObjectTypeDictionary; CallbackReader on_data = CALLBACK_READER_INIT; const char *error = NULL; - uint64_t rc_id = server_addr == NULL ? 0 : channel_connect(false, - server_addr, true, on_data, 50, &error); + uint64_t rc_id = 0; + if (server_addr != NULL) { + rc_id = channel_connect(false, server_addr, true, on_data, 50, &error); + } Boolean should_exit = true; Boolean tabbed; @@ -848,17 +850,33 @@ static void handle_remote_client(mparm_T *params, int remote_args, rvobj.data.dictionary = o.data.dictionary; } else { mch_errmsg("vim._cs_remote returned unexpected value\n"); - os_exit(3); + os_exit(2); } for (size_t i = 0; i < rvobj.data.dictionary.size ; i++) { - if (strcmp(rvobj.data.dictionary.items[i].key.data, "tabbed") == 0) { - // should we check items[i].value.type here? + 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"); + 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; } 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; } } + api_free_object(o); if (should_exit) { os_exit(0); -- cgit From 2be938a2513b1dd604ce0069667b89a64441cb2a Mon Sep 17 00:00:00 2001 From: Charlie Groves Date: Thu, 10 Mar 2022 17:26:20 -0500 Subject: fix(remote): report connection error, missing return values --- src/nvim/main.c | 25 ++++++++++++++++++------- 1 file changed, 18 insertions(+), 7 deletions(-) (limited to 'src') diff --git a/src/nvim/main.c b/src/nvim/main.c index eb60d51b9b..f08ede7197 100644 --- a/src/nvim/main.c +++ b/src/nvim/main.c @@ -820,9 +820,13 @@ static void handle_remote_client(mparm_T *params, int remote_args, if (server_addr != NULL) { rc_id = channel_connect(false, server_addr, true, on_data, 50, &error); } - - Boolean should_exit = true; - Boolean tabbed; + if (error) { + mch_msg("Failed to connect to server "); + mch_msg(server_addr); + mch_msg("\nReason: "); + mch_msg(error); + mch_msg("Continuing with remote command in case we can execute locally\n"); + } int t_argc = remote_args; Array args = ARRAY_DICT_INIT; @@ -853,6 +857,9 @@ static void handle_remote_client(mparm_T *params, int remote_args, os_exit(2); } + 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) { @@ -867,21 +874,25 @@ static void handle_remote_client(mparm_T *params, int remote_args, mch_errmsg("vim._cs_remote returned an unexpected type for 'tabbed'\n"); os_exit(2); } - tabbed = rvobj.data.dictionary.items[i].value.data.boolean; + 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; + 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"); + os_exit(2); + } api_free_object(o); - if (should_exit) { + if (should_exit == kTrue) { os_exit(0); } - if (tabbed) { + if (tabbed == kTrue) { params->window_count = argc - remote_args - 1; params->window_layout = WIN_TABS; } -- cgit From 1dbf8675c71dc500ae7502085161cd56e311ccf6 Mon Sep 17 00:00:00 2001 From: Charlie Groves Date: Fri, 11 Mar 2022 11:16:34 -0500 Subject: fix(remote): respect silent in error reporting --- src/nvim/main.c | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) (limited to 'src') diff --git a/src/nvim/main.c b/src/nvim/main.c index f08ede7197..33b13f4dc6 100644 --- a/src/nvim/main.c +++ b/src/nvim/main.c @@ -815,17 +815,10 @@ static void handle_remote_client(mparm_T *params, int remote_args, rvobj.data.dictionary = (Dictionary)ARRAY_DICT_INIT; rvobj.type = kObjectTypeDictionary; CallbackReader on_data = CALLBACK_READER_INIT; - const char *error = NULL; + 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, &error); - } - if (error) { - mch_msg("Failed to connect to server "); - mch_msg(server_addr); - mch_msg("\nReason: "); - mch_msg(error); - mch_msg("Continuing with remote command in case we can execute locally\n"); + rc_id = channel_connect(false, server_addr, true, on_data, 50, &connect_error); } int t_argc = remote_args; @@ -839,6 +832,8 @@ static void handle_remote_client(mparm_T *params, int remote_args, 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 = cstr_to_string("return vim._cs_remote(...)"); Object o = nlua_exec(s, a, &err); -- cgit From 1201145b6893703fb351f51d9f2c742bd6946403 Mon Sep 17 00:00:00 2001 From: Charlie Groves Date: Fri, 11 Mar 2022 13:05:40 -0500 Subject: fix(remote): use STATIC_CSTR_AS_STRING --- src/nvim/main.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'src') diff --git a/src/nvim/main.c b/src/nvim/main.c index 33b13f4dc6..230be9d9b9 100644 --- a/src/nvim/main.c +++ b/src/nvim/main.c @@ -835,9 +835,8 @@ static void handle_remote_client(mparm_T *params, int remote_args, ADD(a, CSTR_TO_OBJ(server_addr)); ADD(a, CSTR_TO_OBJ(connect_error)); ADD(a, ARRAY_OBJ(args)); - String s = cstr_to_string("return vim._cs_remote(...)"); + String s = STATIC_CSTR_AS_STRING("return vim._cs_remote(...)"); Object o = nlua_exec(s, a, &err); - api_free_string(s); api_free_array(a); if (ERROR_SET(&err)) { mch_errmsg(err.msg); -- cgit