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

A Few Buffer--Related Functions

In this chapter we study in detail several of the functions used in GNU Emacs. This is called a "walk-through". These functions are used as examples of Lisp code, but are not imaginary examples; with the exception of the first, simplified function definition, these functions show the actual code used in GNU Emacs. You can learn a great deal from these definitions. The functions described here are all related to buffers. Later, we will study other functions.

Finding More Information

In this walk-through, I will describe each new function as we come to it, sometimes in detail and sometimes briefly. If you are interested, you can get the full documentation of any Emacs Lisp function at any time by typing C-h f and then the name of the function (and then RET). Similarly, you can get the full documentation for a variable by typing C-h v and then the name of the variable (and then RET).

Also, if you want to see a function in its original source file, you can use the find-tags function to jump to it. Type M-. (i.e., type the META and the period key at the same time, or else type the ESC key and then type the period key), and then, at the prompt, type in the name of the function whose source code you want to see, such as mark-whole-buffer, and then type RET. Emacs will switch buffers and display the source code for the function on your screen. To switch back to this buffer, type C-x b RET.

Depending on how the initial default values of your copy of Emacs are set, you may also need to specify a `tags table', which is a file called `TAGS'. The one you will most likely want to specify is in the `emacs/src' directory; thus you would use the M-x visit-tags-table command and specify a pathname such as `/usr/local/lib/emacs/19.23/src/TAGS'. See section `Tag Tables' in The GNU Emacs Manual. Also, see section Create Your Own `TAGS' File, for how to create your own.

After you become more familiar with Emacs Lisp, you will find that you will frequently use find-tags to navigate your way around source code; and you will create your own `TAGS' tables.

Incidentally, the files that contain Lisp code are conventionally called libraries. The metaphor is derived from that of a specialized library, such as a law library or an engineering library, rather than a general library. Each library, or file, contains functions that relate to a particular topic or activity, such as `abbrev.el' for handling abbreviations and other typing shortcuts, and `help.el' for on-line help. (Sometimes several libraries provide code for a single activity, as the various `rmail...' files provide code for reading electronic mail.) In The GNU Emacs Manual, you will see sentences such as "The C-h p command lets you search the standard Emacs Lisp libraries by topic keywords."

A Simplified beginning-of-buffer Definition

The beginning-of-buffer command is a good function to start with since you are likely to be familiar with it and it is easy to understand. Used as an interactive command, beginning-of-buffer moves the cursor to the beginning of the buffer, leaving the mark at the previous position. It is generally bound to M-<.

In this section, we will discuss a shortened version of the function that shows how it is most frequently used. This shortened function works as written, but it does not contain the code for a complex option. In another section, we will describe the entire function. (See section Complete Definition of beginning-of-buffer.)

Before looking at the code, let's consider what the function definition has to contain: it must include an expression that makes the function interactive so it can be called by typing M-x beginning-of-buffer or by typing a keychord such as C-<; it must include code to leave a mark at the original position in the buffer; and it must include code to move the cursor to the beginning of the buffer.

Here is the complete text of the shortened version of the function:

(defun simplified-beginning-of-buffer ()
  "Move point to the beginning of the buffer; 
leave mark at previous position."
  (interactive)
  (push-mark)
  (goto-char (point-min)))

Like all function definitions, this definition has five parts following the special form defun:

  1. The name: in this case, simplified-beginning-of-buffer.
  2. A list of the arguments: in this case, an empty list, (),
  3. The documentation string.
  4. The interactive expression.
  5. The body.

In this function definition, the argument list is empty; this means that this function does not require any arguments. (When we look at the definition for the complete function, we will see that it may be passed an optional argument.)

The interactive expression tells Emacs that the function is intended to be used interactively. In this case, interactive does not have an argument because simplified-beginning-of-buffer does not require one.

The body of the function consists of the two lines:

(push-mark)
(goto-char (point-min))

The first of these lines is the expression, (push-mark). When this expression is evaluated by the Lisp interpreter, it sets a mark at the current position of the cursor, wherever that may be. The position of this mark is saved in the mark ring.

The next line is (goto-char (point-min)). This expression jumps the cursor to the minimum point in the buffer, that is, to the beginning of the buffer (or to the beginning of the accessible portion of the buffer if it is narrowed. See section Narrowing and Widening.)

The push-mark command sets a mark at the place where the cursor was located before it was moved to the beginning of the buffer by the (goto-char (point-min)) expression. Consequently, you can, if you wish, go back to where you were originally by typing C-x C-x.

That is all there is to the function definition!

When you are reading code such as this and come upon an unfamiliar function, such as goto-char, you can find out what it does by using the describe-function command. To use this command, type C-h f and then type in the name of the function and press RET. The describe-function command will print the function's documentation string in a `*Help*' window. For example, the documentation for goto-char is:

One arg, a number.  Set point to that number.
Beginning of buffer is position (point-min),
end is (point-max).

(The prompt for describe-function will offer you the symbol preceding the cursor, so you can save typing by positioning the cursor right after the function and then typing C-h f RET.)

The end-of-buffer function definition is written in the same way as the beginning-of-buffer definition except that the body of the function contains the expression (goto-char (point-max)) in place of (goto-char (point-min)).

The Definition of mark-whole-buffer

The mark-whole-buffer function is no harder to understand than the simplified-beginning-of-buffer function. In this case, however, we will look at the complete function, not a shortened version.

The mark-whole-buffer function is not as commonly used as the beginning-of-buffer function, but is useful nonetheless: it marks a whole buffer as a region by putting point at the beginning and a mark at the end of the buffer. It is generally bound to C-x h.

The code for the complete function looks like this:

(defun mark-whole-buffer ()
  "Put point at beginning and mark at end of buffer."
  (interactive)
  (push-mark (point))
  (push-mark (point-max))
  (goto-char (point-min)))

Like all other functions, the mark-whole-buffer function fits into the template for a function definition. The template looks like this:

(defun name-of-function (argument-list)
  "documentation..."
  (interactive-expression...)
  body...)

Here is how the function works: the name of the function is mark-whole-buffer; it is followed by an empty argument list, `()', which means that the function does not require arguments. The documentation comes next.

The next line is an (interactive) expression that tells Emacs that the function will be used interactively. These details are similar to the simplified-beginning-of-buffer function described in the previous section.

Body of mark-whole-buffer

The body of the mark-whole-buffer function consists of three lines of code:

(push-mark (point))
(push-mark (point-max))
(goto-char (point-min))

The first of these lines is the expression, (push-mark (point)).

This line does exactly the same job as the first line of the body of the simplified-beginning-of-buffer function, which is written (push-mark). In both cases, the Lisp interpreter sets a mark at the current position of the cursor.

I don't know why the expression in mark-whole-buffer is written (push-mark (point)) and the expression in beginning-of-buffer is written (push-mark). Perhaps whoever wrote the code did not know that the argument for push-mark is optional and that if push-mark is not passed an argument, the function automatically sets mark at the location of point by default. Or perhaps the expression was written so as to parallel the structure of the next line. In any case, the line causes Emacs to determine the position of point and set a mark there.

The next line of mark-whole-buffer is (push-mark (point-max)). This expression sets a mark at the point in the buffer that has the highest number. This will be the end of the buffer (or, if the buffer is narrowed, the end of the accessible portion of the buffer. See section Narrowing and Widening, for more about narrowing.) After this mark has been set, the previous mark, the one set at point, is no longer set, but Emacs remembers its position, just as all other recent marks are always remembered. This means that you can, if you wish, go back to that position by typing C-u C-SPC twice.

Finally, the last line of the function is (goto-char (point-min))). This is written exactly the same way as it is written in beginning-of-buffer. The expression moves the cursor to the minimum point in the buffer, that is, to the beginning of the buffer (or to the beginning of the accessible portion of the buffer). As a result of this, point is placed at the beginning of the buffer and mark is set at the end of the buffer. The whole buffer is, therefore, the region.

The Definition of append-to-buffer

The append-to-buffer command is very nearly as simple as the mark-whole-buffer command. What it does is copy the region (that is, the part of the buffer between point and mark) from the current buffer to a specified buffer.

The append-to-buffer command uses the insert-buffer-substring function to copy the region. insert-buffer-substring is described by its name: it takes a string of characters from part of a buffer, a "substring", and inserts them into another buffer. Most of append-to-buffer is concerned with setting up the conditions for insert-buffer-substring to work: the code must specify both the buffer to which the text will go and the region that will be copied. Here is the complete text of the function:

(defun append-to-buffer (buffer start end)
  "Append to specified buffer the text of the region.
It is inserted into that buffer before its point.

When calling from a program, give three arguments:
a buffer or the name of one, and two character numbers
specifying the portion of the current buffer to be copied."
  (interactive "BAppend to buffer: \nr")
  (let ((oldbuf (current-buffer)))
    (save-excursion
      (set-buffer (get-buffer-create buffer))
      (insert-buffer-substring oldbuf start end))))

The function can be understood by looking at it as a series of filled-in templates.

The outermost template is for the function definition. In this case, it looks like this (with several slots filled in):

(defun append-to-buffer (buffer start end)
  "documentation..."
  (interactive "BAppend to buffer: \nr")
  body...)

The first line of the function includes its name and three arguments. The arguments are the buffer to which the text will be copied, and the start and end of the region in the current buffer that will be copied.

The next part of the function is the documentation, which is clear and complete.

The append-to-buffer Interactive Expression

Since the append-to-buffer function will be used interactively, the function must have an interactive expression. (For a review of interactive, see section Make a Function Interactive.) The expression reads as follows:

(interactive "BAppend to buffer: \nr")

This expression has an argument inside of quotation marks and that argument has two parts, separated by `\n'.

The first part is `BAppend to buffer: '. Here, the `B' tells Emacs to ask for the name of the buffer that will be passed to the function. Emacs will ask for the name by prompting the user in the minibuffer, using the string following the `B', which is the string `Append to buffer: '. Emacs then binds the variable buffer in the function's argument list to the specified buffer.

The newline, `\n', separates the first part of the argument from the second part. It is followed by an `r' that tells Emacs to bind the two arguments that follow the symbol buffer in the function's argument list (that is, start and end) to the values of point and mark.

The Body of append-to-buffer

The body of the append-to-buffer function begins with let.

As we have seen before (see section let), the purpose of a let expression is to create and give initial values to one or more variables that will only be used within the body of the let. This means that such a variable will not be confused with any variable of the same name outside the let expression.

We can see how the let expression fits into the function as a whole by showing a template for append-to-buffer with the let expression in outline:

(defun append-to-buffer (buffer start end)
  "documentation..."
  (interactive "BAppend to buffer: \nr")
  (let ((variable value))
        body...)

The let expression has three elements:

  1. The symbol let;
  2. A varlist containing, in this case, a single two-element list, (variable value);
  3. The body of the let expression.

In the append-to-buffer function, the varlist looks like this:

(oldbuf (current-buffer))

In this part of the let expression, the one variable, oldbuf, is bound to the value returned by the (current-buffer) expression. The variable, oldbuf, is used to keep track of the buffer in which you are working.

The element or elements of a varlist are surrounded by a set of parentheses so the Lisp interpreter can distinguish the varlist from the body of the let. As a consequence, the two-element list within the varlist is surrounded by circumscribing set of parentheses. The line looks like this:

(let ((oldbuf (current-buffer)))
  ... )

The two parentheses before oldbuf might surprise you if you did not realize that the first parenthesis before oldbuf marks the boundary of the varlist and the second parenthesis marks the beginning of the two-element list, (oldbuf (current-buffer)).

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 functions definitions use let, save-excursion, and set-buffer this way.

Review

Here is a brief summary of the various functions discussed in this chapter.

describe-function
describe-variable
Print the documentation for a function or variable. Conventionally bound to C-h f and C-h v.
find-tag
Find the file containing the source for a function or variable and switch buffers to it, positioning point at the beginning of the item. Conventionally bound to M-. (that's a period following the META key).
save-excursion
Save the location of point and mark and restore their values after the arguments to save-excursion have been evaluated. Also, remember the current buffer and return to it.
push-mark
Set mark at a location and record the value of the previous mark on the mark ring. The mark is a location in the buffer that will keep its relative position even if text is added to or removed from the buffer.
goto-char
Set point to the location specified by the value of the argument, which can be a number, a marker, or an expression that returns the number of a position, such as (point-min).
insert-buffer-substring
Copy a region of text from a buffer that is passed to the function as an argument and insert the region into the current buffer.
mark-whole-buffer
Mark the whole buffer as a region. Normally bound to C-x h.
set-buffer
Switch the attention of Emacs to another buffer, but do not change the window being displayed. Used when the program rather than a human is to work on a different buffer.
get-buffer-create
get-buffer
Find a named buffer or create one if a buffer of that name does not exist. The get-buffer function returns nil if the named buffer does not exist.

Exercises


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