Search code examples
emacselispemacs23

Emacs - Can't get buffer-offer-save working


I would like to have Emacs ask me whether I want to save a modified buffer, when that buffer is not associated with a file. To open a new buffer (not visiting a file) I have the following function in my .emacs file:

;; Creates a new empty buffer
(defun new-empty-buffer ()
  "Opens a new empty buffer."
  (interactive)
  (let ((buf (generate-new-buffer "untitled")))
    (switch-to-buffer buf)
    (funcall (and default-major-mode))
    (setq buffer-offer-save t)))

I thought setting "buffer-offer-save" to something not nil would made the trick. But whenever I kill the buffer with "kill-this-buffer", it gets instantly killed without asking anything.

This happens on GNU Emacs 23.1.1

Any ideas?

Thanks, W


Solution

  • Edited to add use of buffers-offer-save. Note: the variable buffer-offer-save is only used upon exiting Emacs.

    You can start with this code and customize it to what you want:

    (add-to-list 'kill-buffer-query-functions 'ask-me-first)
    (defun ask-me-first ()
      "prompt when killing a buffer"
      (if (or buffer-offer-save 
              (eq this-command 'kill-this-buffer)
              (and (buffer-modified-p) (not (buffer-file-name))))
          (y-or-n-p (format "Do you want to kill %s without saving? " (buffer-name)))
        t))
    

    Upon further reflection, that is a bit heavy-handed because you get prompted for all buffers that get killed, and there are often lots of temporary buffers that Emacs uses. If you just want to be prompted when you try to interactively kill a buffer (that isn't associated with a file).

    You can use this advice which only prompts you when you're interactively trying to kill a buffer:

    (defadvice kill-buffer (around kill-buffer-ask-first activate)
      "if called interactively, prompt before killing"
      (if (and (or buffer-offer-save (interactive-p))
               (buffer-modified-p)
               (not (buffer-file-name)))
          (let ((answ (completing-read
                       (format "Buffer '%s' modified and not associated with a file, what do you want to do? (k)ill (s)ave (a)bort? " (buffer-name))
                       '("k" "s" "a")
                       nil
                       t)))
            (when (cond ((string-match answ "k")
                         ;; kill
                         t)
                        ((string-match answ "s")
                         ;; write then kill
                         (call-interactively 'write-file)
                         t)
                        (nil))
              ad-do-it)
    
            t)
        ;; not prompting, just do it
        ad-do-it))