autoscratch - solve the *scratch* buffer problem - Updated 17.07.2017 21:53

I use emacs for more than 20 years now. I love it, I am addicted, I can't even do anything productive without it. However, there was one problem left: the *scratch* buffer. This is a non-file buffer, which always exists always in emacs. By default it has emacs-lisp-mode enabled and you can use it to hack short elisp sexps for testing. In fact I use it for exactly this purpose.

But sometimes I hate it as well! I get a phone call and need to take a note quickly, *scratch* is already open, so I use this. But the mode doesn't really fit. So I switch to text-mode and then enter the notes. I did it this way almost since day one of my emacs usage.

A couple of months ago I came up with a "solution", I just create a *text* buffer on startup with text-mode already enabled in my .emacs. But I still need to switch to it everytime I need it. Still too annoying!

So now, here's my final solution, which tries to fix this mess once and for all: autoscratch.

This major mode is really simple. Basically it consits of an alist with instructions on how to automatically switch the *scratch* buffer mode. Enter an "(" and it switches to emacs-lisp-mode, enter "*" and it switches to org-mode, enter some letter a-z, and it switches to text-mode. You get the idea.

It also solves another problem I (and many other users according to google) have: once I set the *scratch* buffer mode to, say, *text-mode* with some text in there, I don't have an elisp *scratch* buffer left anymore. I'd need another one, but how to create a second *scratch* buffer? Obviously you'll need to rename the current text-mode buffer first and then create a new empty buffer. The emacs wiki contains lots of suggestions for this kind of solution.

No more of this! Autoscratch can just "fork" the buffer, if enabled (set autoscratch-fork-after-trigger to t which is the default). Here's how it works: type a "(" into the empty autoscratch-enabled *scratch* buffer. Autoscratch renames this buffer to *emacs-lisp-scratch*, enables emacs-lisp-mode and creates a new *scratch* buffer in the background. So, if you need some *scratch* space, it'll be there for you waiting bravely for input.

Here's the default trigger list telling autoscratch how to switch modes:

'(("[(;]"         . (emacs-lisp-mode))
  ("#"            . (autoscratch-select
                     '(("perl"   . (cperl-mode))
                       ("ruby"   . (ruby-mode))
                       ("python" . (python-mode))
                       ("conf"   . (conf-unix-mode))
                       ("shell"  . (shell-script-mode)))))
  ("[-a-zA-Z0-9]" . (text-mode))
  ("/"            . (c-mode))
  ("*"            . (progn (insert " ") (org-mode)))
  ("."            . (fundamental-mode)))

Now if you configure autoscratch like this:

(require 'autoscratch-mode)
(setq initial-major-mode 'autoscratch-mode)
(setq initial-scratch-message "")
(setq inhibit-startup-screen t)

then emacs will start with an empty *scratch* buffer as always, but with autoscratch mode enabled. Type in a "(" and emacs-lisp-mode will be started, the *scratch* buffer will be renamed and a new *scratch* created in the background. Or, type in a "#" and you'll be asked what to switch (the autoscratch-select function does this). You can configure almost anything here.

Oh, and just in case you need to manually create a new scratch buffer, just execute "M-x autoscratch-buffer".

Update 17.07.2017 21:53:

You can complete this scratch buffer setup with the great persistent-scratch.el mode. Here's my config for it:

(require 'persistent-scratch)
(setq persistent-scratch-save-file
    (expand-file-name "scratches.el" user-init-dir))

(defun tvd-autoscratch-p ()
  "Return non-nil if the current buffer is a scratch buffer"
  (string-match "scratch*" (buffer-name)))

(setq persistent-scratch-scratch-buffer-p-function 'tvd-autoscratch-p)

With this setup, scratch buffers will be saved on exit and restored on startup, so you never loose any cool snippet or note you have in a scratch buffer.