mirror of
https://github.com/neovim/neovim.git
synced 2025-10-20 00:31:49 +00:00
feat: make :restart work for remote UI (#34354)
This commit is contained in:
@@ -7,12 +7,9 @@
|
||||
|
||||
#include "nvim/api/keysets_defs.h"
|
||||
#include "nvim/api/private/defs.h"
|
||||
#include "nvim/api/private/dispatch.h"
|
||||
#include "nvim/api/private/helpers.h"
|
||||
#include "nvim/channel.h"
|
||||
#include "nvim/channel_defs.h"
|
||||
#include "nvim/eval.h"
|
||||
#include "nvim/eval/typval.h"
|
||||
#include "nvim/eval/typval_defs.h"
|
||||
#include "nvim/event/multiqueue.h"
|
||||
#include "nvim/globals.h"
|
||||
@@ -25,7 +22,6 @@
|
||||
#include "nvim/msgpack_rpc/channel.h"
|
||||
#include "nvim/msgpack_rpc/channel_defs.h"
|
||||
#include "nvim/os/os.h"
|
||||
#include "nvim/os/os_defs.h"
|
||||
#include "nvim/profile.h"
|
||||
#include "nvim/tui/tui.h"
|
||||
#include "nvim/tui/tui_defs.h"
|
||||
@@ -51,14 +47,13 @@ static bool ui_client_is_remote = false;
|
||||
#endif
|
||||
// uncrustify:on
|
||||
|
||||
uint64_t ui_client_start_server(int argc, char **argv)
|
||||
uint64_t ui_client_start_server(const char *exepath, size_t argc, char **argv)
|
||||
{
|
||||
varnumber_T exit_status;
|
||||
char **args = xmalloc(((size_t)(2 + argc)) * sizeof(char *));
|
||||
char **args = xmalloc((2 + argc) * sizeof(char *));
|
||||
int args_idx = 0;
|
||||
args[args_idx++] = xstrdup(argv[0]);
|
||||
args[args_idx++] = xstrdup("--embed");
|
||||
for (int i = 1; i < argc; i++) {
|
||||
for (size_t i = 1; i < argc; i++) {
|
||||
args[args_idx++] = xstrdup(argv[i]);
|
||||
}
|
||||
args[args_idx++] = NULL;
|
||||
@@ -72,7 +67,8 @@ uint64_t ui_client_start_server(int argc, char **argv)
|
||||
#else
|
||||
bool detach = true;
|
||||
#endif
|
||||
Channel *channel = channel_job_start(args, get_vim_var_str(VV_PROGPATH),
|
||||
varnumber_T exit_status;
|
||||
Channel *channel = channel_job_start(args, exepath,
|
||||
CALLBACK_READER_INIT, on_err, CALLBACK_NONE,
|
||||
false, true, true, detach, kChannelStdinPipe,
|
||||
NULL, 0, 0, NULL, &exit_status);
|
||||
@@ -287,57 +283,69 @@ void ui_client_event_raw_line(GridLineEvent *g)
|
||||
(const schar_T *)grid_line_buf_char, grid_line_buf_attr);
|
||||
}
|
||||
|
||||
/// Restarts the embedded server without killing the UI.
|
||||
/// When a "restart" UI event is received, its arguments are saved here when
|
||||
/// waiting for the server to exit.
|
||||
static Array restart_args = ARRAY_DICT_INIT;
|
||||
static bool restart_pending = false;
|
||||
|
||||
void ui_client_event_restart(Array args)
|
||||
{
|
||||
// 1. Client-side server detach.
|
||||
ui_client_detach();
|
||||
// NB: don't send nvim_ui_detach to server, as it may have already exited.
|
||||
// ui_client_detach();
|
||||
|
||||
// 2. Close ui client channel (auto kills the `nvim --embed` server due to self-exit).
|
||||
const char *error;
|
||||
bool success = channel_close(ui_client_channel_id, kChannelPartAll, &error);
|
||||
if (!success) {
|
||||
ELOG("%s", error);
|
||||
// Save the arguments for ui_client_may_restart_server() later.
|
||||
api_free_array(restart_args);
|
||||
restart_args = copy_array(args, NULL);
|
||||
restart_pending = true;
|
||||
}
|
||||
|
||||
/// Called when the current server has exited.
|
||||
void ui_client_may_restart_server(void)
|
||||
{
|
||||
if (!restart_pending) {
|
||||
return;
|
||||
}
|
||||
restart_pending = false;
|
||||
|
||||
// 3. Get v:argv.
|
||||
typval_T *tv = get_vim_var_tv(VV_ARGV);
|
||||
if (tv->v_type != VAR_LIST || tv->vval.v_list == NULL) {
|
||||
ELOG("failed to get vim var typval");
|
||||
return;
|
||||
size_t argc;
|
||||
char **argv = NULL;
|
||||
if (restart_args.size < 2
|
||||
|| restart_args.items[0].type != kObjectTypeString
|
||||
|| restart_args.items[1].type != kObjectTypeArray
|
||||
|| (argc = restart_args.items[1].data.array.size) < 1) {
|
||||
ELOG("Error handling ui event 'restart'");
|
||||
goto cleanup;
|
||||
}
|
||||
list_T *l = tv->vval.v_list;
|
||||
int argc = tv_list_len(l);
|
||||
|
||||
// Assert to be positive for safe conversion to size_t.
|
||||
assert(argc > 0);
|
||||
|
||||
char **argv = xmalloc(sizeof(char *) * ((size_t)argc + 1));
|
||||
listitem_T *li = tv_list_first(l);
|
||||
for (int i = 0; i < argc && li != NULL; i++, li = TV_LIST_ITEM_NEXT(l, li)) {
|
||||
if (TV_LIST_ITEM_TV(li)->v_type == VAR_STRING && TV_LIST_ITEM_TV(li)->vval.v_string != NULL) {
|
||||
argv[i] = TV_LIST_ITEM_TV(li)->vval.v_string;
|
||||
} else {
|
||||
// 1. Get executable path and command-line arguments.
|
||||
const char *exepath = restart_args.items[0].data.string.data;
|
||||
argv = xcalloc(argc + 1, sizeof(char *));
|
||||
for (size_t i = 0; i < argc; i++) {
|
||||
if (restart_args.items[1].data.array.items[i].type == kObjectTypeString) {
|
||||
argv[i] = restart_args.items[1].data.array.items[i].data.string.data;
|
||||
}
|
||||
if (argv[i] == NULL) {
|
||||
argv[i] = "";
|
||||
}
|
||||
}
|
||||
argv[argc] = NULL;
|
||||
|
||||
// 4. Start a new `nvim --embed` server.
|
||||
uint64_t rv = ui_client_start_server(argc, argv);
|
||||
// 2. Start a new `nvim --embed` server.
|
||||
uint64_t rv = ui_client_start_server(exepath, argc, argv);
|
||||
if (!rv) {
|
||||
ELOG("failed to start nvim server");
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
// 5. Client-side server re-attach.
|
||||
// 3. Client-side server re-attach.
|
||||
ui_client_channel_id = rv;
|
||||
ui_client_is_remote = false;
|
||||
ui_client_attach(tui_width, tui_height, tui_term, tui_rgb);
|
||||
|
||||
ILOG("restarted server id=%" PRId64, rv);
|
||||
cleanup:
|
||||
xfree(argv);
|
||||
api_free_array(restart_args);
|
||||
restart_args = (Array)ARRAY_DICT_INIT;
|
||||
}
|
||||
|
||||
#ifdef EXITFREE
|
||||
|
Reference in New Issue
Block a user