[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
PROPOSAL: Control over process cleanup in `save-buffers-kill-emacs'.
From: |
Karl Fogel |
Subject: |
PROPOSAL: Control over process cleanup in `save-buffers-kill-emacs'. |
Date: |
Fri, 22 Sep 2017 13:58:41 -0500 |
In `save-buffers-kill-emacs' in files.el, we check for active processes -- the
familiar "Active processes exist; kill them and exit anyway? " query -- and
then only at the very end of the function do we run
`kill-emacs-query-functions' and call `kill-emacs' (which then runs the hooks
in `kill-emacs-hook' of course).
This means that neither `kill-emacs-query-functions' nor `kill-emacs-hook'
happen in time to offer any fine-grained control over whether the user gets
queried about active processes. And since the `confirm-kill-processes' flag
applies to all processes, one can't use it to customize *which* processes one
is queried about at exit time.
I propose moving `kill-emacs-query-functions' to before the process-killing
block, so that hooks can do things with processes before Emacs asks about those
processes. I haven't tested this patch yet, but this gives the idea:
--- lisp/files.el
+++ lisp/files.el
@@ -6875,6 +6875,7 @@ save-buffers-kill-emacs
(buffer-list))))
(progn (setq confirm nil)
(yes-or-no-p "Modified buffers exist; exit anyway? ")))
+ (run-hook-with-args-until-failure 'kill-emacs-query-functions)
(or (not (fboundp 'process-list))
;; process-list is not defined on MSDOS.
(not confirm-kill-processes)
@@ -6897,8 +6898,6 @@ save-buffers-kill-emacs
(when (window-live-p window)
(quit-restore-window window 'kill)))))
(list-processes t)))))
- ;; Query the user for other things, perhaps.
- (run-hook-with-args-until-failure 'kill-emacs-query-functions)
(or (null confirm)
(funcall confirm "Really exit Emacs? "))
(kill-emacs))))
Justification:
Sometimes there are expected processes that one knows it's okay to kill at exit
time, but one would prefer to be queried about any unexpected processes
(perhaps there is a long-running job that one forgot about, and one would
answer "no" to exiting Emacs if one were reminded about that job).
For example, I just started using IMAP (instead of local spool source) to fetch
email into Gnus. Since I'm querying two separate IMAP servers, there are two
separate IMAP buffers each with its own process. When I exit Emacs, I do not
need to be queried about those process buffers -- I know it's okay for Emacs to
kill the processes. But I can't easily do `set-process-query-on-exit-flag' at
the time the IMAP processes are started, since I just run `M-x gnus' and then
somewhen after that something runs IMAP (maybe there's a hook for this
somewhere, but if so, I haven't found it yet).
But I could put code like this into a hook, if only there were a hook that were
run before the process-killing block in `save-buffers-kill-emacs':
(mapcar (lambda (buf)
(when (string-match "^ \\*imap source\\*.*" (buffer-name buf))
(message "shutting down IMAP process '%s'" (get-buffer-process
buf))
(set-process-query-on-exit-flag (get-buffer-process buf) nil)
(kill-buffer buf)))
(buffer-list))
I think it would be generally useful to offer the ability to have custom
process cleanup at exit time.
My only reservation about the change is that the hook name
`kill-emacs-query-functions' perhaps becomes even less accurate (though it is
already potentially inaccurate, depending on how people are using it). In
fact, my personal use would be in order to *avoid* some queries, not to perform
any new queries. But for all I know, people are already using that hook to do
things that have nothing to do with queries, so maybe moving it earlier doesn't
add to the problem.
(A further possibility is to put the hook call at the very beginning of the
function, even before the big `let', so that the hooks is run even before the
"Modified buffers exist; exit anyway? " check. I'm not sure whether that would
be useful or not; since I don't have a concrete use case for it, I'm not
pushing for it here.)
For reference, here's the entire function as it stands right now, current tip
(commit 908af46abdb) of the "emacs-26" branch:
(defun save-buffers-kill-emacs (&optional arg)
"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."
(interactive "P")
;; Don't use save-some-buffers-default-predicate, because we want
;; to ask about all the buffers before killing Emacs.
(save-some-buffers arg t)
(let ((confirm confirm-kill-emacs))
(and
(or (not (memq t (mapcar (function
(lambda (buf) (and (buffer-file-name buf)
(buffer-modified-p buf))))
(buffer-list))))
(progn (setq confirm nil)
(yes-or-no-p "Modified buffers exist; exit anyway? ")))
(or (not (fboundp 'process-list))
;; process-list is not defined on MSDOS.
(not confirm-kill-processes)
(let ((processes (process-list))
active)
(while processes
(and (memq (process-status (car processes)) '(run stop open
listen))
(process-query-on-exit-flag (car processes))
(setq active t))
(setq processes (cdr processes)))
(or (not active)
(with-current-buffer-window
(get-buffer-create "*Process List*") nil
#'(lambda (window _value)
(with-selected-window window
(unwind-protect
(progn
(setq confirm nil)
(yes-or-no-p "Active processes exist; kill them and
exit anyway? "))
(when (window-live-p window)
(quit-restore-window window 'kill)))))
(list-processes t)))))
;; Query the user for other things, perhaps.
(run-hook-with-args-until-failure 'kill-emacs-query-functions)
(or (null confirm)
(funcall confirm "Really exit Emacs? "))
(kill-emacs))))
Thoughts,
-Karl
- PROPOSAL: Control over process cleanup in `save-buffers-kill-emacs'.,
Karl Fogel <=