A Quick Elisp Tutorial
Emacs has a handy, but sometimes decried, feature called the "scratch" buffer. This is a special buffer which is created upon startup and allows the user to type in and evaluate Emacs Lisp code. Handy for editing tasks too specific (or not useful enough) to put into an function and handy for exploratory Emacs Lisp interactive development (although this development is just as easily accomplished in any file in Lisp mode).
One problem with
*scratch* is that its tempting to put significant
bits of code (and other information) into it. This isn't a problem in
*scratch* isn't associated with a file, and its contents
are lost without warning when Emacs is closed. Today we'll modify the
default behavior of Emacs so that it saves the scratch buffer to a
file on exit and loads it back in on startup.
This will serve as a brief Elisp tutorial.
If you are totally new to Emacs, I'd just put the code we are about to
write directly in your
.emacs.d/init.el file. These
files are executed when emacs starts, and since we need to ensure that
our behavior happens on startup, this is a reasonable place to put
code. After years of emacs usage, your
.emacs will balloon into an
unspeakable cthonian mess, and you'll have to refactor it, but by then
you'll know what you need to for that process.
Let's start by declaring a few parameters:
(defvar persistent-scratch-filename "~/.emacs-persistent-scratch" "Location of *scratch* file contents for persistent-scratch.") (defvar persistent-scratch-backup-directory "~/.emacs-persistent-scratch-backups/" "Location of backups of the *scratch* buffer contents for persistent-scratch.")
defvar declares variables, associates them with a value (the second
term), and a doc-string (the third term). Providing a doc-string will
ensure that when these symbols appear in the result of an apropos
search, they will have a convenient description associated with them.
It also will help us out when we look at the code in 4 years. Don't forget to create these directories before trying the code! (Or, modify the code to check for their existence and create them otherwise!)
Our code is going to backup any version of the scratch contents before overwriting them, just in case something really important was hiding in there. That means we need to copy the current scratch file contents (not the contents of the scratch buffer, but the last version of it) to a backup file. That file needs to have a generated name. We'll use the date to disambiguate scratch backups:
(defun make-persistent-scratch-backup-name () "Create a filename to backup the current scratch file by concatenating PERSISTENT-SCRATCH-BACKUP-DIRECTORY with the current date and time." (concat persistent-scratch-backup-directory (replace-regexp-in-string (regexp-quote " ") "-" (current-time-string))))
Again, the initial string in the body of this function is
documentation. Emacs will show us this description when it displays
information about this function.
concat concatenates strings,
current-time-string does what you'd think, and we use
replace-regexp-in-string to remove the spaces.
produces a regular expression which matches exactly its input string
and nothing else.
Saving the Contents of
Next is our function to save the contents of the
We will eventually place this function on a "hook" which ensures it
gets run every time emacs shuts down.
(defun save-persistent-scratch () "Write the contents of *scratch* to the file name PERSISTENT-SCRATCH-FILENAME, making a backup copy in PERSISTENT-SCRATCH-BACKUP-DIRECTORY." (with-current-buffer (get-buffer "*scratch*") (if (file-exists-p persistent-scratch-filename) (copy-file persistent-scratch-filename (make-persistent-scratch-backup-name))) (write-region (point-min) (point-max) persistent-scratch-filename)))
This function needs to work with the contents of the
buffer, so it uses the special form
with-current-buffer to create a
context where actions refer to the contents of that buffer.
We then check to see whether a file containing the previous scratch
buffer is present, and if it is we use
copy-file to copy it to the
backup directory. We then use
write-region to write the contents of
(point-max) (that is, the whole
thing), to the scratch file location.
Loading the Contents of
(defun load-persistent-scratch () "Load the contents of PERSISTENT-SCRATCH-FILENAME into the scratch buffer, clearing its contents first." (if (file-exists-p persistent-scratch-filename) (with-current-buffer (get-buffer "*scratch*") (delete-region (point-min) (point-max)) (shell-command (format "cat %s" persistent-scratch-filename) (current-buffer)))))
(It has been correctly pointed out in the comments that
insert-file is the more idiomatic way of getting file contents into a buffer, which I somehow forgot about!) We first check to see whether there is a file containing the previous
session's scratch contents. If there is, we switch to the scratch
buffer context with
with-current-buffer and use
cat to insert the contents into
Hooking It All In
Since we are writing this in our
.emacs file, we can ensure that the
contents of the last session's
*scratch* are read in by simply
This will get executed on emacs startup, just as we want. We have to
do something more complicated to ensure that
is run whenever emacs exits.
To do this, we use one of emacs's many "hooks". A hook, in emacs
parlance, is a list of functions which emacs promises to run at
specific times or when specific events occur. The hook we need is
kill-emacs-hook. This hook is run whenever emacs is killed for any
We can use the special form
push, which pushes an item onto the
start of a list, to add our function.
(push #'save-persistent-scratch kill-emacs-hook)
save-persistent-scratch is preceded by a
#'. This tells
emacs that we want the function associated with the symbol
save-persistent-scratch, not the value (of which there is none
That is It!
That's it. Save this into your
.emacs and you should now have a
scratch buffer which remembers its contents between sessions. Handy!