save-excursion
in append-to-buffer
The body of the let
expression in append-to-buffer
consists of a save-excursion
expression.
The save-excursion
function saves the location of point, and restores it
to that position after the expressions in the
body of the save-excursion
complete execution. In addition,
save-excursion
keeps track of the original buffer, and
restores it. This is how save-excursion
is used in
append-to-buffer
.
Incidentally, it is worth noting here that a Lisp function is normally
formatted so that everything that is enclosed in a multi-line spread is
indented more to the right than the first symbol. In this function
definition, the let
is indented more than the defun
, and
the save-excursion
is indented more than the let
, like
this:
(defun … … … (let… (save-excursion …
This formatting convention makes it easy to see that the lines in
the body of the save-excursion
are enclosed by the parentheses
associated with save-excursion
, just as the
save-excursion
itself is enclosed by the parentheses associated
with the let
:
(let ((oldbuf (current-buffer))) (save-excursion … (set-buffer …) (insert-buffer-substring oldbuf start end) …))
The use of the save-excursion
function can be viewed as a process
of filling in the slots of a template:
(save-excursion first-expression-in-body second-expression-in-body … last-expression-in-body)
In this function, the body of the save-excursion
contains only
one expression, the let*
expression. You know about a
let
function. The let*
function is different. It
enables Emacs to set each variable in its varlist in sequence, one
after another; such that variables in the latter part of the varlist
can make use of the values to which Emacs set variables earlier in the
varlist.
Looking at the let*
expression in append-to-buffer
:
(let* ((append-to (get-buffer-create buffer)) (windows (get-buffer-window-list append-to t t)) point) BODY...)
we see that append-to
is bound to the value returned by the
(get-buffer-create buffer)
. On the next line,
append-to
is used as an argument to
get-buffer-window-list
; this would not be possible with the
let
expression. Note that point
is automatically bound
to nil
, the same way as it would be done in the let
statement.
Now let’s focus on the functions set-buffer
and
insert-buffer-substring
in the body of the let*
expression.
In the old days, the set-buffer
expression was simply
(set-buffer (get-buffer-create buffer))
but now it is
(set-buffer append-to)
This is because append-to
was bound to (get-buffer-create
buffer)
earlier on in the let*
expression.
The append-to-buffer
function definition inserts text from the
buffer in which you are currently to a named buffer. It happens that
insert-buffer-substring
does just the reverse—it copies text
from another buffer to the current buffer—that is why the
append-to-buffer
definition starts out with a let
that
binds the local symbol oldbuf
to the value returned by
current-buffer
.
The insert-buffer-substring
expression looks like this:
(insert-buffer-substring oldbuf start end)
The insert-buffer-substring
function copies a string
from the buffer specified as its first argument and inserts the
string into the present buffer. In this case, the argument to
insert-buffer-substring
is the value of the variable created
and bound by the let
, namely the value of oldbuf
, which
was the current buffer when you gave the append-to-buffer
command.
After insert-buffer-substring
has done its work,
save-excursion
will restore the action to the original buffer
and append-to-buffer
will have done its job.
Written in skeletal form, the workings of the body look like this:
(let (bind-oldbuf
-to-value-of-current-buffer
) (save-excursion ; Keep track of buffer. change-buffer insert-substring-from-oldbuf
-into-buffer) change-back-to-original-buffer-when-finished let-the-local-meaning-of-oldbuf
-disappear-when-finished
In summary, append-to-buffer
works as follows: it saves the
value of the current buffer in the variable called oldbuf
. It
gets the new buffer (creating one if need be) and switches Emacs’s
attention to it. Using the value of oldbuf
, it inserts the
region of text from the old buffer into the new buffer; and then using
save-excursion
, it brings you back to your original buffer.
In looking at append-to-buffer
, you have explored a fairly
complex function. It shows how to use let
and
save-excursion
, and how to change to and come back from another
buffer. Many function definitions use let
,
save-excursion
, and set-buffer
this way.