mirror of
				https://github.com/neovim/neovim.git
				synced 2025-11-03 17:24:29 +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;
 | 
			
		||||
  }
 | 
			
		||||
  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