4

I had made some random notes in my scratch buffer.
By mistake, I pressed C-x C-c and killed the Emacs session.
All my content in the scratch buffer was gone.

Question:

When I try to close Emacs when the scratch buffer had been edited, I want Emacs to ask for a confirmation (offer to save or something) before it exits the current session. How can this be done? I'm not conversant with eLisp.

I searched the manual and there seems to be no way to change this behaviour.

Not duplicate:

My question is not duplicate to the question "never close scratch" in that, the other user is referring to killing the scratch buffer intentionally using kill-buffer C-x C-k. In my case, I unexpectedly exit out of Emacs either by closing the window or giving C-x C-c command.

4
  • that's a nature of scratch buffer - it's not linked to any file. and there is no need to change it, just create normal buffer (like scratch.el or something) and when you try exit emacs, you will be asked as usual what to do with changes.
    – rsm
    Nov 2, 2017 at 14:02
  • Possible duplicate of never close scratch
    – Drew
    Nov 2, 2017 at 14:48
  • @Drew It may not be a duplicate in that, I would not be killing the scratch buffer individually, but quiting Emacs kills it (even if modified,without warnings). All I'm looking for is a way, in which, Emacs informs the user that scratch buffer is modified and request for save if needed
    – Prasanna
    Nov 2, 2017 at 17:02
  • This is not an answer to your question, but it is generally a good idea to have a safeguard against inadvertently quitting emacs. The first sexp sets a short form of answering to all confirmation requests. Add these to your emacs config: (fset 'yes-or-no-p 'y-or-n-p) (setq confirm-kill-emacs 'y-or-n-p)
    – Heikki
    Nov 3, 2017 at 7:12

4 Answers 4

2

persistent-scratch is another package which saves and restores the contents of the *scratch* buffer. The following is a possible setup.

(use-package persistent-scratch
  :ensure t
  :commands persistent-scratch-setup-default
  :hook (after-init . persistent-scratch-setup-default))
1
  • 1
    This is what i was looking for. Thank you!
    – Prasanna
    Jan 23, 2021 at 17:12
2

This is a commonly asked question. It might be a duplicate here (dunno). There are various tweaks or libraries that some users use to provide what you are asking - you will likely get some answers pointing to them.

But my suggestion is to not use *scratch* the way you are using it - maybe not use it at all. Instead, use C-x C-f foo.el or whatever, which tells Emacs that you might want to save whatever you're doing in that buffer. Emacs will also automatically save your work periodically after you do save it, if you do. And you need not save if you don't ever want to.

IOW, you get all of the liberty of buffer *scratch* (throw it away when done), but with the advantage that Emacs will do just what you requested: let you know before you exit that you have unsaved changes in that buffer. And you can put the buffer in any mode you like - it need not be emacs-lisp-mode. And emacs-lisp-mode gives you as much Lisp support as the default mode for *scratch* provides (in my opinion).

*scratch* really is for stuff that you intend to toss.

10
  • 1
    "*scratch* really is for stuff that you intend to toss." Couldn't agree more. But I use it like scratch pad to keep a temporary copy of things, before they get better shape and go into some file. I don't want to lose it before my work is done - because of a mistake. I will have to resort to creating an extra file (foo), if I don't get a good solution
    – Prasanna
    Nov 2, 2017 at 17:09
  • No, you don't have to "resort to creating an extra file (foo). That's the point. Use C-x C-f foo.el and never bother to save your scratch work to disk. (You can even have Emacs create such a buffer for you by default.) Because you visit it as a file buffer, even though there is no file backing it up, Emacs will let you know that your work is not saved when you kill the buffer or you quit Emacs. This is the Emacs Way. Your habit of using *scratch* and expecting Emacs to warn you about not saving your work is a bad habit - nothing more.
    – Drew
    Nov 2, 2017 at 17:31
  • 1
    Got it. Just now I tried it. Good idea and it would work for me. Edited you answer as there was a missing "C". To make up for the edit requirements - i had to change -IMHO to in my opinion
    – Prasanna
    Nov 2, 2017 at 17:47
  • @ocodo: How is my comment, or my answer, "out of order here"? I mention an alternative to "persistent scratch", one that I and many others use, and have done so reliably for decades. It gives you all of the advantages I cited: appropriate mode, confirmation to save, etc. If you really want a lisp-interaction-mode buffer where you'll be prompted to save your work, then use C-x f with a file suffix that automatically gives you that mode. Simple, fail-safe. No one is arguing against "mistakes/outages happen and safety nets are good." Emacs has taken care of that concern since Day One.
    – Drew
    Sep 17, 2022 at 16:59
  • @Drew maybe I misread what you were suggesting. I thought you meant to open a file, manually, every time you start Emacs.
    – ocodo
    Sep 18, 2022 at 1:08
2

You could use the (bundled) savehist package to save and restore the scratch contents:

(use-package savehist
  :init
  (savehist-mode)
  :config
  (defun my-savehist-scratch ()
    (with-current-buffer (startup--get-buffer-create-scratch)
      (setq initial-scratch-message (buffer-string))))
  (add-hook 'savehist-save-hook #'my-savehist-scratch)
  (add-to-list 'savehist-additional-variables 'initial-scratch-message))

then you don't have to worry about it being killed, it'll be saved in ~/.emacs.d/history anyway.

EDIT: Thanks Y.E. for mentioning that this package will also give you persistent minibuffer histories (e.g. regex replaces, occur's and so on). I was already using savehist for that, but if you don't want to save minibuffer histories you may want to find a different solution.

4
  • 2
    Thank you for this idea, I really liked it and it works fine for the OP question case (preserve *\scratch* contents on Emacs kill). Though there's one nuance that I cannot ignore: (savehist-mode) field of concern is saving minibuffer history, so it's like solving a task with a tool that's not purposed for the task (not restricted by itself if it works of course, but still might lead to some clashes/inconsistencies in future). I hope this doesn't sound too oppositional, my intention is to mention this nuance, that's it.
    – Y. E.
    Sep 7, 2021 at 6:40
  • In emacs 29 it's probably easier to just define-multisession-variable my-savehist-scratch
    – unhammer
    Sep 19, 2022 at 9:27
  • more context on define-multisession-variable (in Emacs 29)?
    – Y. E.
    Sep 19, 2022 at 16:41
  • 1
0

After trying many different approaches I tend to agree that the accepted answer to the mentioned never close scratch is a way to go and may be adapted to the topic of this question too.

So, in my configuration I currently use this approach to ask for confirmation before killing Emacs or *scratch* buffer, if the latter is not empty:


;; Prompts on non-empty *scratch* buffer.
(defun yet-prompt-on-not-empty-scratch-buffer (question)
  "Prompt if *scratch* buffer is not empty.
Appends a confirmation QUESTION to the prompt message.
If *scratch* buffer is empty, returns true without prompting."
  (let ((scratch (get-buffer "*scratch*")))
    (if (and scratch (> (buffer-size scratch) 0))
        (y-or-n-p (format (concat
                           "Warning: *scratch* buffer is not empty. "
                           question)))
      t)))


;; Call prompting function on Emacs kill. 
(defun yet-verify-emtpy-scratch-on-emacs-kill ()
  "Require confirmation to kill Emacs if *scratch* buffer is not empty."
  (yet-prompt-on-not-empty-scratch-buffer "Really kill Emacs?"))

(add-to-list 'kill-emacs-query-functions
             #'yet-verify-emtpy-scratch-on-emacs-kill)


;; Call prompting function on a buffer kill.
(defun yet-verify-emtpy-scratch-on-buffer-kill ()
  "Require confirmation to kill *scratch* buffer if it is not empty."
  (if (equal "*scratch*" (buffer-name))
      (yet-prompt-on-not-empty-scratch-buffer "Really kill *scratch* buffer?")
    t))

(add-to-list 'kill-buffer-query-functions
             #'yet-verify-emtpy-scratch-on-buffer-kill)


Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.