eintr: append save-excursion
4.4.3 ‘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 has a ‘*’ in its name. It enables
Emacs to set each variable in its varlist in sequence, one after
another.
Its critical feature is that variables later in the varlist can make
use of the values to which Emacs set variables earlier in the varlist.
The ‘let*’ expression fwd-para let.
We will skip functions like ‘let*’ and focus on two: the ‘set-buffer’
function and the ‘insert-buffer-substring’ function.
In the old days, the ‘set-buffer’ expression was simply
(set-buffer (get-buffer-create buffer))
but now it is
(set-buffer append-to)
‘append-to’ is bound to ‘(get-buffer-create buffer)’ earlier on in the
‘let*’ expression. That extra binding would not be necessary except for
that ‘append-to’ is used later in the varlist as an argument to
‘get-buffer-window-list’.
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’ copies text from another buffer to the current
buffer, just the reverse—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.