mirror of
https://github.com/neovim/neovim.git
synced 2025-10-20 00:31:49 +00:00
feat(editor): ":restart" command #33953
Problem: Developing/troubleshooting plugins has friction because "restarting" Nvim requires quitting and manually starting again. #32484 Solution: - Implement a `:restart` command which emits `restart` UI event. - Handle the `restart` UI event in the builtin TUI client: stop the `nvim --embed` server, start a new one, and attach to it.
This commit is contained in:
@@ -12,6 +12,7 @@
|
||||
#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"
|
||||
@@ -37,6 +38,10 @@
|
||||
#endif
|
||||
|
||||
static TUIData *tui = NULL;
|
||||
static int tui_width = 0;
|
||||
static int tui_height = 0;
|
||||
static char *tui_term = "";
|
||||
static bool tui_rgb = false;
|
||||
static bool ui_client_is_remote = false;
|
||||
|
||||
// uncrustify:off
|
||||
@@ -164,12 +169,8 @@ void ui_client_run(bool remote_ui)
|
||||
FUNC_ATTR_NORETURN
|
||||
{
|
||||
ui_client_is_remote = remote_ui;
|
||||
int width, height;
|
||||
char *term;
|
||||
bool rgb;
|
||||
tui_start(&tui, &width, &height, &term, &rgb);
|
||||
|
||||
ui_client_attach(width, height, term, rgb);
|
||||
tui_start(&tui, &tui_width, &tui_height, &tui_term, &tui_rgb);
|
||||
ui_client_attach(tui_width, tui_height, tui_term, tui_rgb);
|
||||
|
||||
// TODO(justinmk): this is for log_spec. Can remove this after nvim_log #7062 is merged.
|
||||
if (os_env_exists("__NVIM_TEST_LOG", true)) {
|
||||
@@ -284,6 +285,59 @@ 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.
|
||||
void ui_client_event_restart(Array args)
|
||||
{
|
||||
// 1. Client-side server detach.
|
||||
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);
|
||||
return;
|
||||
}
|
||||
|
||||
// 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;
|
||||
}
|
||||
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 {
|
||||
argv[i] = "";
|
||||
}
|
||||
}
|
||||
argv[argc] = NULL;
|
||||
|
||||
// 4. Start a new `nvim --embed` server.
|
||||
uint64_t rv = ui_client_start_server(argc, argv);
|
||||
if (!rv) {
|
||||
ELOG("failed to start nvim server");
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
// 5. Client-side server re-attach.
|
||||
ui_client_channel_id = rv;
|
||||
ui_client_attach(tui_width, tui_height, tui_term, tui_rgb);
|
||||
|
||||
ILOG("restarted server id=%" PRId64, rv);
|
||||
cleanup:
|
||||
xfree(argv);
|
||||
}
|
||||
|
||||
#ifdef EXITFREE
|
||||
void ui_client_free_all_mem(void)
|
||||
{
|
||||
|
Reference in New Issue
Block a user