mirror of
https://github.com/neovim/neovim.git
synced 2025-09-05 10:58:16 +00:00
feat: ":restart +cmd" #34788
Problem: ":restart" always executes ":qall" to exit the server. Solution: Support ":restart +cmd" so the user can control the command used to exit the server. Co-authored-by: Justin M. Keyes <justinkz@gmail.com> Co-authored-by: zeertzjq <zeertzjq@outlook.com>
This commit is contained in:
@@ -70,21 +70,20 @@ Stop or detach the current UI
|
||||
Restart Nvim
|
||||
|
||||
*:restart*
|
||||
:restart
|
||||
:restart [+cmd]
|
||||
Restarts the Nvim server with the same startup arguments
|
||||
|v:argv| and reattaches the current UI to the new server.
|
||||
All other UIs will detach.
|
||||
|
||||
This fails when changes have been made and Vim refuses to
|
||||
|abandon| the current buffer.
|
||||
Use with `:confirm` to prompt if changes have been made.
|
||||
|
||||
Example: `:restart +qall!` stops the server using `:qall!`.
|
||||
|
||||
Note: |+cmd| defaults to `qall!` if not specified.
|
||||
Note: If the current UI hasn't implemented the "restart" UI
|
||||
event, this command is equivalent to `:qall`.
|
||||
Note: Only works if the UI and server are on the same system.
|
||||
|
||||
:restart!
|
||||
Force restarts the Nvim server, abandoning unsaved buffers.
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
GUI commands
|
||||
|
||||
|
@@ -2184,13 +2184,13 @@ M.cmds = {
|
||||
command = 'quitall',
|
||||
flags = bit.bor(BANG, TRLBAR),
|
||||
addr_type = 'ADDR_NONE',
|
||||
func = 'ex_quitall_or_restart',
|
||||
func = 'ex_quitall',
|
||||
},
|
||||
{
|
||||
command = 'qall',
|
||||
flags = bit.bor(BANG, TRLBAR, CMDWIN, LOCK_OK),
|
||||
addr_type = 'ADDR_NONE',
|
||||
func = 'ex_quitall_or_restart',
|
||||
func = 'ex_quitall',
|
||||
},
|
||||
{
|
||||
command = 'read',
|
||||
@@ -2248,9 +2248,9 @@ M.cmds = {
|
||||
},
|
||||
{
|
||||
command = 'restart',
|
||||
flags = bit.bor(BANG, TRLBAR),
|
||||
flags = bit.bor(CMDARG, TRLBAR),
|
||||
addr_type = 'ADDR_NONE',
|
||||
func = 'ex_quitall_or_restart',
|
||||
func = 'ex_restart',
|
||||
},
|
||||
{
|
||||
command = 'retab',
|
||||
|
@@ -15,6 +15,7 @@
|
||||
#include "nvim/api/private/defs.h"
|
||||
#include "nvim/api/private/helpers.h"
|
||||
#include "nvim/api/ui.h"
|
||||
#include "nvim/api/vimscript.h"
|
||||
#include "nvim/arglist.h"
|
||||
#include "nvim/ascii_defs.h"
|
||||
#include "nvim/autocmd.h"
|
||||
@@ -4700,6 +4701,13 @@ void not_exiting(void)
|
||||
exiting = false;
|
||||
}
|
||||
|
||||
/// Call this function if we thought we were going to restart, but we won't
|
||||
/// (because of an error).
|
||||
void not_restarting(void)
|
||||
{
|
||||
restarting = false;
|
||||
}
|
||||
|
||||
bool before_quit_autocmds(win_T *wp, bool quit_all, bool forceit)
|
||||
{
|
||||
apply_autocmds(EVENT_QUITPRE, NULL, NULL, false, wp->w_buffer);
|
||||
@@ -4829,22 +4837,39 @@ int before_quit_all(exarg_T *eap)
|
||||
}
|
||||
|
||||
/// ":qall": try to quit all windows
|
||||
/// ":restart": restart the Nvim server
|
||||
static void ex_quitall_or_restart(exarg_T *eap)
|
||||
static void ex_quitall(exarg_T *eap)
|
||||
{
|
||||
if (before_quit_all(eap) == FAIL) {
|
||||
return;
|
||||
}
|
||||
exiting = true;
|
||||
Error err = ERROR_INIT;
|
||||
if ((eap->forceit || !check_changed_any(false, false))
|
||||
&& (eap->cmdidx != CMD_restart || remote_ui_restart(current_ui, &err))) {
|
||||
getout(0);
|
||||
if (!eap->forceit && check_changed_any(false, false)) {
|
||||
not_exiting();
|
||||
return;
|
||||
}
|
||||
not_exiting();
|
||||
getout(0);
|
||||
}
|
||||
|
||||
/// ":restart": restart the Nvim server (using ":qall!").
|
||||
/// ":restart +cmd": restart the Nvim server using ":cmd".
|
||||
static void ex_restart(exarg_T *eap)
|
||||
{
|
||||
char *quit_cmd = (eap->do_ecmd_cmd) ? eap->do_ecmd_cmd : "qall!";
|
||||
Error err = ERROR_INIT;
|
||||
if ((cmdmod.cmod_flags & CMOD_CONFIRM) && check_changed_any(false, false)) {
|
||||
return;
|
||||
}
|
||||
restarting = true;
|
||||
nvim_command(cstr_as_string(quit_cmd), &err);
|
||||
if (ERROR_SET(&err)) {
|
||||
emsg(err.msg); // UI disappeared already?
|
||||
emsg(err.msg); // Could not exit
|
||||
api_clear_error(&err);
|
||||
not_restarting();
|
||||
return;
|
||||
}
|
||||
if (!exiting) {
|
||||
emsg("restart failed: +cmd did not quit the server");
|
||||
not_restarting();
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -423,6 +423,8 @@ EXTERN int sc_col; // column for shown command
|
||||
EXTERN int starting INIT( = NO_SCREEN);
|
||||
// true when planning to exit. Might keep running if there is a changed buffer.
|
||||
EXTERN bool exiting INIT( = false);
|
||||
// true when planning to restart.
|
||||
EXTERN bool restarting INIT( = false);
|
||||
// internal value of v:dying
|
||||
EXTERN int v_dying INIT( = 0);
|
||||
// is stdin a terminal?
|
||||
|
@@ -809,6 +809,17 @@ void getout(int exitval)
|
||||
ui_call_set_title(cstr_as_string(p_titleold));
|
||||
}
|
||||
|
||||
if (restarting) {
|
||||
Error err = ERROR_INIT;
|
||||
if (!remote_ui_restart(current_ui, &err)) {
|
||||
if (ERROR_SET(&err)) {
|
||||
ELOG("%s", err.msg); // UI disappeared already?
|
||||
api_clear_error(&err);
|
||||
}
|
||||
}
|
||||
restarting = false;
|
||||
}
|
||||
|
||||
if (garbage_collect_at_exit) {
|
||||
garbage_collect(false);
|
||||
}
|
||||
|
@@ -264,6 +264,16 @@ describe('TUI :restart', function()
|
||||
restart_pid_check()
|
||||
gui_running_check()
|
||||
|
||||
-- Check ":restart +qall" on an unmodified buffer.
|
||||
tt.feed_data(':restart +qall\013')
|
||||
screen_expect(s0)
|
||||
restart_pid_check()
|
||||
gui_running_check()
|
||||
|
||||
-- Check ":restart +echo" cannot restart server.
|
||||
tt.feed_data(':restart +echo\013')
|
||||
screen:expect({ any = vim.pesc('+cmd did not quit the server') })
|
||||
|
||||
tt.feed_data('ithis will be removed\027')
|
||||
screen_expect([[
|
||||
this will be remove^d |
|
||||
@@ -273,20 +283,15 @@ describe('TUI :restart', function()
|
||||
{5:-- TERMINAL --} |
|
||||
]])
|
||||
|
||||
-- Check ":restart" on a modified buffer.
|
||||
tt.feed_data(':restart\013')
|
||||
screen_expect([[
|
||||
this will be removed |
|
||||
{3: }|
|
||||
{101:E37: No write since last change} |
|
||||
{101:E162: No write since last change for buffer "[No N}|
|
||||
{101:ame]"} |
|
||||
{102:Press ENTER or type command to continue}^ |
|
||||
{5:-- TERMINAL --} |
|
||||
]])
|
||||
-- Check ":confirm restart" on a modified buffer.
|
||||
tt.feed_data(':confirm restart\013')
|
||||
screen:expect({ any = vim.pesc('Save changes to "Untitled"?') })
|
||||
|
||||
-- Check ":restart!".
|
||||
tt.feed_data(':restart!\013')
|
||||
-- Cancel the operation (abandons restart).
|
||||
tt.feed_data('C\013')
|
||||
|
||||
-- Check ":restart" on the modified buffer.
|
||||
tt.feed_data(':restart\013')
|
||||
screen_expect(s0)
|
||||
restart_pid_check()
|
||||
gui_running_check()
|
||||
@@ -3728,9 +3733,9 @@ describe('TUI client', function()
|
||||
screen_client:expect(s1)
|
||||
screen_server:expect(s1)
|
||||
|
||||
-- Run :restart! on the remote client.
|
||||
-- Run :restart on the remote client.
|
||||
-- The remote client should start a new server while the original one should exit.
|
||||
feed_data(':restart!\n')
|
||||
feed_data(':restart\n')
|
||||
screen_client:expect([[
|
||||
^ |
|
||||
{100:~ }|*3
|
||||
@@ -3805,9 +3810,9 @@ describe('TUI client', function()
|
||||
feed_data(':echo "GUI Running: " .. has("gui_running")\013')
|
||||
screen_client:expect({ any = 'GUI Running: 1' })
|
||||
|
||||
-- Run :restart! on the client.
|
||||
-- Run :restart on the client.
|
||||
-- The client should start a new server while the original server should exit.
|
||||
feed_data(':restart!\n')
|
||||
feed_data(':restart\n')
|
||||
screen_client:expect([[
|
||||
^ |
|
||||
{100:~ }|*4
|
||||
|
Reference in New Issue
Block a user