4

problem

Lately I run GNU Emacs mostly as GUI on X/tty7 (which I'll call "the desktop" as opposed to emacs-desktop) on one of my Debian laptops. Occasionally the desktop hangs, in which case I usually can goto tty1 and sudo shutdown -[whatever] now. Unfortunately this does not cause Emacs to shut down as cleanly as I'd like: I'd like Emacs to (e.g.) save any unsaved buffers and desktop-save, but that doesn't seem to get done.

So I'm thinking that, in this usecase, I should utter something from tty1 (before shutdown) to tell Emacs to shutdown cleanly ... but I don't know what to say. How to do this?

solution

thanks

TIA and for past help to the many fine folks @ help-gnu-emacs, esp Yuri Khan for the initial suggestion and Jorge A. Alfaro-Murillo for the more important details of this solution. Special thanks to Faried Nawaz for 2 important advances that pretty-much solve the problem.

server and client

One way that WFM (not entirely without problems--see notes below) is

  1. Preparation:

1.1. Whenever you start Emacs, make it start a server instance. I did this by adding the following line to my ~/.emacs.d/init.el:

    (server-start)

1.2. Also in ~/.emacs.d/init.el, define a callable function to tell emacs to shutdown cleanly, with as few prompts as possible. Faried Nawaz recommended

    (defun my-kill-emacs ()
      "Set kill-emacs-query-functions , confirm-kill-emacs , and
    kill-emacs-hook to nil to quit emacs without any pesky prompts
    (except to save buffers)"
      (let (kill-emacs-query-functions confirm-kill-emacs kill-emacs-hook)
        (save-buffers-kill-emacs)))

1.3. Restart your emacs to be sure to incorporate your new init.el code.

  1. When you encounter tty7/desktop hang: Goto tty1, and login if not already. Then do either of the following:

2.1. manually: from bash commandline, run

emacsclient -c -a '' -e '(my-kill-emacs)'

2.2. scripted: save the above line into an executable file à la ~/bin/shutdown_Emacs_cleanly.sh and run it. E.g.:

#!/bin/sh
emacsclient -c -a '' -e '(my-kill-emacs)'

notes

  1. If your (graphical) Emacs has no unsaved buffers when you kill it (as described above), Emacs will exit with no prompts. If your Emacs has unsaved buffers when you kill it, you will get prompts (from your character-mode Emacs in tty1) to save the buffers. (Writing a function that saves all unsaved buffers without any prompts is left as an exercise for the reader :-)

  2. Whether or not you have unsaved buffers, when your tty1 commandline exits, its terminal handling may be "polluted": e.g. (and in roughly decreasing order of importance),

    • You will no longer see what you type at the bash prompt.

    • History browsing (via up/down-arrow key) also fails--at least, I cannot see anything on the commandline.

    • Hitting RET at the bash prompt no longer does a line feed, though it still produces a new prompt. This results in a display like

      me@it:~$ me@it:~$ me@it:~$ me@it:~$ me@it:~$ me@it:~$ me@it:~$ me@it:~$ me@it:~$

    My tty1 is always polluted by running the above; YMMV. Fortunately, as Nawaz points out, one can unpollute by calling reset from the tty1 commandline (after installing package=ncurses-bin).

TomRoche
  • 592
  • 3
  • 20

1 Answers1

5

When you run (server-start) it adds a function called server-kill-emacs-query-function (defined in server.el) to the kill-emacs-query-functions hook. One solution that might work for you (I've tested it and it works for me) is to modify your emacsclient line to

emacsclient -c -a '' \
-e '(let (kill-emacs-query-functions confirm-kill-emacs kill-emacs-hook) (save-buffers-kill-emacs))'

Or better yet, define a function in your .emacs or init.el and call it from emacsclient:

(defun my-kill-emacs ()
  "Set kill-emacs-query-functions , confirm-kill-emacs , and
kill-emacs-hook to nil to quit emacs without any pesky prompts
(except to save buffers)"
  (let (kill-emacs-query-functions confirm-kill-emacs kill-emacs-hook)
    (save-buffers-kill-emacs)))

Your script:

#!/bin/sh
emacsclient -c -a '' -e '(my-kill-emacs)'

If running the above messes up your terminal, just type "reset" (part of Debian package=ncurses-bin).

TomRoche
  • 592
  • 3
  • 20
Faried Nawaz
  • 191
  • 7
  • The good news: `reset` WFM, thanks! The bad news ... – TomRoche Nov 19 '15 at 21:34
  • ... currently, running `(my-kill-emacs)` from my `init.el` seems to auto-answer the "wanna kill clients?" question, since I don't see that. But I still get and must interact reply to the "wanna exit?" question (followed by terminal pollution, solved by `reset`). Dunno if this is a version problems; FWIW I currently run `GNU Emacs 24.4.1 (x86_64-pc-linux-gnu, GTK+ Version 3.14.5)`. Meanwhile, I'll try the commandlines. – TomRoche Nov 19 '15 at 21:38
  • I also still get and must reply to the "wanna exit?" question (followed by terminal pollution) with either of the commandlines `emacsclient -c -a '' -e '(my-kill-emacs)'` and `emacsclient -c -a '' -e '(let (kill-emacs-query-functions confirm-kill-emacs) (save-buffers-kill-emacs))'`. FWIW, I'm also running `lsb_release -ds`==`LMDE 2 Betsy`, `cat /etc/debian_version`==`8.2`, `uname -rv`==`3.16.0-4-amd64 #1 SMP Debian 3.16.7-ckt11-1+deb8u3 (2015-08-04)` – TomRoche Nov 19 '15 at 21:56
  • Can you see if adding `kill-emacs-hook` to the list of `let` variables fixes the problem? – Faried Nawaz Nov 20 '15 at 17:29
  • That works! Edited above (pending peer review) and I'll also edit my solution below. – TomRoche Nov 22 '15 at 05:02