Go to the first, previous, next, last section, table of contents.


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 locations of point and mark, and restores them to those positions 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 two 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 (get-buffer-create 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 two expressions. The body looks like this:

(set-buffer (get-buffer-create buffer))
(insert-buffer-substring oldbuf start end)

When the append-to-buffer function is evaluated, the two expressions in the body of the save-excursion are evaluated in sequence. The value of the last expression is returned as the value of the save-excursion function; the other expression is evaluated only for its side effects.

The first line in the body of the save-excursion uses the set-buffer function to change the current buffer to the one specified in the first argument to append-to-buffer. (Changing the buffer is the side effect; as we have said before, in Lisp, a side effect is often the primary thing we want.) The second line does the primary work of the function.

The set-buffer function changes Emacs' attention to the buffer to which the text will be copied and from which save-excursion will return. The line looks like this:

(set-buffer (get-buffer-create buffer))

The innermost expression of this list is (get-buffer-create buffer). This expression uses the get-buffer-create function, which either gets the named buffer, or if it does not exist, creates one with the given name. This means you can use append-to-buffer to put text into a buffer that did not previously exist.

get-buffer-create also keeps set-buffer from getting an unnecessary error: set-buffer needs a buffer to go to; if you were to specify a buffer that does not exist, Emacs would baulk. Since get-buffer-create will create a buffer if none exists, set-buffer is always provided with a buffer.

The last line of append-to-buffer does the work of appending the text:

(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 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.


Go to the first, previous, next, last section, table of contents.