Options to automatically stop the Emacs server
* doc/emacs/misc.texi (Emacs Server): Document the new function. Also mention that an Emacs server can be started with emacsclient. * etc/NEWS: Describe the new function (bug#51377). * lisp/server.el (server-stop-automatically): New function. (server-stop-automatically): New auxiliary variable. (server-stop-automatically--maybe-kill-emacs) (server-stop-automatically--handle-delete-frame): New auxiliary functions. (server-save-buffers-kill-terminal): Call the new auxiliary function when necessary.
This commit is contained in:
parent
0a93fb499b
commit
894dd18804
3 changed files with 135 additions and 21 deletions
|
@ -1703,6 +1703,11 @@ options. @xref{Initial Options}. When Emacs is started this way, it
|
|||
calls @code{server-start} after initialization and does not open an
|
||||
initial frame. It then waits for edit requests from clients.
|
||||
|
||||
@item
|
||||
Run the command @code{emacsclient} with the @samp{--alternate-editor=""}
|
||||
command-line option. This starts an Emacs daemon only if no Emacs daemon
|
||||
is already running.
|
||||
|
||||
@cindex systemd unit file
|
||||
@item
|
||||
If your operating system uses @command{systemd} to manage startup,
|
||||
|
@ -1769,6 +1774,32 @@ you can give each daemon its own server name like this:
|
|||
emacs --daemon=foo
|
||||
@end example
|
||||
|
||||
@findex server-stop-automatically
|
||||
The Emacs server can optionally be stopped automatically when
|
||||
certain conditions are met. To do this, call the function
|
||||
@code{server-stop-automatically} in your init file (@pxref{Init
|
||||
File}), with one of the following arguments:
|
||||
|
||||
@itemize
|
||||
@item
|
||||
With the argument @code{empty}, the server is stopped when it has no
|
||||
clients, no unsaved file-visiting buffers and no running processes
|
||||
anymore.
|
||||
|
||||
@item
|
||||
With the argument @code{delete-frame}, when the last client frame is
|
||||
being closed, you are asked whether each unsaved file-visiting buffer
|
||||
must be saved and each unfinished process can be stopped, and if so,
|
||||
the server is stopped.
|
||||
|
||||
@item
|
||||
With the argument @code{kill-terminal}, when the last client frame is
|
||||
being closed with @kbd{C-x C-c} (@code{save-buffers-kill-terminal}),
|
||||
you are asked whether each unsaved file-visiting buffer must be saved
|
||||
and each unfinished process can be stopped, and if so, the server is
|
||||
stopped.
|
||||
@end itemize
|
||||
|
||||
@findex server-eval-at
|
||||
If you have defined a server by a unique server name, it is possible
|
||||
to connect to the server from another Emacs instance and evaluate Lisp
|
||||
|
|
6
etc/NEWS
6
etc/NEWS
|
@ -139,6 +139,12 @@ suspicious and could be malicious.
|
|||
With this command-line option, Emacs reuses an existing graphical client
|
||||
frame if one exists; otherwise it creates a new frame.
|
||||
|
||||
+++
|
||||
*** 'server-stop-automatically' can be used to automatically stop the server.
|
||||
The Emacs server will be automatically stopped when certain conditions
|
||||
are met. The conditions are given by the argument, which can be
|
||||
'empty', 'delete-frame' or 'kill-terminal'.
|
||||
|
||||
* Editing Changes in Emacs 29.1
|
||||
|
||||
---
|
||||
|
|
119
lisp/server.el
119
lisp/server.el
|
@ -1716,6 +1716,9 @@ be a cons cell (LINENUMBER . COLUMNNUMBER)."
|
|||
(when server-raise-frame
|
||||
(select-frame-set-input-focus (window-frame)))))
|
||||
|
||||
(defvar server-stop-automatically nil
|
||||
"Internal status variable for `server-stop-automatically'.")
|
||||
|
||||
;;;###autoload
|
||||
(defun server-save-buffers-kill-terminal (arg)
|
||||
;; Called from save-buffers-kill-terminal in files.el.
|
||||
|
@ -1724,27 +1727,101 @@ With ARG non-nil, silently save all file-visiting buffers, then kill.
|
|||
|
||||
If emacsclient was started with a list of filenames to edit, then
|
||||
only these files will be asked to be saved."
|
||||
(let ((proc (frame-parameter nil 'client)))
|
||||
(cond ((eq proc 'nowait)
|
||||
;; Nowait frames have no client buffer list.
|
||||
(if (cdr (frame-list))
|
||||
(progn (save-some-buffers arg)
|
||||
(delete-frame))
|
||||
;; If we're the last frame standing, kill Emacs.
|
||||
(save-buffers-kill-emacs arg)))
|
||||
((processp proc)
|
||||
(let ((buffers (process-get proc 'buffers)))
|
||||
(save-some-buffers
|
||||
arg (if buffers
|
||||
;; Only files from emacsclient file list.
|
||||
(lambda () (memq (current-buffer) buffers))
|
||||
;; No emacsclient file list: don't override
|
||||
;; `save-some-buffers-default-predicate' (unless
|
||||
;; ARG is non-nil), since we're not killing
|
||||
;; Emacs (unlike `save-buffers-kill-emacs').
|
||||
(and arg t)))
|
||||
(server-delete-client proc)))
|
||||
(t (error "Invalid client frame")))))
|
||||
(if server-stop-automatically
|
||||
(server-stop-automatically--handle-delete-frame (selected-frame))
|
||||
(let ((proc (frame-parameter nil 'client)))
|
||||
(cond ((eq proc 'nowait)
|
||||
;; Nowait frames have no client buffer list.
|
||||
(if (cdr (frame-list))
|
||||
(progn (save-some-buffers arg)
|
||||
(delete-frame))
|
||||
;; If we're the last frame standing, kill Emacs.
|
||||
(save-buffers-kill-emacs arg)))
|
||||
((processp proc)
|
||||
(let ((buffers (process-get proc 'buffers)))
|
||||
(save-some-buffers
|
||||
arg (if buffers
|
||||
;; Only files from emacsclient file list.
|
||||
(lambda () (memq (current-buffer) buffers))
|
||||
;; No emacsclient file list: don't override
|
||||
;; `save-some-buffers-default-predicate' (unless
|
||||
;; ARG is non-nil), since we're not killing
|
||||
;; Emacs (unlike `save-buffers-kill-emacs').
|
||||
(and arg t)))
|
||||
(server-delete-client proc)))
|
||||
(t (error "Invalid client frame"))))))
|
||||
|
||||
(defun server-stop-automatically--handle-delete-frame (frame)
|
||||
"Handle deletion of FRAME when `server-stop-automatically' is used."
|
||||
(when server-stop-automatically
|
||||
(if (if (and (processp (frame-parameter frame 'client))
|
||||
(eq this-command 'save-buffers-kill-terminal))
|
||||
(progn
|
||||
(dolist (f (frame-list))
|
||||
(when (and (eq (frame-parameter frame 'client)
|
||||
(frame-parameter f 'client))
|
||||
(not (eq frame f)))
|
||||
(set-frame-parameter f 'client nil)
|
||||
(let ((server-stop-automatically nil))
|
||||
(delete-frame f))))
|
||||
(if (cddr (frame-list))
|
||||
(let ((server-stop-automatically nil))
|
||||
(delete-frame frame)
|
||||
nil)
|
||||
t))
|
||||
(null (cddr (frame-list))))
|
||||
(let ((server-stop-automatically nil))
|
||||
(save-buffers-kill-emacs)
|
||||
(delete-frame frame)))))
|
||||
|
||||
(defun server-stop-automatically--maybe-kill-emacs ()
|
||||
"Handle closing of Emacs daemon when `server-stop-automatically' is used."
|
||||
(unless (cdr (frame-list))
|
||||
(when (and
|
||||
(not (memq t (mapcar (lambda (b)
|
||||
(and (buffer-file-name b)
|
||||
(buffer-modified-p b)))
|
||||
(buffer-list))))
|
||||
(not (memq t (mapcar (lambda (p)
|
||||
(and (memq (process-status p)
|
||||
'(run stop open listen))
|
||||
(process-query-on-exit-flag p)))
|
||||
(process-list)))))
|
||||
(kill-emacs))))
|
||||
|
||||
;;;###autoload
|
||||
(defun server-stop-automatically (arg)
|
||||
"Automatically stop server when possible.
|
||||
|
||||
When ARG is 'empty, the server is stopped when it has no remaining
|
||||
clients, no remaining unsaved file-visiting buffers, and no
|
||||
running processes with a query-on-exit flag.
|
||||
|
||||
When ARG is 'delete-frame, the user is asked when the last frame is
|
||||
being closed whether each unsaved file-visiting buffer must be
|
||||
saved and each running process with a query-on-exit flag can be
|
||||
stopped, and if so, the server itself is stopped.
|
||||
|
||||
When ARG is 'kill-terminal, the user is asked when the last frame
|
||||
is being close with \\[save-buffers-kill-terminal] \
|
||||
whether each unsaved file-visiting
|
||||
buffer must be saved and each running process with a query-on-exit
|
||||
flag can be stopped, and if so, the server itself is stopped.
|
||||
|
||||
This function is meant to be put in init files."
|
||||
(when (daemonp)
|
||||
(setq server-stop-automatically arg)
|
||||
(cond
|
||||
((eq arg 'empty)
|
||||
(setq server-stop-automatically nil)
|
||||
(run-with-timer 10 2
|
||||
#'server-stop-automatically--maybe-kill-emacs))
|
||||
((eq arg 'delete-frame)
|
||||
(add-hook 'delete-frame-functions
|
||||
#'server-stop-automatically--handle-delete-frame))
|
||||
((eq arg 'kill-terminal))
|
||||
(t
|
||||
(error "Unexpected argument")))))
|
||||
|
||||
(define-key ctl-x-map "#" 'server-edit)
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue