I tend to use often non-file buffers kinda like post-it-notes and it is way too easy to kill them inadvertently, as there is no confirmation to kill. Even if you enforce the habit of writing only in file buffers (subject to confirmation), you might still inadvertently write in a non-file buffer.
Therefore, I created a kill-hook to ask kill confirmation, but only for buffers that I created (setting global buffer-offer-save
would make Emacs unusable). To identify user buffers, I exploit the fact that the name of buffers created automatically starts with a star.
Now, given its prominence, I would like to use the *scratch*
buffer as a note taking buffer too.
In this case, to fit the Emacs naming convention, I need to rename it scratch
(or anyway something without the star).
I see two possibilities:
I prevent its creation: in the kill hook I check if I am going to kill the last buffer and create my
scratch
, to prevent the creation of Emacs'*scratch*
.I look for a create create-scratch-buffer hook and rename the scratch here.
As for point 1, (length (list-buffers))
includes also so called non-interesting (hidden) buffers and I would happily avoid to parse names with regexp on every hook call (to detect interesting buffers).
As for point 2, how can I detect the scratch buffer creation? Perhaps with a mode hook, e.g. something like:
(add-hook 'after-change-major-mode-hook 'rename-scratch)
My actual kill hook follows.
(add-to-list 'kill-buffer-query-functions 'ask-before-killing-user-buffer)
(defun ask-before-killing-user-buffer ()
"If the current buffer is a user buffer, ask for saving before killing.
Here a user buffer is one not: associated to a file, belonging to a process or auto-created by Emacs.
The latter are considered such when starting with the usual `*'.
The proposed filename will not be accepted if any buffer is already visiting the file"
(interactive)
(let* (save-name visited-by exit-while-p
(ask "Save file as: ")
(buffer (current-buffer))
(buffer-name (buffer-name))
(user-buff-p (if (or (string-match "^ \\|\\*" buffer-name)
(get-buffer-process buffer)
(buffer-file-name)) nil t)))
;; Ask to save modified buffer
(if (and user-buff-p (buffer-modified-p))
(if (y-or-n-p (format "`%s' was modified; save it? " buffer-name))
(progn
;; accept only non visited file names
(setq default-directory DEFAULT-SAVE-DIR)
(while (not exit-while-p)
(setq save-name (file-truename (read-file-name ask nil nil nil buffer-name)))
(setq visited-by (find-buffer-visiting save-name))
(if visited-by
(setq ask (format "`%s' is being visited by buffer `%s'.\nPlease choose another name: "
save-name (buffer-name visited-by)))
(setq exit-while-p t)))
(write-file save-name t))))
t))
UPDATE
Try to answer to your comments, clarifiying what I am willing to achieve.
I have a shortcut creating buffers named scratch1
, scratch2
, etc to readily copy snippets from web pages or from ebooks, to type a nearby task, the draft of an email, etc. Normally these are ephemeral buffers never translating into files, they live until the text snippets are copied in actual documents (but occasionally the buffer is edited and saved). Important original material gets immediately the status of file-buffer (with the related backup facilities); it is anyway unpleasant to accidentally kill my scratches, despite I can recover them going on the source web page, ebook etc. Just like it is not crucial to lose your remember-the-milk notes, but ...
Currently using a mode hook seems to me a solution without to much overhead:
(defun rename-scratch-buffer ()
(if (and (get-buffer "*scratch*") (not (get-buffer "scratch")))
(with-current-buffer "*scratch*" (rename-buffer "scratch"))))
(add-hook 'after-change-major-mode-hook 'rename-scratch-buffer)
user-buff-p
along the lines of(not (string= "*scratch*" (buffer-name)))
?C-x 4 f foo.txt
instead ofC-x 4 b foo
then you get what you want, no? And you can of course setauto-mode-alist
to give you whatever mode you want for such buffers. The buffers are not written to disk unless you explicitly do so. So what's the problem?*scratch*
toscratch
, you can do so viaafter-init-hook
, such as:(add-hook 'after-init-hook (lambda () (rename-buffer "scratch")))
.*scratch*
is one of those. What you want is a file buffer (which you never save).