From 5be9a9cacfaae1959c4b95c45c146044a181ad20 Mon Sep 17 00:00:00 2001 From: Lars Ingebrigtsen Date: Sun, 17 Apr 2022 13:37:51 +0200 Subject: [PATCH] Add a new command `restart-emacs' * doc/lispref/os.texi (Killing Emacs): Document it. * lisp/files.el (save-buffers-kill-emacs): Add new RESTART parameter. (restart-emacs): New function. * src/emacs.c (terminate_due_to_signal, Fkill_emacs): Take an optional RESTART parameter. * test/lisp/files-tests.el (files-tests-save-buffers-kill-emacs--confirm-kill-processes): * src/xterm.c (x_connection_closed): * src/xsmfns.c (Fhandle_save_session): * src/keyboard.c (Fcommand_error_default_function, command_loop) (command_loop_1, read_menu_command, read_event_from_main_queue) (read_key_sequence, quit_throw_to_read_char): * src/eval.c (process_quit_flag): Adjust Fkill_emacs callers. --- doc/lispref/os.texi | 13 ++++++++++++- etc/NEWS | 12 +++++++++++- lisp/files.el | 19 ++++++++++++++++--- src/emacs.c | 21 +++++++++++++++------ src/eval.c | 2 +- src/keyboard.c | 18 +++++++++--------- src/xdisp.c | 2 +- src/xsmfns.c | 2 +- src/xterm.c | 2 +- test/lisp/files-tests.el | 2 +- 10 files changed, 68 insertions(+), 25 deletions(-) diff --git a/doc/lispref/os.texi b/doc/lispref/os.texi index 8366689640f..eea0ab8f6bc 100644 --- a/doc/lispref/os.texi +++ b/doc/lispref/os.texi @@ -699,7 +699,7 @@ If you started Emacs from a terminal, the parent process normally resumes control. The low-level primitive for killing Emacs is @code{kill-emacs}. -@deffn Command kill-emacs &optional exit-data +@deffn Command kill-emacs &optional exit-data restart This command calls the hook @code{kill-emacs-hook}, then exits the Emacs process and kills it. @@ -714,6 +714,10 @@ input) can read them. If @var{exit-data} is neither an integer nor a string, or is omitted, that means to use the (system-specific) exit status which indicates successful program termination. + +If @var{restart} is non-@code{nil}, instead of just exiting at the +end, start a new Emacs process, using the same command line arguments +as the currently running Emacs process. @end deffn @cindex SIGTERM @@ -756,6 +760,13 @@ the remaining functions in this hook. Calling @code{kill-emacs} directly does not run this hook. @end defopt +@deffn Command restart-emacs +This command does the same as @code{save-buffers-kill-emacs}, but +instead of just killing the current Emacs process at the end, it'll +restart a new Emacs process, using the same command line arguments as +the currently running Emacs process. +@end deffn + @node Suspending Emacs @subsection Suspending Emacs @cindex suspending Emacs diff --git a/etc/NEWS b/etc/NEWS index 71d1e90d833..0245ec8c689 100644 --- a/etc/NEWS +++ b/etc/NEWS @@ -194,6 +194,15 @@ methods instead. * Changes in Emacs 29.1 ++++ +** New command 'restart-emacs'. +This is like 'save-buffers-kill-emacs', but instead of just killing +the current Emacs process at the end, it starts a new Emacs process +(using the same command line arguments as the running Emacs process). +'kill-emacs' and 'save-buffers-kill-emacs' have also gained new +optional parameters to restart instead of just killing the current +process. + +++ ** New user option 'mouse-drag-and-drop-region-cross-program'. If non-nil, this option allows dragging text in the region from Emacs @@ -1451,7 +1460,8 @@ compliant. +++ ** New macro 'setopt'. This is like 'setq', but is meant to be used for user options instead -of plain variables, and uses 'custom-set'/'set-default' to set them. +of plain variables, and +uses 'custom-set'/'set-default' to set them. +++ ** New utility predicate 'mode-line-window-selected-p'. diff --git a/lisp/files.el b/lisp/files.el index b5ec7d45005..80180276a99 100644 --- a/lisp/files.el +++ b/lisp/files.el @@ -7762,14 +7762,17 @@ prompt the user before killing them." :group 'convenience :version "26.1") -(defun save-buffers-kill-emacs (&optional arg) +(defun save-buffers-kill-emacs (&optional arg restart) "Offer to save each buffer, then kill this Emacs process. With prefix ARG, silently save all file-visiting buffers without asking. If there are active processes where `process-query-on-exit-flag' returns non-nil and `confirm-kill-processes' is non-nil, asks whether processes should be killed. + Runs the members of `kill-emacs-query-functions' in turn and stops -if any returns nil. If `confirm-kill-emacs' is non-nil, calls it." +if any returns nil. If `confirm-kill-emacs' is non-nil, calls it. + +If RESTART, restart Emacs after killing the current Emacs process." (interactive "P") ;; Don't use save-some-buffers-default-predicate, because we want ;; to ask about all the buffers before killing Emacs. @@ -7823,7 +7826,7 @@ if any returns nil. If `confirm-kill-emacs' is non-nil, calls it." (run-hook-with-args-until-failure 'kill-emacs-query-functions) (or (null confirm) (funcall confirm "Really exit Emacs? ")) - (kill-emacs)))) + (kill-emacs nil restart)))) (defun save-buffers-kill-terminal (&optional arg) "Offer to save each buffer, then kill the current connection. @@ -7838,6 +7841,16 @@ only these files will be asked to be saved." (if (frame-parameter nil 'client) (server-save-buffers-kill-terminal arg) (save-buffers-kill-emacs arg))) + +(defun restart-emacs () + "Kill the current Emacs process and start a new one. +This goes through the same shutdown procedure as +`save-buffers-kill-emacs', but instead of killing Emacs and +exiting, it re-executes Emacs (using the same command line +arguments as the running Emacs)." + (interactive) + (save-buffers-kill-emacs nil t)) + ;; We use /: as a prefix to "quote" a file name ;; so that magic file name handlers will not apply to it. diff --git a/src/emacs.c b/src/emacs.c index a35996c07aa..50b1628d207 100644 --- a/src/emacs.c +++ b/src/emacs.c @@ -427,7 +427,7 @@ terminate_due_to_signal (int sig, int backtrace_limit) don't care about the message stack. */ if (sig == SIGINT && noninteractive) clear_message_stack (); - Fkill_emacs (make_fixnum (sig)); + Fkill_emacs (make_fixnum (sig), Qnil); } shut_down_emacs (sig, Qnil); @@ -2740,21 +2740,25 @@ sort_args (int argc, char **argv) xfree (priority); } -DEFUN ("kill-emacs", Fkill_emacs, Skill_emacs, 0, 1, "P", +DEFUN ("kill-emacs", Fkill_emacs, Skill_emacs, 0, 2, "P", doc: /* Exit the Emacs job and kill it. If ARG is an integer, return ARG as the exit program code. If ARG is a string, stuff it as keyboard input. Any other value of ARG, or ARG omitted, means return an exit code that indicates successful program termination. +If RESTART is non-nil, instead of just exiting at the end, start a new +Emacs process, using the same command line arguments as the currently +running Emacs process. + This function is called upon receipt of the signals SIGTERM or SIGHUP, and upon SIGINT in batch mode. -The value of `kill-emacs-hook', if not void, -is a list of functions (of no args), -all of which are called before Emacs is actually killed. */ +The value of `kill-emacs-hook', if not void, is a list of functions +(of no args), all of which are called before Emacs is actually +killed. */ attributes: noreturn) - (Lisp_Object arg) + (Lisp_Object arg, Lisp_Object restart) { int exit_code; @@ -2801,6 +2805,11 @@ all of which are called before Emacs is actually killed. */ eln_load_path_final_clean_up (); #endif + if (!NILP (restart)) + { + execvp (*initial_argv, initial_argv); + } + if (FIXNUMP (arg)) exit_code = (XFIXNUM (arg) < 0 ? XFIXNUM (arg) | INT_MIN diff --git a/src/eval.c b/src/eval.c index a1cebcd0257..6b1e12b8232 100644 --- a/src/eval.c +++ b/src/eval.c @@ -1613,7 +1613,7 @@ process_quit_flag (void) Lisp_Object flag = Vquit_flag; Vquit_flag = Qnil; if (EQ (flag, Qkill_emacs)) - Fkill_emacs (Qnil); + Fkill_emacs (Qnil, Qnil); if (EQ (Vthrow_on_input, flag)) Fthrow (Vthrow_on_input, Qt); quit (); diff --git a/src/keyboard.c b/src/keyboard.c index e569f8f34c9..19c8fdf1dc0 100644 --- a/src/keyboard.c +++ b/src/keyboard.c @@ -1059,7 +1059,7 @@ Default value of `command-error-function'. */) print_error_message (data, Qexternal_debugging_output, SSDATA (context), signal); Fterpri (Qexternal_debugging_output, Qnil); - Fkill_emacs (make_fixnum (-1)); + Fkill_emacs (make_fixnum (-1), Qnil); } else { @@ -1122,7 +1122,7 @@ command_loop (void) /* End of file in -batch run causes exit here. */ if (noninteractive) - Fkill_emacs (Qt); + Fkill_emacs (Qt, Qnil); } } @@ -1331,7 +1331,7 @@ command_loop_1 (void) Lisp_Object cmd; if (! FRAME_LIVE_P (XFRAME (selected_frame))) - Fkill_emacs (Qnil); + Fkill_emacs (Qnil, Qnil); /* Make sure the current window's buffer is selected. */ set_buffer_internal (XBUFFER (XWINDOW (selected_window)->contents)); @@ -1402,7 +1402,7 @@ command_loop_1 (void) /* A filter may have run while we were reading the input. */ if (! FRAME_LIVE_P (XFRAME (selected_frame))) - Fkill_emacs (Qnil); + Fkill_emacs (Qnil, Qnil); set_buffer_internal (XBUFFER (XWINDOW (selected_window)->contents)); ++num_input_keys; @@ -1660,7 +1660,7 @@ read_menu_command (void) unbind_to (count, Qnil); if (! FRAME_LIVE_P (XFRAME (selected_frame))) - Fkill_emacs (Qnil); + Fkill_emacs (Qnil, Qnil); if (i == 0 || i == -1) return Qt; @@ -2259,7 +2259,7 @@ read_event_from_main_queue (struct timespec *end_time, /* Terminate Emacs in batch mode if at eof. */ if (noninteractive && FIXNUMP (c) && XFIXNUM (c) < 0) - Fkill_emacs (make_fixnum (1)); + Fkill_emacs (make_fixnum (1), Qnil); if (FIXNUMP (c)) { @@ -10039,7 +10039,7 @@ read_key_sequence (Lisp_Object *keybuf, Lisp_Object prompt, if (fix_current_buffer) { if (! FRAME_LIVE_P (XFRAME (selected_frame))) - Fkill_emacs (Qnil); + Fkill_emacs (Qnil, Qnil); if (XBUFFER (XWINDOW (selected_window)->contents) != current_buffer) Fset_buffer (XWINDOW (selected_window)->contents); @@ -10163,7 +10163,7 @@ read_key_sequence (Lisp_Object *keybuf, Lisp_Object prompt, record_unwind_current_buffer (); if (! FRAME_LIVE_P (XFRAME (selected_frame))) - Fkill_emacs (Qnil); + Fkill_emacs (Qnil, Qnil); set_buffer_internal (XBUFFER (XWINDOW (window)->contents)); goto replay_sequence; } @@ -11393,7 +11393,7 @@ quit_throw_to_read_char (bool from_signal) /* When not called from a signal handler it is safe to call Lisp. */ if (!from_signal && EQ (Vquit_flag, Qkill_emacs)) - Fkill_emacs (Qnil); + Fkill_emacs (Qnil, Qnil); /* Prevent another signal from doing this before we finish. */ clear_waiting_for_input (); diff --git a/src/xdisp.c b/src/xdisp.c index 2dbc68f657c..a3a4338eb4f 100644 --- a/src/xdisp.c +++ b/src/xdisp.c @@ -12143,7 +12143,7 @@ setup_echo_area_for_printing (bool multibyte_p) { /* If we can't find an echo area any more, exit. */ if (! FRAME_LIVE_P (XFRAME (selected_frame))) - Fkill_emacs (Qnil); + Fkill_emacs (Qnil, Qnil); ensure_echo_area_buffers (); diff --git a/src/xsmfns.c b/src/xsmfns.c index 199e3ded3dd..7015a8eb633 100644 --- a/src/xsmfns.c +++ b/src/xsmfns.c @@ -522,7 +522,7 @@ Do not call this function yourself. */) { /* We should not do user interaction here, but it is not easy to prevent. Fix this in next version. */ - Fkill_emacs (Qnil); + Fkill_emacs (Qnil, Qnil); #if false /* This will not be reached, but we want kill-emacs-hook to be run. */ diff --git a/src/xterm.c b/src/xterm.c index 89dd28c0d58..ab4dcc3841a 100644 --- a/src/xterm.c +++ b/src/xterm.c @@ -19773,7 +19773,7 @@ For details, see etc/PROBLEMS.\n", if (terminal_list == 0) { fprintf (stderr, "%s\n", error_msg); - Fkill_emacs (make_fixnum (70)); + Fkill_emacs (make_fixnum (70), Qnil); } totally_unblock_input (); diff --git a/test/lisp/files-tests.el b/test/lisp/files-tests.el index 42b09201de8..e4424f3cbed 100644 --- a/test/lisp/files-tests.el +++ b/test/lisp/files-tests.el @@ -263,7 +263,7 @@ form.") nil)) (kill-emacs-args nil) ((symbol-function #'kill-emacs) - (lambda (&optional arg) (push arg kill-emacs-args))) + (lambda (&optional arg arg) (push arg kill-emacs-args))) (process (make-process :name "sleep" -- 2.39.2