bug-gnu-emacs
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

bug#51993: 29.0.50; [PATCH] Killing emacsclient terminal with `server-st


From: Jim Porter
Subject: bug#51993: 29.0.50; [PATCH] Killing emacsclient terminal with `server-stop-automatically' doesn't prompt to save files
Date: Sun, 28 Nov 2021 21:39:46 -0800

To help move things along, I've drafted an initial version of a proposal describing possible behaviors of `server-stop-automatically' at a high level. Hopefully that will make it easier to discuss how each setting should work, and we can refine the proposal until we're happy with it. Then any implementation changes should "just" be a matter of following the final proposal.

I welcome any comments or suggested additions to this proposal. I covered things how I see them, but I may not have provided enough detail for everyone to understand all the nuances, and other people might have their own use cases they'd like to see addressed.

I can also post this proposal to emacs-devel if people think it would be better to get a wider range of feedback on it. Once we can get some level of consensus on the proposal, then hopefully we'll know the right thing to do about this bug.

--------------------

Automatically Shutting Down the Emacs Daemon
Revision 1

* Introduction

Since Emacs 23, `emacsclient' has had the ability to automatically start an Emacs daemon by passing `--alternate-editor=""' (or setting the ALTERNATE_EDITOR environment variable to the empty string). In Emacs 29, the ability to automatically shut down the daemon was added for symmetry. This allows users who prefer to start the Emacs daemon on an as-needed basis to configure the daemon to stop when finished. However, "finished" is a vague term and doesn't precisely describe the conditions that would cause the Emacs daemon to be shut down.

Note: for the discussion below, "clients" refers to both "true clients" (members of `server-clients') and "pseudo-clients" (each frame with the `client' parameter set to `nowait'). This is essentially the logic used by `server-save-buffers-kill-terminal' since Emacs 23.

* Proposed Behaviors

I propose two main ways of determining when the Emacs daemon should be shut down automatically. Each has different pros and cons, and so there are arguments for supporting one, both, or neither in Emacs going forward. However, I think each are distinct enough that supporting both would be reasonable.

** Implicit Shutdown

For this behavior, the Emacs daemon will be silently stopped once nothing would be lost by stopping it. In particular, this means that the Emacs daemon should continue so long as there's at least one a) active client, b) unsaved file, or c) running subprocess (with non-nil `process-query-on-exit-flag'). If none of these exist, then the Emacs daemon will be stopped.

One open question is how this should interact with options that control how `save-buffers-kill-emacs' prompts the user. If `confirm-kill-processes' is nil, should the Emacs daemon then be stopped even if there are active subprocesses?

*** Pros

A benefit of this behavior is that because the shutdown occurs implicitly, there's no change to how users interact with Emacs. For example, `save-buffers-kill-terminal' will prompt the user to save only those files passed to `emacsclient'.

*** Cons

However, the behavior's benefit has another side to it: it can be difficult for a user to predict whether the Emacs daemon will be stopped. For example, a stray unsaved file that the user forgot about could be the difference between the daemon continuing to run or being stopped.

Furthermore, since an Emacs daemon with no clients is out of sight, it may be some time before the user realizes their mistake, leading to confusion about why some other program appears to be reading an out-of-date version of the file. That said, this aspect is equally a concern when *not* automatically stopping the Emacs daemon at all.

** Explicit Shutdown

(Note: this is the behavior I personally prefer.) In this case, Emacs will be stopped as soon as there are no active clients, prompting the user to save their work as needed. In other words, when a client is about to be deleted for any reason (calling `server-save-buffers-kill-terminal', deleting the last frame associated with the client, etc), then:

- If this is not the last client, behave as in Emacs 28; that is, prompt to save any files passed to `emacsclient' before deleting the client.

- If this is the last client, prompt the user to save all their work before killing Emacs entirely; that is, call `save-buffers-kill-emacs'. In this case, the behavior should be identical (or as close as possible) to killing a "regular", non-server Emacs in a similar state.

One open question is: should Emacs warn the user that it will the daemon when deleting the last client? Currently it does so in `server-kill-emacs-query-function', asking, "This Emacs session has clients; exit anyway?" It may be useful to keep this warning, possibly rewording it in this case to explain the situation better. It's also possible that it's just extra noise and should be eliminate in this case. (It may even make sense to provide a separate configuration option.)

*** Pros

One of the main goals with Explicit Shutdown is to resolve a concern mentioned above: an Emacs daemon with no clients is out of sight, so it's easy to forget about it. If the daemon is holding onto unsaved work, it may take a while until the user realizes this. By prompting to save *all* the user's work before closing the last client, it's much harder to make this mistake.

*** Cons

This behavior makes it more difficult for a user to know ahead of time whether `save-buffers-kill-terminal' (bound by default to `C-x C-c') will kill the client or Emacs entirely. The prompt mentioned above in `server-kill-emacs-query-function' does let the user bail out though, if they didn't mean to kill Emacs entirely.

However, `save-buffers-kill-terminal' already has this complexity (almost), since it will kill Emacs entirely when executed from a non-client frame. That said, it's possible to tell what will happen in this case by looking at the mode line: if it starts with something like "U:@---", it's a client frame and thus an observant user will know what `save-buffers-kill-terminal' will do.

* Delayed Shutdown

It may also be worth considering whether the Emacs daemon should be stopped immediately when the conditions are met, or whether it would be better to delay it by a short time. Some operations, such as `git rebase -i', can open the $EDITOR, close it, and then reopen it in rapid succession. In a case like that, it would be more efficient if the Emacs daemon weren't stopped right away.

That said, I don't think this is a critical problem, and believe it would be ok to decide what to do about this later.

* Current Behaviors

Currently, Emacs 29 supports Implicit Shutdown (called `empty') and has two slightly-different variations on Explicit Shutdown (called `kill-terminal' and `delete-frame'). `empty' is implemented as a timer that periodically calls `server-stop-automatically--maybe-kill-emacs' to check if there's any need to keep the daemon running (non-daemon frames, unsaved files, or running processes); if not, it stops the daemon. This differs very slightly from the proposed spec above, since it checks for frames, not active clients. Some clients (e.g. `emacsclient --eval FOO') don't create any frames, so it may be useful to enhance the current implementation of Implicit Shutdown to account for this.

`kill-terminal' is implemented in `server-stop-automatically--handle-delete-frame' (called by `server-save-buffers-kill-terminal'). It first deletes all frames associated with the current client *except* the current one. Then, if there are any non-daemon frames aside from the current one, it just deletes that frame; if it's the last non-daemon frame, it calls `save-buffers-kill-emacs'.

`delete-frame' works like `kill-terminal' above, but will also call `save-buffers-kill-emacs' when closing the last non-daemon frame using other means, such as clicking the "X" in the frame's title bar on a GUI system.

As mentioned above, `kill-terminal' and `delete-frame' work similarly to the Explicit Shutdown behavior, but there are some differences. For example, when killing a non-last client, `kill-terminal' and `delete-frame' don't prompt to save files passed to `emacsclient'. When killing the last client, they delete all the non-current frames before calling `save-buffers-kill-emacs', meaning that pressing `C-g' to cancel when prompted will still result in all but one frame going away.





reply via email to

[Prev in Thread] Current Thread [Next in Thread]