Quick persistent scratch buffers
Emacs has a feature where you can quickly open a buffer to paste or
keep text temporarily. It can be done by calling
typing out any name and pressing return. If a buffer with such a name
exists it shows up, otherwise an empty buffer with no associated file
is created. I discovered this accidentally years ago and have been
using this feature a lot since.
The problem with this is that the buffers created only last till your emacs session lasts. If you exit emacs, these temporary buffers die with it.
Emacs also starts up with a
*scratch* buffer which, like a temporary
buffer, is not associated with a file and can be used to quickly jot
down some text. This again has the same fate of other temporary
buffers if we exit emacs. The content on closing emacs is lost and you
start with a new blank scratch on the next startup.
A package called persistent-scratch seemed to have solved this problem by saving the scratch buffer every time you kill emacs. I’ve been using it for some time to persist my scratch across sessions but have recently realized that it can work with any temporary buffer.
The key here is the
variable that can hold any custom function that can be used to match
up a file name for the package to auto save.
I added a function that does exactly this. All temporary buffers starting
*scratch: are treated as candidates for getting persisted. The
function is a one liner and is as follows
(defun persistent-scratch-buffer-identifier() (string-match "^*scratch:" (buffer-name)))
I also added a few utility functions that enhance the experience of quickly opening up a new scratch buffer with persistent-scratch-mode enabled. On pressing a key mapped to a command a prompt auto completes for the available prompts to open an existing scratch buffer or suggests a new scratch with a randomly named buffer. A custom name could be entered if required.
It works by getting a list of scratches from here
(defun persistent-scratch-get-scratches() (let ((scratch-buffers) (save-data (read (with-temp-buffer (let ((coding-system-for-read 'utf-8-unix)) (insert-file-contents persistent-scratch-save-file)) (buffer-string))))) (dolist (saved-buffer save-data) (push (substring (aref saved-buffer 0) (length "*scratch:")) scratch-buffers)) scratch-buffers))
and uses it to quickly open a scratch buffer
(defun persistent-scratch-quick-open() (interactive) (let* ((scratch-buffers (persistent-scratch-get-scratches)) (chosen-scratch (concat "*scratch:" (completing-read "Choose a scratch: " scratch-buffers nil nil nil nil (random-alnum 4)))) (buffer-exists-p (get-buffer chosen-scratch))) (pop-to-buffer chosen-scratch) (unless buffer-exists-p (persistent-scratch-restore-this)) (persistent-scratch-mode)))
It uses a new function
persistent-scratch-restore-this to restore the
content of only that particular buffer if it was originally not open.
The contents for this is completely same as the
persistent-scratch-restore in the package.
The only difference being that this limits the restoration to only one buffer unlike the original implementation which replaces the content for all overriding any unsaved changes for other buffers.
Here’s the relevant portion of the code
(defun persistent-scratch-restore-this(&optional file) (interactive) ;; ... (dolist (saved-buffer save-data) (when (string= current-buf (aref saved-buffer 0)) (with-current-buffer (get-buffer-create (aref saved-buffer 0)) ;; ...
Full code can be found here. It uses a function(
to generate random name for the buffer from here.