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: How to find more information.
- simplified-beginning-of-buffer: Shows
goto-char
,point-min
, andpush-mark
. - mark-whole-buffer: Almost the same as
beginning-of-buffer
. - append-to-buffer: Uses
save-excursion
andinsert-buffer-substring
. - Buffer Related Review: Review.
- Buffer Exercises
4.1 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
Also, describe-function
will tell you the location of the function definition.
Put point into the name of the file that contains the function and press the push-button
rather than “return” or “enter”. Emacs will take you directly to the function definition.
More generally, if you want to see a function in its original source file, you can use the xref-find-definitions
function to jump to it. xref-find-definitions
works with a wide variety of languages, not just Lisp, and C, and it works with non-programming text as well. For example, xref-find-definitions
will jump to the various nodes in the Texinfo source file of this document (provided that you’ve run the etags utility to record all the nodes in the manuals that come with Emacs; see Create Tags Table).
To use the xref-find-definitions
command, type M-. (i.e., press the period key while holding down the key, or else type the mark-whole-buffer
, and then type
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 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.”
4.2 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 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 M-<; 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:
1 | (defun simplified-beginning-of-buffer () |
Like all function definitions, this definition has five parts following the macro defun
:
- The name: in this example,
simplified-beginning-of-buffer
. - A list of the arguments: in this example, an empty list,
()
, - The documentation string.
- The interactive expression.
- 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 example, 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:
1 | (push-mark) |
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 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 describe-function
command will print the function’s documentation string in a Help window. For example, the documentation for goto-char
is:
1 | Set point to POSITION, a number or marker. |
The function’s one argument is the desired position.
(The prompt for describe-function
will offer you the symbol under or preceding the cursor, so you can save typing by positioning the cursor right over or after the function and then typing C-h f
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))
.
4.3 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.
- mark-whole-buffer overview
- Body of mark-whole-buffer: Only three lines of code.
An overview of mark-whole-buffer
In GNU Emacs 22, the code for the complete function looks like this:
1 | (defun mark-whole-buffer () |
Like all other functions, the mark-whole-buffer
function fits into the template for a function definition. The template looks like this:
1 | (defun name-of-function (argument-list) |
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.
4.3.1 Body of mark-whole-buffer
The body of the mark-whole-buffer
function consists of three lines of code:
1 | (push-mark (point)) |
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 arguments for push-mark
are 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.
In earlier versions of GNU Emacs, the next line of mark-whole-buffer
was (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 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-
In GNU Emacs 22, the (point-max)
is slightly more complicated. The line reads
1 | (push-mark (point-max) nil t) |
The expression works nearly the same as before. It sets a mark at the highest numbered place in the buffer that it can. However, in this version, push-mark
has two additional arguments. The second argument to push-mark
is nil
. This tells the function it should display a message that says “Mark set” when it pushes the mark. The third argument is t
. This tells push-mark
to activate the mark when Transient Mark mode is turned on. Transient Mark mode highlights the currently active region. It is often turned off.
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.
4.4 The Definition of append-to-buffer
The append-to-buffer
command is more complex than 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.
- append-to-buffer overview
- append interactive: A two part interactive expression.
- append-to-buffer body: Incorporates a
let
expression. - append save-excursion: How the
save-excursion
works.
An Overview of append-to-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 substring from a buffer, and inserts it 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, the window it comes from and goes to, and the region that will be copied.
Here is the complete text of the function:
1 | (defun append-to-buffer (buffer 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 function, it looks like this (with several slots filled in):
1 | (defun append-to-buffer (buffer start end) |
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. As is conventional, the three arguments are written in upper case so you will notice them easily. Even better, they are described in the same order as in the argument list.
Note that the documentation distinguishes between a buffer and its name. (The function can handle either.)
4.4.1 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 Making a Function Interactive.) The expression reads as follows:
1 | (interactive |
This expression is not one with letters standing for parts, as described earlier. Instead, it starts a list with these parts:
The first part of the list is an expression to read the name of a buffer and return it as a string. That is read-buffer
. The function requires a prompt as its first argument, ‘“Append to buffer: “’. Its second argument tells the command what value to provide if you don’t specify anything.
In this case that second argument is an expression containing the function other-buffer
, an exception, and a ‘t’, standing for true.
The first argument to other-buffer
, the exception, is yet another function, current-buffer
. That is not going to be returned. The second argument is the symbol for true, t
. that tells other-buffer
that it may show visible buffers (except in this case, it will not show the current buffer, which makes sense).
The expression looks like this:
1 | (other-buffer (current-buffer) t) |
The second and third arguments to the list
expression are (region-beginning)
and (region-end)
. These two functions specify the beginning and end of the text to be appended.
Originally, the command used the letters ‘B’ and ‘r’. The whole interactive
expression looked like this:
1 | (interactive "BAppend to buffer: \nr") |
But when that was done, the default value of the buffer switched to was invisible. That was not wanted.
(The prompt was separated from the second argument with a newline, ‘\n’. It was followed by an ‘r’ that told 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. That argument worked fine.)
4.4.2 The Body of append-to-buffer
The body of the append-to-buffer
function begins with let
.
As we have seen before (see 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:
1 | (defun append-to-buffer (buffer start end) |
The let
expression has three elements:
- The symbol
let
; - A varlist containing, in this case, a single two-element list,
(
variable value)
; - The body of the
let
expression.
In the append-to-buffer
function, the varlist looks like this:
1 | (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 and from which you will copy.
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 a circumscribing set of parentheses. The line looks like this:
1 | (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))
.
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:
1 | (defun ... |
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 thesave-excursion
itself is enclosed by the parentheses associated with the let
:
1 | (let ((oldbuf (current-buffer))) |
The use of the save-excursion
function can be viewed as a process of filling in the slots of a template:
1 | (save-excursion |
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. See The let*
expression.
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
1 | (set-buffer (get-buffer-create buffer)) |
but now it is
1 | (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
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:
1 | (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 toinsert-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:
1 | (let (bind-oldbuf-to-value-of-current-buffer) |
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.
4.5 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.
xref-find-definitions
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 key).
save-excursion
Save the location of point and restore its value 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 returnsnil
if the named buffer does not exist.
4.6 Exercises
- Write your own
simplified-end-of-buffer
function definition; then test it to see whether it works. - Use
if
andget-buffer
to write a function that prints a message telling you whether a buffer exists. - Using
xref-find-definitions
, find the source for thecopy-to-buffer
function.