An Introduction To Programming in Emacs Lisp
An Introduction To Programming in Emacs Lisp
in Emacs Lisp
An Introduction to
Programming in Emacs Lisp
by Robert J. Chassell
This is An Introduction to Programming in Emacs Lisp, for people who are not
programmers.
Published by the:
ISBN 1-882114-43-4
Permission is granted to copy, distribute and/or modify this document
under the terms of the GNU Free Documentation License, Version 1.3 or
any later version published by the Free Software Foundation; there being
no Invariant Section, with the Front-Cover Texts being “A GNU Manual”,
and with the Back-Cover Texts as in (a) below. A copy of the license is
included in the section entitled “GNU Free Documentation License”.
(a) The FSF’s Back-Cover Text is: “You have the freedom to copy and
modify this GNU manual. Buying copies from the FSF supports it in
developing GNU and promoting software freedom.”
i
Short Contents
Preface............................................................ 1
1 List Processing ............................................... 1
2 Practicing Evaluation........................................ 20
3 How To Write Function Definitions........................... 26
4 A Few Buffer-Related Functions.............................. 48
5 A Few More Complex Functions.............................. 59
6 Narrowing and Widening..................................... 73
7 car, cdr, cons: Fundamental Functions ...................... 77
8 Cutting and Storing Text .................................... 85
9 How Lists are Implemented ................................. 108
10 Yanking Text Back ......................................... 113
11 Loops and Recursion........................................ 115
12 Regular Expression Searches ................................ 141
13 Counting via Repetition and Regexps ....................... 155
14 Counting Words in a defun ................................. 167
15 Readying a Graph .......................................... 187
16 Your .emacs File ........................................... 196
17 Debugging.................................................. 215
18 Conclusion ................................................. 221
A The the-the Function...................................... 223
B Handling the Kill Ring...................................... 225
C A Graph with Labeled Axes ................................ 233
D Free Software and Free Manuals............................. 254
E GNU Free Documentation License .......................... 256
Index ........................................................... 265
ii
Table of Contents
Preface .......................................................... 1
On Reading this Text....................................................... 1 For Whom This is
Written.................................................. 2
Lisp History................................................................ 3 A Note for Novices
......................................................... 3
Thank You................................................................. 4
1 List Processing.............................................. 1
1.1 Lisp Lists ............................................................. 1
1.4.1 Lisp Atoms ...................................................... 1 1.1.2 Whitespace in Lists
.............................................. 2
1.1.3 GNU Emacs Helps You Type Lists ............................... 3
1.2 Run a Program ....................................................... 3 1.3 Generate an Error
Message............................................ 4
1.5 Symbol Names and Function Definitions ............................... 6
1.6 The Lisp Interpreter................................................... 6
1.6.1 Byte Compiling .................................................. 7
1.7 Evaluation ............................................................ 8
1.7.1 Evaluating Inner Lists............................................ 8
1.8 Variables.............................................................. 9
1.8.1 Error Message for a Symbol Without a Function................. 10
1.8.2 Error Message for a Symbol Without a Value.................... 10
1.9 Arguments........................................................... 11
1.9.1 Arguments’ Data Types......................................... 12 1.8.2 An Argument as
the Value of a Variable or List ................. 12
1.8.3 Variable Number of Arguments.................................. 13
1.8.4 Using the Wrong Type Object as an Argument .................. 13
1.8.5 The message Function .......................................... 14
1.10 Setting the Value of a Variable ....................................... 16
1.10.1 Using setq...................................................... 16 1.9.2 Counting
....................................................... 17
1.11 Summary ........................................................... 18
1.12 Exercises............................................................ 19
17 Debugging............................................... 215
17.1 debug.............................................................. 215
17.2 debug-on-entry................................................... 216
17.3 debug-on-quit and (debug)....................................... 218
17.4 The edebug Source Level Debugger ................................ 218
17.5 Debugging Exercises ............................................... 220
18 Conclusion............................................... 221
viii
Index.......................................................... 265
On Reading this Text 1
Preface
Most of the GNU Emacs integrated environment is written in the programming
language called Emacs Lisp. The code written in this programming language is the
software—the sets of instructions—that tell the computer what to do when you give
it commands. Emacs is designed so that you can write new code in Emacs Lisp and
easily install it as an extension to the editor.
(GNU Emacs is sometimes called an “extensible editor”, but it does much more
than provide editing capabilities. It is better to refer to Emacs as an “extensible
computing environment”. However, that phrase is quite a mouthful. It is easier to
refer to Emacs simply as an editor. Moreover, everything you do in Emacs—find the
Mayan date and phases of the moon, simplify polynomials, debug code, manage files,
read letters, write books—all these activities are kinds of editing in the most general
sense of the word.)
Although Emacs Lisp is usually thought of in association only with Emacs, it is a
full computer programming language. You can use Emacs Lisp as you would any
other programming language.
Perhaps you want to understand programming; perhaps you want to extend
Emacs; or perhaps you want to become a programmer. This introduction to Emacs
Lisp is designed to get you started: to guide you in learning the fundamentals of
programming, and more importantly, to show you how you can teach yourself to go
further.
Learning about these features of Emacs is like learning new routes around your
home town.
Finally, I hope to convey some of the skills for using Emacs to learn aspects of
programming that you don’t know. You can often use Emacs to help you understand
what puzzles you or to find out how to do something new. This self-reliance is not
only a pleasure, but an advantage.
Lisp History
Lisp was first developed in the late 1950s at the Massachusetts Institute of
Technology for research in artificial intelligence. The great power of the Lisp
language makes it superior for other purposes as well, such as writing editor
commands and integrated environments.
GNU Emacs Lisp is largely inspired by Maclisp, which was written at MIT in the
1960s. It is somewhat inspired by Common Lisp, which became a standard in the
1980s. However, Emacs Lisp is much simpler than Common Lisp. (The standard
Emacs distribution contains an optional extensions file, cl-lib.el, that adds many
Common Lisp features to Emacs Lisp.)
Thank You
My thanks to all who helped me with this book. My especial thanks to Jim Blandy,
Noah Friedman, Jim Kingdon, Roland McGrath, Frank Ritter, Randy Smith, Richard M.
Stallman, and Melissa Weisshaus. My thanks also go to both Philip Johnson and
David Stampe for their patient encouragement. My mistakes are my own.
Robert J. Chassell
bob@gnu.org
1
Section 1.1: Lisp Lists
1 List Processing
To the untutored eye, Lisp is a strange programming language. In Lisp code there are
parentheses everywhere. Some people even claim that the name stands for “Lots of
Isolated Silly Parentheses”. But the claim is unwarranted. Lisp stands for LISt
Processing, and the programming language handles lists (and lists of lists) by putting
them between parentheses. The parentheses mark the boundaries of the list.
Sometimes a list is preceded by an apostrophe ‘'’, called a single-quote in Lisp.1 Lists
are the basis of Lisp.
1 A single-quote is an abbreviation for the special form quote; you need not think about
special forms now. See Section 1.5 “Lisp Interpreter”, page 6.
2 Chapter 1: List Processing
concerned, the words we have been using in the lists cannot be divided into any
smaller parts and still mean the same thing as part of a program; likewise with
numbers and single character symbols like ‘+’. On the other hand, unlike an ancient
atom, a list can be split into parts. (See Chapter 7 “carcdr & cons Fundamental
Functions”, page 77.)
In a list, atoms are separated from each other by whitespace. They can be right
next to a parenthesis.
Technically speaking, a list in Lisp consists of parentheses surrounding atoms
separated by whitespace or surrounding other lists or surrounding both atoms and
other lists. A list can have just one atom in it or have nothing in it at all. A list with
nothing in it looks like this: (), and is called the empty list. Unlike anything else, an
empty list is considered both an atom and a list at the same time.
The printed representation of both atoms and lists are called symbolic expressions
or, more concisely, s-expressions. The word expression by itself can refer to either the
printed representation, or to the atom or list as it is held internally in the computer.
Often, people use the term expression indiscriminately. (Also, in many texts, the word
form is used as a synonym for expression.)
Incidentally, the atoms that make up our universe were named such when they
were thought to be indivisible; but it has been found that physical atoms are not
indivisible. Parts can split off an atom or it can fission into two parts of roughly equal
size. Physical atoms were named prematurely, before their truer nature was found.
In Lisp, certain kinds of atom, such as an array, can be separated into parts; but the
mechanism for doing this is different from the mechanism for splitting a list. As far
as list operations are concerned, the atoms of a list are unsplittable.
As in English, the meanings of the component letters of a Lisp atom are different
from the meaning the letters make as a word. For example, the word for the South
American sloth, the ‘ai’, is completely different from the two words, ‘a’, and ‘i’.
There are many kinds of atom in nature but only a few in Lisp: for example,
numbers, such as 37, 511, or 1729, and symbols, such as ‘+’, ‘foo’, or ‘forward-line’. The
words we have listed in the examples above are all symbols. In everyday Lisp
conversation, the word “atom” is not often used, because programmers usually try to
be more specific about what kind of atom they are dealing with. Lisp programming is
mostly about symbols (and sometimes numbers) within lists. (Incidentally, the
preceding three word parenthetical remark is a proper list in Lisp, since it consists of
atoms, which in this case are symbols, separated by whitespace and enclosed by
parentheses, without any non-Lisp punctuation.)
Text between double quotation marks—even sentences or paragraphs—is also
an atom. Here is an example:
'(this list includes "text between quotation marks.")
In Lisp, all of the quoted text including the punctuation mark and the blank spaces is
a single atom. This kind of atom is called a string (for “string of characters”) and is
the sort of thing that is used for messages that a computer can print for a human to
read. Strings are a different kind of atom than numbers or symbols and are used
differently.
3
1.1.2 Whitespace in Lists
Section 1.2: Run a Program
The amount of whitespace in a list does not matter. From the point of view of the
Lisp language,
'(this list looks like this)
is exactly the same as this:
'(this list looks like this)
Both examples show what to Lisp is the same list, the list made up of the symbols
‘this’, ‘list’, ‘looks’, ‘like’, and ‘this’ in that order.
Extra whitespace and newlines are designed to make a list more readable by
humans. When Lisp reads the expression, it gets rid of all the extra whitespace
(but it needs to have at least one space between atoms in order to tell them apart.)
Odd as it seems, the examples we have seen cover almost all of what Lisp lists
look like! Every other list in Lisp looks more or less like one of these examples,
except that the list may be longer and more complex. In brief, a list is between
parentheses, a string is between quotation marks, a symbol looks like a word, and a
number looks like a number. (For certain situations, square brackets, dots and a few
other special characters may be used; however, we will go quite far without them.)
2 Emacs shows integer values in decimal, in octal and in hex, and also as a character, but
let’s ignore this convenience feature for now.
5
the one we just used, but without the single-quote in front of it. Position the cursor
right after it and type C-xC-e:
(this is an unquoted list)
A *Backtrace* window will open up and you should see the following in it:
Section 1.3: Generate an Error Message
This is how Lisp works. Simple. There are added complications which we will get
to in a minute, but these are the fundamentals. Of course, to write Lisp programs,
you need to know how to write function definitions and attach them to names, and
how to do this without confusing either yourself or the computer.
Now, for the first complication. In addition to lists, the Lisp interpreter can
evaluate a symbol that is not quoted and does not have parentheses around it. The
Lisp interpreter will attempt to determine the symbol’s value as a variable. This
situation is described in the section on variables. (See Section 1.7 “Variables”, page
9.)
The second complication occurs because some functions are unusual and do not
work in the usual manner. Those that don’t are called special forms. They are used for
special jobs, like defining a function, and there are not many of them. In the next few
chapters, you will be introduced to several of the more important special forms.
As well as special forms, there are also macros. A macro is a construct defined in
Lisp, which differs from a function in that it translates a Lisp expression into another
expression that is to be evaluated in place of the original expression. (See Section
8.2.2 “Lisp macro”, page 93.)
For the purposes of this introduction, you do not need to worry too much about
whether something is a special form, macro, or ordinary function. For example, if is a
special form (see Section 3.7 “if”, page 37), but when is a macro (see Section 8.2.2
“Lisp macro”, page 93). In earlier versions of Emacs, defun was a special form, but
now it is a macro (see Section 3.1 “defun”, page 26). It still behaves in the same way.
The final complication is this: if the function that the Lisp interpreter is looking at
is not a special form, and if it is part of a list, the Lisp interpreter looks to see
whether the list has a list inside of it. If there is an inner list, the Lisp interpreter first
figures out what it should do with the inside list, and then it works on the outside
list. If there is yet another list embedded inside the inner list, it works on that one
first, and so on. It always works on the innermost list first. The interpreter works on
the innermost list first, to evaluate the result of that list. The result may be used by
the enclosing expression.
Otherwise, the interpreter works left to right, from one expression to the next.
8 Chapter 1: List Processing
1.5.1 Byte Compiling
One other aspect of interpreting: the Lisp interpreter is able to interpret two kinds
of entity: humanly readable code, on which we will focus exclusively, and specially
processed code, called byte compiled code, which is not humanly readable. Byte
compiled code runs faster than humanly readable code.
You can transform humanly readable code into byte compiled code by running
one of the compile commands such as byte-compile-file. Byte compiled code is
usually stored in a file that ends with a .elc extension rather than a .el extension. You
will see both kinds of file in the emacs/lisp directory; the files to read are those with
.el extensions.
As a practical matter, for most things you might do to customize or extend Emacs,
you do not need to byte compile; and I will not discuss the topic here. See Section
“Byte Compilation” in The GNU Emacs Lisp Reference Manual, for a full description of
byte compilation.
1.6 Evaluation
When the Lisp interpreter works on an expression, the term for the activity is called
evaluation. We say that the interpreter “evaluates the expression”. I’ve used this term
several times before. The word comes from its use in everyday language, “to
ascertain the value or amount of; to appraise”, according to Webster’s New Collegiate
Dictionary.
After evaluating an expression, the Lisp interpreter will most likely return the
value that the computer produces by carrying out the instructions it found in the
function definition, or perhaps it will give up on that function and produce an error
message. (The interpreter may also find itself tossed, so to speak, to a different
function or it may attempt to repeat continually what it is doing for ever and ever in
an infinite loop. These actions are less common; and we can ignore them.) Most
frequently, the interpreter returns a value.
At the same time the interpreter returns a value, it may do something else as
well, such as move a cursor or copy a file; this other kind of action is called a side
effect. Actions that we humans think are important, such as printing results, are
often side effects to the Lisp interpreter. It is fairly easy to learn to use side effects.
In summary, evaluating a symbolic expression most commonly causes the Lisp
interpreter to return a value and perhaps carry out a side effect; or else produce an
error.
1.7 Variables
In Emacs Lisp, a symbol can have a value attached to it just as it can have a function
definition attached to it. The two are different. The function definition is a set of
instructions that a computer will obey. A value, on the other hand, is something, such
as number or a name, that can vary (which is why such a symbol is called a variable).
The value of a symbol can be any expression in Lisp, such as a symbol, number, list,
or string. A symbol that has a value is often called a variable.
A symbol can have both a function definition and a value attached to it at the
same time. Or it can have just one or the other. The two are separate. This is
somewhat similar to the way the name Cambridge can refer to the city in
Massachusetts and have some information attached to the name as well, such as
“great programming center”.
10 Chapter 1: List Processing
Another way to think about this is to imagine a symbol as being a chest of
drawers. The function definition is put in one drawer, the value in another, and so on.
What is put in the drawer holding the value can be changed without affecting the
contents of the drawer holding the function definition, and vice versa.
The variable fill-column illustrates a symbol with a value attached to it: in every
GNU Emacs buffer, this symbol is set to some value, usually 72 or 70, but sometimes
to some other value. To find the value of this symbol, evaluate it by itself. If you are
reading this in Info inside of GNU Emacs, you can do this by putting the cursor after
the symbol and typing C-xC-e:
fill-column
After I typed C-xC-e, Emacs printed the number 72 in my echo area. This is the value
for which fill-column is set for me as I write this. It may be different for you in your
Info buffer. Notice that the value returned as a variable is printed in exactly the same
way as the value returned by a function carrying out its instructions. From the point
of view of the Lisp interpreter, a value returned is a value returned. What kind of
expression it came from ceases to matter once the value is known.
A symbol can have any value attached to it or, to use the jargon, we can bind the
variable to a value: to a number, such as 72; to a string, "suchasthis"; to a list, such as
(sprucepineoak); we can even bind a variable to a function definition.
A symbol can be bound to a value in several ways. See Section 1.9 “Setting the
Value of a Variable”, page 16, for information about one way to do this.
addition. In the following expression, put your cursor right after the +, before the
first number 2, type C-xC-e:
(+ 2 2)
In GNU Emacs 22, you will create a *Backtrace* buffer that says:
---------- Buffer: *Backtrace* ----------
Debugger entered--Lisp error: (void-variable +) eval(+) elisp--
eval-last-sexp(nil) eval-last-sexp(nil) funcall-
interactively(eval-last-sexp nil) call-interactively(eval-last-
sexp nil nil) command-execute(eval-last-sexp)
---------- Buffer: *Backtrace* ----------
(Again, you can quit the debugger by typing q in the *Backtrace* buffer.)
This backtrace is different from the very first error message we saw, which said,
‘Debuggerentered--Lisperror:(void-functionthis)’. In this case, the function does not
have a value as a variable; while in the other error message, the function (the word
‘this’) did not have a definition.
In this experiment with the +, what we did was cause the Lisp interpreter to
evaluate the + and look for the value of the variable instead of the function definition.
We did this by placing the cursor right after the symbol rather than after the
parenthesis of the enclosing list as we did before. As a consequence, the Lisp
interpreter evaluated the preceding s-expression, which in this case was + by itself.
Since + does not have a value bound to it, just the function definition, the error
message reported that the symbol’s value as a variable was void.
1.8 Arguments
To see how information is passed to functions, let’s look again at our old standby, the
addition of two plus two. In Lisp, this is written as follows:
(+ 2 2)
If you evaluate this expression, the number 4 will appear in your echo area. What
the Lisp interpreter does is add the numbers that follow the +.
The numbers added by + are called the arguments of the function +. These
numbers are the information that is given to or passed to the function.
The word “argument” comes from the way it is used in mathematics and does not
refer to a disputation between two people; instead it refers to the information
presented to the function, in this case, to the +. In Lisp, the arguments to a function
are the atoms or lists that follow the function. The values returned by the evaluation
of these atoms or lists are passed to the function. Different functions require
different numbers of arguments; some functions require none at all.3
3 It is curious to track the path by which the word “argument” came to have two
different meanings, one in mathematics and the other in everyday English. According to the
Oxford English Dictionary, the word derives from the Latin for ‘tomakeclear, prove’; thus it
came to mean, by one thread of derivation, “the evidence offered as proof”, which is to say,
Section 1.8: Arguments 13
But in the other thread of derivation, it came to mean “to assert in a manner against which
others may make counter assertions”, which led to the meaning of the word as a
disputation. (Note here that the English word has two different definitions attached to it
at the same time. By contrast, in Emacs Lisp, a symbol cannot have two different function
definitions at the same time.)
Position the cursor after the following expression and type C-xC-e:
(+ 2 fill-column)
The value will be a number two more than what you get by evaluating fill-column
alone. For me, this is 74, because my value of fill-column is 72.
As we have just seen, an argument can be a symbol that returns a value when
evaluated. In addition, an argument can be a list that returns a value when it is
evaluated. For example, in the following expression, the arguments to the function
concat are the strings "The" and "redfoxes." and the list (number-to-string (+2fill-
column)).
(concat "The " (number-to-string (+ 2 fill-column)) " red foxes.")
If you evaluate this expression—and if, as with my Emacs, fill-column evaluates to 72
—"The74redfoxes." will appear in the echo area. (Note that you must put spaces after
the word ‘The’ and before the word ‘red’ so they will appear in the final string. The
function number-to-string converts the integer that the addition function returns to a
string. number-to-string is also known as int-to-string.)
(*) ⇒1
In this set, the functions have one argument each:
(+ 3) ⇒3
(* 3) ⇒3
In this set, the functions have three arguments each:
(+ 3 4 5) ⇒ 12
(* 3 4 5) ⇒ 60
Finally, the last part of the error message is the symbol hello. This is the value of
the argument that was passed to +. If the addition had been passed the correct type
of object, the value passed would have been a number, such as 37, rather than a
symbol like hello. But then you would not have got the error message.
5 Actually, you can use %s to print a number. It is non-specific. %d prints only the part of
a number left of a decimal point, and not anything that is not a number.
Section 1.8: Arguments 17
a rather whimsical message will appear in your echo area. On my system it says,
"Thereare58pinkelephantsintheoffice!".
The expression (-fill-column14) is evaluated and the resulting number is inserted
in place of the ‘%d’; and the string in double quotes, "pinkelephants", is treated as a
single argument and inserted in place of the ‘%s’. (That is to say, a string between
double quotes evaluates to itself, like a number.)
Finally, here is a somewhat complex example that not only illustrates the
computation of a number, but also shows how you can use an expression within an
expression to generate the text that is substituted for ‘%s’:
(message "He saw %d %s"
(- fill-column 32) (concat "red "
(substring
"The quick brown foxes jumped." 16 21)
" leaping."))
In this example, message has three arguments: the string, "Hesaw%d%s", the
expression, (-fill-column32), and the expression beginning with the function concat.
The value resulting from the evaluation of (-fill-column32) is inserted in place of the
‘%d’; and the value returned by the expression beginning with concat is inserted in
place of the ‘%s’.
When your fill column is 70 and you evaluate the expression, the message "He
saw38redfoxesleaping." appears in your echo area.
After evaluating the setq expression, you can evaluate the symbol flowers and it
will return the value you just set. Here is the symbol. Place your cursor after it and
type C-xC-e.
flowers
When you evaluate flowers, the list (rosevioletdaisybuttercup) appears in the echo
area.
Incidentally, if you evaluate 'flowers, the variable with a quote in front of it, what
you will see in the echo area is the symbol itself, flowers. Here is the quoted symbol,
so you can try this:
'flowers
Also, as an added convenience, setq permits you to set several different variables
to different values, all in one expression.
To set the value of the variable carnivores to the list '(liontigerleopard) using setq,
the following expression is used:
(setq carnivores '(lion tiger leopard))
Also, setq can be used to assign different values to different variables. The first
argument is bound to the value of the second argument, the third argument is bound
to the value of the fourth argument, and so on. For example, you could use the
following to assign a list of trees to the symbol trees and a list of herbivores to the
symbol herbivores:
(setq trees '(pine fir oak maple) herbivores '(gazelle
antelope zebra))
(The expression could just as well have been on one line, but it might not have fit on
a page; and humans find it easier to read nicely formatted lists.)
Although I have been using the term “assign”, there is another way of thinking
about the workings of setq; and that is to say that setq makes the symbol point to the
list. This latter way of thinking is very common and in forthcoming chapters we shall
come upon at least one symbol that has “pointer” as part of its name. The name is
chosen because the symbol has a value, specifically a list, attached to it; or, expressed
another way, the symbol is set to point to the list.
1.9.2 Counting
Here is an example that shows how to use setq in a counter. You might use this to
count how many times a part of your program repeats itself. First set a variable to
zero; then add one to the number each time the program repeats itself. To do this,
you need a variable that serves as a counter, and two expressions: an initial setq
expression that sets the counter variable to zero; and a second setq expression that
increments the counter each time it is evaluated.
(setq counter 0) ; Let’s call this the initializer.
19
(setq counter (+ counter 1)) ; This is the incrementer.
1.10 Summary
Learning Lisp is like climbing a hill in which the first part is the steepest. You have
now climbed the most difficult part; what remains becomes easier as you progress
onwards.
In summary,
• Lisp programs are made up of expressions, which are lists or single atoms.
• Lists are made up of zero or more atoms or inner lists, separated by whitespace
and surrounded by parentheses. A list can be empty.
• Atoms are multi-character symbols, like forward-paragraph, single character
symbols like +, strings of characters between double quotation marks, or
numbers.
• A number evaluates to itself.
• A string between double quotes also evaluates to itself.
• When you evaluate a symbol by itself, its value is returned.
• When you evaluate a list, the Lisp interpreter looks at the first symbol in the list
and then at the function definition bound to that symbol. Then the instructions
in the function definition are carried out.
• A single-quote ‘'’ tells the Lisp interpreter that it should return the following
expression as written, and not evaluate it as it would if the quote were not
there.
20 Chapter 1: List Processing
• Arguments are the information passed to a function. The arguments to a
function are computed by evaluating the rest of the elements of the list of
which the function is the first element.
• A function always returns a value when it is evaluated (unless it gets an error);
in addition, it may also carry out some action that is a side effect. In many
cases, a function’s primary purpose is to create a side effect.
Section 1.11: Exercises
1.11 Exercises
A few simple exercises:
• Generate an error message by evaluating an appropriate symbol that is not
within parentheses.
• Generate an error message by evaluating an appropriate symbol that is
between parentheses.
• Create a counter that increments by two rather than one.
• Write an expression that prints a message in the echo area when evaluated.
21
2 Practicing Evaluation
Before learning how to write a function definition in Emacs Lisp, it is useful to spend
a little time evaluating various expressions that have already been written. These
expressions will be lists with the functions as their first (and often only) element.
Since some of the functions associated with buffers are both simple and interesting,
we will start with those. In this section, we will evaluate a few of these. In another
section, we will study the code of several other buffer-related functions, to see how
they were written.
Whenever you give an editing command to Emacs Lisp, such as the command to
move the cursor or to scroll the screen, you are evaluating an expression, the first
element of which is a function. This is how Emacs works.
When you type keys, you cause the Lisp interpreter to evaluate an expression and
that is how you get your results. Even typing plain text involves evaluating an Emacs
Lisp function, in this case, one that uses self-insert-command, which simply inserts
the character you typed. The functions you evaluate by typing keystrokes are called
interactive functions, or commands; how you make a function interactive will be
illustrated in the chapter on how to write function definitions. See Section 3.3
“Making a Function Interactive”, page 29.
In addition to typing keyboard commands, we have seen a second way to
evaluate an expression: by positioning the cursor after a list and typing C-xC-e. This
is what we will do in the rest of this section. There are other ways to evaluate an
expression as well; these will be described as we come to them.
Besides being used for practicing evaluation, the functions shown in the next few
sections are important in their own right. A study of these functions makes clear the
distinction between buffers and files, how to switch to a buffer, and how to
determine a location within it.
(buffer-file-name)
When I do this in Info, the value returned by evaluating (buffer-name) is "*info*", and
the value returned by evaluating (buffer-file-name) is nil.
On the other hand, while I am writing this document, the value returned by
evaluating (buffer-name) is "introduction.texinfo", and the value returned by
evaluating (buffer-file-name) is "/gnu/work/intro/introduction.texinfo".
The former is the name of the buffer and the latter is the name of the file. In Info,
the buffer name is "*info*". Info does not point to any file, so the result of evaluating
(buffer-file-name) is nil. The symbol nil is from the Latin word for “nothing”; in this
case, it means that the buffer is not associated with any file.
(In Lisp, nil is also used to mean “false” and is a synonym for the empty list, ().)
When I am writing, the name of my buffer is "introduction.texinfo". The name of
the file to which it points is "/gnu/work/intro/introduction.texinfo".
(In the expressions, the parentheses tell the Lisp interpreter to treat buffer-name
and buffer-file-name as functions; without the parentheses, the interpreter would
attempt to evaluate the symbols as variables. See Section 1.7 “Variables”, page 9.)
In spite of the distinction between files and buffers, you will often find that
people refer to a file when they mean a buffer and vice versa. Indeed, most people
say, “I am editing a file,” rather than saying, “I am editing a buffer which I will soon
save to a file.” It is almost always clear from context what people mean. When
dealing with computer programs, however, it is important to keep the distinction in
mind, since the computer is not as smart as a person.
The word “buffer”, by the way, comes from the meaning of the word as a cushion
that deadens the force of a collision. In early computers, a buffer cushioned the
interaction between files and the computer’s central processing unit. The drums or
tapes that held a file and the central processing unit were pieces of equipment that
were very different from each other, working at their own speeds, in spurts. The
buffer made it possible for them to work together effectively. Eventually, the buffer
grew from being an intermediary, a temporary holding place, to being the place
where work is done. This transformation is rather like that of a small seaport that
grew into a great city: once it was merely the place where cargo was warehoused
temporarily before being loaded onto ships; then it became a business and cultural
center in its own right.
Not all buffers are associated with files. For example, a *scratch* buffer does not
visit any file. Similarly, a *Help* buffer is not associated with any file.
In the old days, when you lacked a ~/.emacs file and started an Emacs session by
typing the command emacs alone, without naming any files, Emacs started with the
*scratch* buffer visible. Nowadays, you will see a splash screen. You can follow one
23
of the commands suggested on the splash screen, visit a file, or press q to quit the
splash screen and reach the *scratch* buffer.
If you switch to the *scratch* buffer, type (buffer-name), position the cursor after
it, and then type C-xC-e to evaluate the expression. The name "*scratch*" will be
returned and will appear in the echo area. "*scratch*" is the name of the buffer.
When you type (buffer-file-name) in the *scratch* buffer and evaluate that, nil will
appear in the echo area, just as it does when you evaluate (buffer-file-name) in Info.
Incidentally, if you are in the *scratch* buffer and want the value returned by an
expression to appear in the *scratch* buffer itself rather than in the echo area, type
C-uC-xC-e instead of C-xC-e. This causes the value returned to appear after the
expression. The buffer will look like this:
(buffer-name)"*scratch*"
You cannot do this in Info since Info is read-only and it will not allow you to change
the contents of the buffer. But you can do this in any buffer you can edit; and when
you write code or documentation (such as this book), this feature is very useful.
6 Actually, by default, if the buffer from which you just switched is visible to you in
another window, other-buffer will choose the most recent buffer that you cannot see; this is a
subtlety that I often forget.
7 Or rather, to save typing, you probably only typed RET if the default buffer was
*scratch*, or if it was different, then you typed just part of the name, such as *sc, pressed
your TAB key to cause it to expand to the full name, and then typed RET.
25
between computer programs and humans: humans have eyes and expect to see the
buffer on which they are working on their computer terminals. This is so obvious, it
almost goes without saying. However, programs do not have eyes. When a computer
program works on a buffer, that buffer does not need to be visible on the screen.
switch-to-buffer is designed for humans and does two different things: it switches
the buffer to which Emacs’s attention is directed; and it switches the buffer
displayed in the window to the new buffer. set-buffer, on the other hand, does only
one thing: it switches the attention of the computer program to a different buffer.
The buffer on the screen remains unchanged (of course, normally nothing happens
there until the command finishes running).
Also, we have just introduced another jargon term, the word call. When you
evaluate a list in which the first symbol is a function, you are calling that function.
The use of the term comes from the notion of the function as an entity that can do
something for you if you call it—just as a plumber is an entity who can fix a leak if
you call him or her.
3
Remember, this expression will move you to your most recent other buffer that you
cannot see. If you really want to go to your most recently selected buffer, even if you can
still see it, you need to evaluate the following more complex expression:
(switch-to-buffer (other-buffer (current-buffer) t))
In this case, the first argument to other-buffer tells it which buffer to skip—the current
one—and the second argument tells other-buffer it is OK to switch to a visible buffer. In
regular use, switch-to-buffer takes you to a buffer not visible in windows since you would
most likely use C-xo (other-window) to go to another visible buffer.
Section 2.5: Exercise
You can see the character count for point in this buffer by evaluating the
following expression in the usual way:
26 Chapter 2: Practicing Evaluation
(point)
As I write this, the value of point is 65724. The point function is frequently used in
some of the examples later in this book.
The value of point depends, of course, on its location within the buffer. If you
evaluate point in this spot, the number will be larger:
(point)
For me, the value of point in this location is 66043, which means that there are 319
characters (including spaces) between the two expressions. (Doubtless, you will see
different numbers, since I will have edited this since I first evaluated point.)
The function point-min is somewhat similar to point, but it returns the value of
the minimum permissible value of point in the current buffer. This is the number 1
unless narrowing is in effect. (Narrowing is a mechanism whereby you can restrict
yourself, or a program, to operations on just a part of a buffer. See Chapter 6
“Narrowing and Widening”, page 73.) Likewise, the function point-max returns the
value of the maximum permissible value of point in the current buffer.
2.5 Exercise
Find a file with which you are working and move towards its middle. Find its buffer
name, file name, length, and your position in the file.
27
3 How To Write Function Definitions
When the Lisp interpreter evaluates a list, it looks to see whether the first symbol on
the list has a function definition attached to it; or, put another way, whether the
symbol points to a function definition. If it does, the computer carries out the
instructions in the definition. A symbol that has a function definition is called,
simply, a function (although, properly speaking, the definition is the function and the
symbol refers to it.)
All functions are defined in terms of other functions, except for a few primitive
functions that are written in the C programming language. When you write
functions’ definitions, you will write them in Emacs Lisp and use other functions as
your building blocks. Some of the functions you will use will themselves be written
in Emacs Lisp (perhaps by you) and some will be primitives written in C. The
primitive functions are used exactly like those written in Emacs Lisp and behave like
them. They are written in C so we can easily run GNU Emacs on any computer that
has sufficient power and can run C.
Let me re-emphasize this: when you write code in Emacs Lisp, you do not
distinguish between the use of functions written in C and the use of functions
written in Emacs Lisp. The difference is irrelevant. I mention the distinction only
because it is interesting to know. Indeed, unless you investigate, you won’t know
whether an already-written function is written in Emacs Lisp or C.
5. The code that instructs the computer what to do: the body of the function
definition.
It is helpful to think of the five parts of a function definition as being organized in
a template, with slots for each part:
(defun function-name (arguments...)
"optional-documentation..."
(interactive argument-passing-info) ; optional body...)
As an example, here is the code for a function that multiplies its argument by 7.
(This example is not interactive. See Section 3.3 “Making a Function Interactive”,
page 29, for that information.)
(defun multiply-by-seven (number)
"Multiply NUMBER by seven."
(* 7 number))
This definition begins with a parenthesis and the symbol defun, followed by the
name of the function.
The name of the function is followed by a list that contains the arguments that
will be passed to the function. This list is called the argument list. In this example, the
list has only one element, the symbol, number. When the function is used, the symbol
will be bound to the value that is used as the argument to the function.
Instead of choosing the word number for the name of the argument, I could have
picked any other name. For example, I could have chosen the word multiplicand. I
picked the word “number” because it tells what kind of value is intended for this
slot; but I could just as well have chosen the word “multiplicand” to indicate the role
that the value placed in this slot will play in the workings of the function. I could
have called it foogle, but that would have been a bad choice because it would not tell
humans what it means. The choice of name is up to the programmer and should be
chosen to make the meaning of the function clear.
Indeed, you can choose any name you wish for a symbol in an argument list, even
the name of a symbol used in some other function: the name you use in an argument
list is private to that particular definition. In that definition, the name refers to a
different entity than any use of the same name outside the function definition.
Suppose you have a nick-name “Shorty” in your family; when your family members
refer to “Shorty”, they mean you. But outside your family, in a movie, for example, the
name “Shorty” refers to someone else. Because a name in an argument list is private
to the function definition, you can change the value of such a symbol inside the body
of a function without changing its value outside the function. The effect is similar to
that produced by a let expression. (See Section 3.6 “let”, page 33.)
29
The argument list is followed by the documentation string that describes the
function. This is what you see when you type C-hf and the name of a function.
Incidentally, when you write a documentation string like this, you should make the
first line a complete sentence since some commands, such as apropos, print only the
first line of a multi-line documentation string. Also, you should not indent the second
line of a documentation string, if you have one, because that looks odd when you use
C-hf (describe-function). The documentation string is optional, but it is so useful, it
should be included in almost every function you write.
The third line of the example consists of the body of the function definition.
(Most functions’ definitions, of course, are longer than this.) In this function, the
body is the list, (*7number), which says to multiply the value of number by 7. (In
Emacs Lisp, * is the function for multiplication, just as + is the function for addition.)
When you use the multiply-by-seven function, the argument number evaluates to
the actual number you want used. Here is an example that shows how multiply-by-
seven is used; but don’t try to evaluate this yet!
(multiply-by-seven 3)
The symbol number, specified in the function definition in the next section, is bound
to the value 3 in the actual use of the function. Note that although number was inside
parentheses in the function definition, the argument passed to the multiply-byseven
function is not in parentheses. The parentheses are written in the function definition
so the computer can figure out where the argument list ends and the rest of the
function definition begins.
If you evaluate this example, you are likely to get an error message. (Go ahead, try
it!) This is because we have written the function definition, but not yet told the
computer about the definition—we have not yet loaded the function definition in
Emacs. Installing a function is the process that tells the Lisp interpreter the
definition of the function. Installation is described in the next section.
(multiply-by-seven NUMBER)
For example, if your prefix argument is 5, the Lisp interpreter will evaluate the line
as if it were:
(message "The result is %d" (* 7 5))
(If you are reading this in GNU Emacs, you can evaluate this expression yourself.)
First, the interpreter will evaluate the inner list, which is (*75). This returns a value
of 35. Next, it will evaluate the outer list, passing the values of the second and
subsequent elements of the list to the function message.
As we have seen, message is an Emacs Lisp function especially designed for
sending a one line message to a user. (See Section 1.8.5 “The message function”, page
14.) In summary, the message function prints its first argument in the echo area as is,
except for occurrences of ‘%d’ or ‘%s’ (and various other %-sequences which we have
not mentioned). When it sees a control sequence, the function looks to the second or
subsequent arguments and prints the value of the argument in the location in the
string where the control sequence is located.
In the interactive multiply-by-seven function, the control string is ‘%d’, which
requires a number, and the value returned by evaluating (*75) is the number 35.
Consequently, the number 35 is printed in place of the ‘%d’ and the message is ‘The
resultis35’.
(Note that when you call the function multiply-by-seven, the message is printed
without quotes, but when you call message, the text is printed in double quotes. This
is because the value returned by message is what appears in the echo area when you
evaluate an expression whose first element is message; but when embedded in a
function, message prints the text as a side effect without quotes.)
tion definition in your .emacs initialization file. When you start Emacs, your
.emacs file is automatically evaluated and all the function definitions within it
are installed. See Chapter 16 “Your .emacs File”, page 196.
• Alternatively, you can put the function definitions that you want installed in one
or more files of their own and use the load function to cause Emacs to evaluate
and thereby install each of the functions in the files. See Section 16.9 “Loading
Files”, page 205.
• Thirdly, if you have code that your whole site will use, it is usual to put it in a
file called site-init.el that is loaded when Emacs is built. This makes the code
available to everyone who uses your machine. (See the INSTALL file that is part
of the Emacs distribution.)
Finally, if you have code that everyone who uses Emacs may want, you can post it
on a computer network or send a copy to the Free Software Foundation. (When you
do this, please license the code and its documentation under a license that permits
other people to run, copy, study, modify, and redistribute the code and which
protects you from having your work taken from you.) If you send a copy of your code
to the Free Software Foundation, and properly protect yourself and others, it may be
included in the next release of Emacs. In large part, this is how Emacs has grown
over the past years, by donations.
3.6 let
The let expression is a special form in Lisp that you will need to use in most function
definitions.
let is used to attach or bind a symbol to a value in such a way that the Lisp
interpreter will not confuse the variable with a variable of the same name that is not
part of the function.
To understand why the let special form is necessary, consider the situation in
which you own a home that you generally refer to as “the house”, as in the sentence,
“The house needs painting.” If you are visiting a friend and your host refers to “the
house”, he is likely to be referring to his house, not yours, that is, to a different house.
If your friend is referring to his house and you think he is referring to your house,
you may be in for some confusion. The same thing could happen in Lisp if a variable
that is used inside of one function has the same name as a variable that is used
inside of another function, and the two are not intended to refer to the same value.
The let special form prevents this kind of confusion.
The let special form prevents confusion. let creates a name for a local variable that
overshadows any use of the same name outside the let expression (in computer
science jargon, we call this binding the variable). This is like understanding that in
your host’s home, whenever he refers to “the house”, he means his house, not yours.
35
(The symbols used to name function arguments are bound as local variables in
exactly the same way. See Section 3.1 “The defun Macro”, page 26.)
Another way to think about let is that it defines a special region in your code:
within the body of the let expression, the variables you’ve named have their own
local meaning. Outside of the let body, they have other meanings (or they may not be
defined at all). This means that inside the let body, calling setq for a variable named
by the let expression will set the value of the local variable of that name. However,
outside of the let body (such as when calling a function that was defined elsewhere),
calling setq for a variable named by the let expression will not affect that local
variable.8let can create more than one variable at once. Also, let gives each variable it
creates an initial value, either a value specified by you, or nil. (In the jargon, this is
binding the variable to the value.) After let has created and bound the variables, it
executes the code in the body of the let, and returns the value of the last expression
in the body, as the value of the whole let expression. (“Execute” is a jargon term that
means to evaluate a list; it comes from the use of the word meaning “to give practical
effect to” (Oxford English Dictionary). Since you evaluate an expression to perform an
action, “execute” has evolved as a synonym to “evaluate”.)
8 This describes the behavior of let when using a style called “lexical binding” (see
Section 3.6.4 “How let Binds Variables”, page 36).
36 Chapter 3: How To Write Function Definitions
3.6.2 Sample let Expression
The following expression creates and gives initial values to the two variables zebra
and tiger. The body of the let expression is a list which calls the message function.
Section 3.6: let
9 According to Jared Diamond in Guns, Germs, and Steel, “. . . zebras become impossibly
dangerous as they grow older” but the claim here is that they do not become fierce like a
tiger. (1997, W. W. Norton and Co., ISBN 0-393-03894-2, page 171)
37
Note that in the first part of the let, the variables pine and fir stand alone as atoms
that are not surrounded by parentheses; this is because they are being bound to nil,
the empty list. But oak is bound to some and so is a part of the list (oak'some).
Similarly, birch is bound to the number 3 and so is in a list with that number. (Since a
number evaluates to itself, the number does not need to be quoted. Also, the number
is printed in the message using a ‘%d’ rather than a ‘%s’.) The four variables as a
group are put into a list to delimit them from the body of the let.
(setq x 0)
(defun getx ()
x)
(setq x 1)
(setq x 0)
(defun getx ()
x)
(setq x 1)
If you are reading this inside of GNU Emacs, you can evaluate the function definition
in the usual way to install it in Emacs, and then you can evaluate the following two
expressions to see the results:
(type-of-animal "fierce")
(type-of-animal "striped")
When you evaluate (type-of-animal"fierce"), you will see the following message
printed in the echo area: "Itisatiger!"; and when you evaluate (type-ofanimal"striped")
you will see nil printed in the echo area.
You can see the consequences of doing this if you evaluate the following version
of the type-of-animal function definition to install it and then evaluate the two
subsequent expressions to pass different arguments to the function.
(defun type-of-animal (characteristic) ; Second version.
"Print message in echo area depending on CHARACTERISTIC. If the
CHARACTERISTIC is the string \"fierce\", then warn of a tiger; else say it is
not fierce." (if (equal characteristic "fierce")
(message "It is a tiger!")
(message "It is not fierce!")))
(type-of-animal "fierce")
42 Chapter 3: How To Write Function Definitions
(type-of-animal "striped")
When you evaluate (type-of-animal"fierce"), you will see the following message
printed in the echo area: "Itisatiger!"; but when you evaluate (type-ofanimal"striped"),
you will see "Itisnotfierce!".
(Of course, if the characteristic were "ferocious", the message "Itisnot fierce!"
would be printed; and it would be misleading! When you write code, you need to
take into account the possibility that some such argument will be tested by the if and
write your program accordingly.)
(if nil
'true
43
'false)
Incidentally, if some other useful value is not available for a test that returns true,
then the Lisp interpreter will return the symbol t for true. For example, the
expression (>54) returns t when evaluated, as you can see by evaluating it in the
usual way:
(> 5 4)
On the other hand, this function returns nil if the test is false.
(> 4 5)
3.10 save-excursion
The save-excursion function is the final special form that we will discuss in this
chapter.
In Emacs Lisp programs used for editing, the save-excursion function is very
common. It saves the location of point, executes the body of the function, and then
restores point to its previous position if its location was changed. Its primary
purpose is to keep the user from being surprised and disturbed by unexpected
movement of point.
Before discussing save-excursion, however, it may be useful first to review what
point and mark are in GNU Emacs. Point is the current location of the cursor.
Wherever the cursor is, that is point. More precisely, on terminals where the cursor
appears to be on top of a character, point is immediately before the character. In
Emacs Lisp, point is an integer. The first character in a buffer is number one, the
second is number two, and so on. The function point returns the current position of
the cursor as a number. Each buffer has its own value for point.
The mark is another position in the buffer; its value can be set with a command
such as C-SPC (set-mark-command). If a mark has been set, you can use the command
C-xC-x (exchange-point-and-mark) to cause the cursor to jump to the mark and set the
mark to be the previous position of point. In addition, if you set another mark, the
position of the previous mark is saved in the mark ring. Many mark positions can be
saved this way. You can jump the cursor to a saved mark by typing C-uC-SPC one or
more times.
The part of the buffer between point and mark is called the region. Numerous
commands work on the region, including center-region, count-words-region, kill-
region, and print-region.
Section 3.10: save-excursion
The save-excursion special form saves the location of point and restores this
position after the code within the body of the special form is evaluated by the Lisp
interpreter. Thus, if point were in the beginning of a piece of text and some code
moved point to the end of the buffer, the save-excursion would put point back to
where it was before, after the expressions in the body of the function were evaluated.
44 Chapter 3: How To Write Function Definitions
In Emacs, a function frequently moves point as part of its internal workings even
though a user would not expect this. For example, count-words-region moves point.
To prevent the user from being bothered by jumps that are both unexpected and
(from the user’s point of view) unnecessary, save-excursion is often used to keep
point in the location expected by the user. The use of save-excursion is good
housekeeping.
To make sure the house stays clean, save-excursion restores the value of point
even if something goes wrong in the code inside of it (or, to be more precise and to
use the proper jargon, “in case of abnormal exit”). This feature is very helpful.
In addition to recording the value of point, save-excursion keeps track of the
current buffer, and restores it, too. This means you can write code that will change
the buffer and have save-excursion switch you back to the original buffer. This is how
save-excursion is used in append-to-buffer. (See Section 4.4 “The Definition of append-
to-buffer”, page 52.)
3.11 Review
In the last few chapters we have introduced a macro and a fair number of functions
and special forms. Here they are described in brief, along with a few similar
functions that have not been mentioned yet.
eval-last-sexp
45
Evaluate the last symbolic expression before the current location of
point. The value is printed in the echo area unless the function is
invoked with an argument; in that case, the output is printed in the
current buffer. This command is normally bound to C-xC-e.
defun Define function. This macro has up to five parts: the name, a template for the
arguments that will be passed to the function, documentation, an
optional interactive declaration, and the body of the definition.
For example, in Emacs the function definition of dired-unmark-allmarks
is as follows.
(defun dired-unmark-all-marks ()
"Remove all marks from all files in the Dired buffer."
(interactive)
(dired-unmark-all-files ?\r))
interactive
Declare to the interpreter that the function can be used interactively.
This special form may be followed by a string with one or more parts
that pass the information to the arguments of the function, in
sequence. These parts may also tell the interpreter to prompt for
information. Parts of the string are separated by newlines, ‘\n’.
Common code characters are:
b The name of an existing buffer. f The name
of an existing file.
p The numeric prefix argument. (Note that this p is lower
case.)
Section 3.11: Review
save-excursion
Record the values of point and the current buffer before evaluating the
body of this special form. Restore the value of point and buffer
afterward.
For example,
(message "We are %d characters into this buffer."
(- (point)
(save-excursion
(goto-char (point-min)) (point))))
message Print a message in the echo area. The first argument is a string that can
contain ‘%s’, ‘%d’, or ‘%c’ to print the value of arguments that follow the
string. The argument used by ‘%s’ must be a string or a symbol; the
argument used by ‘%d’ must be a number. The argument used by ‘%c’
must be an ascii code number; it will be printed as the character with
that ascii code. (Various other %-sequences have not been mentioned.)
setq
set The setq special form sets the value of its first argument to the value of the
second argument. The first argument is automatically quoted by setq. It
does the same for succeeding pairs of arguments.
buffer-name
Without an argument, return the name of the buffer, as a string.
buffer-file-name
Without an argument, return the name of the file the buffer is visiting.
current-buffer
Return the buffer in which Emacs is active; it may not be the buffer
that is visible on the screen.
Section 3.12: Exercises
other-buffer
Return the most recently selected buffer (other than the buffer passed
to other-buffer as an argument and other than the current buffer).
switch-to-buffer
Select a buffer for Emacs to be active in and display it in the current
window so users can look at it. Usually bound to C-xb.
set-buffer
Switch Emacs’s attention to a buffer on which programs will run.
Don’t alter what the window is showing.
buffer-size
Return the number of characters in the current buffer.
48 Chapter 3: How To Write Function Definitions
point Return the value of the current position of the cursor, as an integer
counting the number of characters from the beginning of the buffer.
point-min Return the minimum permissible value of point in the current buffer.
This is 1, unless narrowing is in effect.
point-max Return the value of the maximum permissible value of point in the
current buffer. This is the end of the buffer, unless narrowing is in
effect.
3.12 Exercises
• Write a non-interactive function that doubles the value of its argument, a
number. Make that function interactive.
• Write a function that tests whether the current value of fill-column is greater
than the argument passed to the function, and if so, prints an appropriate
message.
49
4 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.
such as “The C-hp command lets you search the standard Emacs Lisp libraries by
topic keywords.”
In GNU Emacs 22, the code for the complete function looks like this:
52 Chapter 4: A Few Buffer-Related Functions
(defun mark-whole-buffer ()
"Put point at beginning and mark at end of buffer. You probably should not use
this function in Lisp programs; it is usually a mistake for a Lisp function to use any
subroutine that uses or sets the mark."
(interactive)
(push-mark (point))
(push-mark (point-max) nil t)
(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-beginningof-buffer
function described in the previous section.
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-hf and C-hv.
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 META 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-xh.
59
let* Declare a list of variables and give them an initial value; then evaluate the rest of
the expressions in the body of let*. The values of the variables can be
used to bind ensuing variables in the list.
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.
4.6 Exercises
• Write your own simplified-end-of-buffer function definition; then test it to see
whether it works.
• Use if and get-buffer to write a function that prints a message telling you
whether a buffer exists.
• Using xref-find-definitions, find the source for the copy-to-buffer function.
Section 5.1: The Definition of copy-to-buffer
As with other function definitions, you can use a template to see an outline of the
function:
(defun insert-buffer (buffer)
"documentation..."
62 Chapter 5: A Few More Complex Functions
(interactive "*bInsert buffer: ") body...)
A Read-only Buffer
The asterisk is for the situation when the current buffer is a read-only buffer—a
buffer that cannot be modified. If insert-buffer is called when the current buffer is
read-only, a message to this effect is printed in the echo area and the terminal may
beep or blink at you; you will not be permitted to insert anything into current buffer.
The asterisk does not need to be followed by a newline to separate it from the next
argument.
and the if expression does not evaluate the then-part. This is fine, since we do not
need to do anything to the variable buffer if it really is a buffer.
On the other hand, when the value of buffer is not a buffer itself, but the name of a
buffer, the true-or-false-test returns true and the then-part of the expression is
evaluated. In this case, the then-part is (setqbuffer(get-bufferbuffer)). This expression
uses the get-buffer function to return an actual buffer itself, given its name. The setq
then sets the variable buffer to the value of the buffer itself, replacing its previous
value (which was the name of the buffer).
64 Chapter 5: A Few More Complex Functions
5.2.4 The or in the Body
The purpose of the or expression in the insert-buffer function is to ensure that the
argument buffer is bound to a buffer and not just to the name of a buffer. The
previous section shows how the job could have been done using an if expression.
However, the insert-buffer function actually uses or. To understand this, it is
necessary to understand how or works.
An or function can have any number of arguments. It evaluates each argument in
turn and returns the value of the first of its arguments that is not nil. Also, and this is
a crucial feature of or, it does not evaluate any subsequent arguments after returning
the first non-nil value.
The or expression looks like this:
(or (bufferp buffer)
(setq buffer (get-buffer buffer)))
The first argument to or is the expression (bufferpbuffer). This expression returns
true (a non-nil value) if the buffer is actually a buffer, and not just the name of a
buffer. In the or expression, if this is the case, the or expression returns this true
value and does not evaluate the next expression—and this is fine with us, since we
do not want to do anything to the value of buffer if it really is a buffer.
On the other hand, if the value of (bufferpbuffer) is nil, which it will be if the value
of buffer is the name of a buffer, the Lisp interpreter evaluates the next element of
the or expression. This is the expression (setqbuffer(get-buffer buffer)). This
expression returns a non-nil value, which is the value to which it sets the variable
buffer—and this value is a buffer itself, not the name of a buffer.
The result of all this is that the symbol buffer is always bound to a buffer itself
rather than to the name of a buffer. All this is necessary because the set-buffer
function in a following line only works with a buffer itself, not with the name to a
buffer.
Incidentally, using or, the situation with the usher would be written like this:
(or (holding-on-to-guest) (find-and-take-arm-of-guest))
except, and this is what confuses novices, very important work is done inside the
push-mark expression.
The get-buffer function returns a buffer with the name provided. You will note
that the function is not called get-buffer-create; it does not create a buffer if one does
not already exist. The buffer returned by get-buffer, an existing buffer, is passed to
insert-buffer-substring, which inserts the whole of the buffer (since you did not
specify anything else).
The location into which the buffer is inserted is recorded by push-mark. Then the
function returns nil, the value of its last command. Put another way, the insert-buffer
function exists only to produce a side effect, inserting another buffer, not to return
any value.
and Emacs moves the cursor that fraction of the way from the beginning of the
buffer. Thus, you can either call this function with the key command M-<, which will
move the cursor to the beginning of the buffer, or with a key command such as C-
u7M-< which will move the cursor to a point 70% of the way through the buffer. If a
number bigger than ten is used for the argument, it moves to the end of the buffer.
The beginning-of-buffer function can be called with or without an argument. The
use of the argument is optional.
The "P" in the interactive expression tells Emacs to pass a prefix argument, if
there is one, to the function in raw form. A prefix argument is made by typing the
META key followed by a number, or by typing C-u and then a number. (If you don’t
type a number, C-u defaults to a cons cell with a 4. A lowercase "p" in the interactive
expression causes the function to convert a prefix arg to a number.)
The true-or-false-test of the if expression looks complex, but it is not: it checks
whether arg has a value that is not nil and whether it is a cons cell. (That is what
consp does; it checks whether its argument is a cons cell.) If arg has a value that is
not nil (and is not a cons cell), which will be the case if beginning-ofbuffer is called
with a numeric argument, then this true-or-false-test will return true and the then-
part of the if expression will be evaluated. On the other hand, if beginning-of-buffer is
not called with an argument, the value of arg will be nil and the else-part of the if
expression will be evaluated. The else-part is simply point-min, and when this is the
outcome, the whole goto-char expression is
(goto-char(point-min)), which is how we saw the beginning-of-buffer function in its
simplified form.
number and finally the large number is divided by ten to provide a value that is one
character larger than the percentage position in the buffer.
The number that results from all this is passed to goto-char and the cursor is
moved to that point.
5.4 Review
Here is a brief summary of some of the topics covered in this chapter.
or Evaluate each argument in sequence, and return the value of the first argument
that is not nil; if none return a value that is not nil, return nil. In brief,
return the first true value of the arguments; return a true value if one
or any of the others are true.
and Evaluate each argument in sequence, and if any are nil, return nil; if none are nil,
return the value of the last argument. In brief, return a true value only
if all the arguments are true; return a true value if one and each of the
others is true.
&optional A keyword used to indicate that an argument to a function definition is
optional; this means that the function can be evaluated without the
argument, if desired.
prefix-numeric-value
Convert the raw prefix argument produced by (interactive"P") to a
numeric value.
forward-line
Move point forward to the beginning of the next line, or if the
argument is greater than one, forward that many lines. If it can’t move
as far forward as it is supposed to, forward-line goes forward as far as it
73
can and then returns a count of the number of additional lines it was
supposed to move but couldn’t.
erase-buffer
Delete the entire contents of the current buffer.
bufferp Return t if its argument is a buffer; otherwise return nil.
6.2 what-line
The what-line command tells you the number of the line in which the cursor is
located. The function illustrates the use of the save-restriction and save-excursion
commands. Here is the original text of the function:
(defun what-line ()
"Print the current line number (in the buffer) of point."
(interactive)
(save-restriction
(widen)
(save-excursion
(beginning-of-line) (message "Line
%d"
(1+ (count-lines 1 (point)))))))
(In modern versions of GNU Emacs, the what-line function has been expanded to
tell you your line number in a narrowed buffer as well as your line number in a
widened buffer. The modern version is more complex than the version shown here.
If you feel adventurous, you might want to look at it after figuring out how this
version works. You will probably need to use C-hf (describe-function). The newer
version uses a conditional to determine whether the buffer has been narrowed.
76
Also, the modern version of what-line uses line-number-at-pos, which among other
simple expressions, such as (goto-char(point-min)), moves point to the beginning of
the current line with (forward-line0) rather than beginning-ofline.)
Section 6.2: what-line
The what-line function as shown here has a documentation line and is interactive,
as you would expect. The next two lines use the functions save-restriction and widen.
The save-restriction special form notes whatever narrowing is in effect, if any, in
the current buffer and restores that narrowing after the code in the body of the save-
restriction has been evaluated.
The save-restriction special form is followed by widen. This function undoes any
narrowing the current buffer may have had when what-line was called. (The
narrowing that was there is the narrowing that save-restriction remembers.) This
widening makes it possible for the line counting commands to count from the
beginning of the buffer. Otherwise, they would have been limited to counting within
the accessible region. Any original narrowing is restored just before the completion
of the function by the save-restriction special form.
The call to widen is followed by save-excursion, which saves the location of the
cursor (i.e., of point), and restores it after the code in the body of the save-excursion
uses the beginning-of-line function to move point.
(Note that the (widen) expression comes between the save-restriction and save-
excursion special forms. When you write the two save-... expressions in sequence,
write save-excursion outermost.)
The last two lines of the what-line function are functions to count the number of
lines in the buffer and then print the number in the echo area.
(message "Line %d"
(1+ (count-lines 1 (point)))))))
The message function prints a one-line message at the bottom of the Emacs
screen. The first argument is inside of quotation marks and is printed as a string of
characters. However, it may contain a ‘%d’ expression to print a following argument.
‘%d’ prints the argument as a decimal, so the message will say something such as
‘Line243’.
Chapter 6: Narrowing and Widening
The number that is printed in place of the ‘%d’ is computed by the last line of the
function:
(1+ (count-lines 1 (point)))
What this does is count the lines from the first position of the buffer, indicated by the
1, up to (point), and then add one to that number. (The 1+ function adds one to its
argument.) We add one to it because line 2 has only one line before it, and count-lines
counts only the lines before the current line.
77
After count-lines has done its job, and the message has been printed in the echo
area, the save-excursion restores point to its original position; and save-restriction
restores the original narrowing, if any.
7.2 cons
The cons function constructs lists; it is the inverse of car and cdr. For example, cons
can be used to make a four element list from the three element list, (firoak maple):
(cons 'pine '(fir oak maple))
Section 7.2: cons
12 Actually, you can cons an element to an atom to produce a dotted pair. Dotted pairs
are not discussed here; see Section “Dotted Pair Notation” in The GNU Emacs Lisp Reference
Manual.
81
In the third example, the cons function is used to construct a three element list which
is then passed to the length function as its argument.
We can also use length to count the number of elements in an empty list:
(length ())
⇒0
As you would expect, the number of elements in an empty list is zero.
An interesting experiment is to find out what happens if you try to find the length
of no list at all; that is, if you try to call length without giving it an argument, not even
an empty list:
(length )
What you see, if you evaluate this, is the error message
Lisp error: (wrong-number-of-arguments length 0)
This means that the function receives the wrong number of arguments, zero, when it
expects some other number of arguments. In this case, one argument is expected,
the argument being a list whose length the function is measuring. (Note that one list
is one argument, even if the list has many elements inside it.)
The part of the error message that says ‘length’ is the name of the function.
7.3 nthcdr
The nthcdr function is associated with the cdr function. What it does is take the cdr of
a list repeatedly.
If you take the cdr of the list (pinefiroakmaple), you will be returned the list
(firoakmaple). If you repeat this on what was returned, you will be returned the list
(oakmaple). (Of course, repeated cdring on the original list will just give you the
original cdr since the function does not change the list. You need to evaluate the cdr
of the cdr and so on.) If you continue this, eventually you will be returned an empty
list, which in this case, instead of being shown as () is shown as nil.
For review, here is a series of repeated cdrs, the text following the ‘⇒’ shows what
is returned.
(cdr '(pine fir oak maple))
⇒ (fir oak maple)
(cdr '(maple))
⇒ nil
7.4 nth
The nthcdr function takes the cdr of a list repeatedly. The nth function takes the car of
the result returned by nthcdr. It returns the Nth element of the list.
Thus, if it were not defined in C for speed, the definition of nth would be:
(defun nth (n list)
"Returns the Nth element of LIST.
83
N counts from zero. If LIST is not that long, nil is returned."
(car (nthcdr n list)))
(Originally, nth was defined in Emacs Lisp in subr.el, but its definition was redone in
C in the 1980s.)
The nth function returns a single element of a list. This can be very convenient.
Note that the elements are numbered from zero, not one. That is to say, the first
element of a list, its car is the zeroth element. This zero-based counting often
bothers people who are accustomed to the first element in a list being number one,
which is one-based.
For example:
(nth 0 '("one" "two" "three")) ⇒ "one"
7.5 setcar
As you might guess from their names, the setcar and setcdr functions set the car or
the cdr of a list to a new value. They actually change the original list, unlike car and
cdr which leave the original list as it was. One way to find out how this works is to
experiment. We will start with the setcar function.
First, we can make a list and then set the value of a variable to the list, using the
setq special form. Because we intend to use setcar to change the list, this setq should
not use the quoted form '(antelopegiraffeliontiger), as that would yield a list that is
part of the program and bad things could happen if we tried to change part of the
program while running it. Generally speaking an Emacs Lisp program’s components
should be constant (or unchanged) while the program is running. So we instead
construct an animal list by using the list function, as follows:
(setq animals (list 'antelope 'giraffe 'lion 'tiger))
If you are reading this in Info inside of GNU Emacs, you can evaluate this expression
in the usual fashion, by positioning the cursor after the expression and typing C-x C-
e. (I’m doing this right here as I write this. This is one of the advantages of having the
interpreter built into the computing environment. Incidentally, when there is
nothing on the line after the final parentheses, such as a comment, point can be on
the next line. Thus, if your cursor is in the first column of the next line, you do not
need to move it. Indeed, Emacs permits any amount of white space after the final
parenthesis.)
Section 7.6: setcdr
When we evaluate the variable animals, we see that it is bound to the list
(antelopegiraffeliontiger):
84 Chapter 7: car, cdr, cons: Fundamental Functions
animals
⇒ (antelope giraffe lion tiger)
Put another way, the variable animals points to the list (antelopegiraffelion tiger).
Next, evaluate the function setcar while passing it two arguments, the variable
animals and the quoted symbol hippopotamus; this is done by writing the three
element list (setcaranimals'hippopotamus) and then evaluating it in the usual fashion:
(setcar animals 'hippopotamus)
After evaluating this expression, evaluate the variable animals again. You will see that
the list of animals has changed:
animals
⇒ (hippopotamus giraffe lion tiger)
The first element on the list, antelope is replaced by hippopotamus.
So we can see that setcar did not add a new element to the list as cons would
have; it replaced antelope with hippopotamus; it changed the list.
7.6 setcdr
The setcdr function is similar to the setcar function, except that the function replaces
the second and subsequent elements of a list rather than the first element.
(To see how to change the last element of a list, look ahead to “The kill-new
function”, page 97, which uses the nthcdr and setcdr functions.)
To see how this works, set the value of the variable to a list of domesticated
animals by evaluating the following expression:
(setq domesticated-animals (list 'horse 'cow 'sheep 'goat))
If you now evaluate the list, you will be returned the list (horsecowsheepgoat):
domesticated-animals
⇒ (horse cow sheep goat)
Next, evaluate setcdr with two arguments, the name of the variable which has a
list as its value, and the list to which the cdr of the first list will be set;
(setcdr domesticated-animals '(cat dog))
If you evaluate this expression, the list (catdog) will appear in the echo area. This is
the value returned by the function. The result we are interested in is the side effect,
which we can see by evaluating the variable domesticated-animals:
domesticated-animals
⇒ (horse cat dog)
Indeed, the list is changed from (horsecowsheepgoat) to (horsecatdog). The cdr of the
list is changed from (cowsheepgoat) to (catdog).
85
7.7 Exercise
Construct a list of four birds by evaluating several expressions with cons. Find out
what happens when you cons a list onto itself. Replace the first element of the list of
four birds with a fish. Replace the rest of that list with a list of other fish.
86 Chapter 7: car, cdr, cons: Fundamental Functions
Section 8.1: zap-to-char
8.2 kill-region
The zap-to-char function uses the kill-region function. This function clips text from a
region and copies that text to the kill ring, from which it may be retrieved.
The Emacs 22 version of that function uses condition-case and copy-regionas-kill,
both of which we will explain. condition-case is an important special form.
In essence, the kill-region function calls condition-case, which takes three
arguments. In this function, the first argument does nothing. The second argument
contains the code that does the work when all goes well. The third argument
contains the code that is called in the event of an error.
We will go through the condition-case code in a moment. First, let us look at the
definition of kill-region, with comments added:
;; The 'kill-append' function concatenates the new string and ;; the old.
The 'kill-new' function inserts text into a new ;; item in the kill ring.
8.2.1 condition-case
As we have seen earlier (see Section 1.3 “Generate an Error Message”, page 4), when
the Emacs Lisp interpreter has trouble evaluating an expression, it provides you
with help; in the jargon, this is called “signaling an error”. Usually, the computer
stops the program and shows you a message.
However, some programs undertake complicated actions. They should not simply
stop on an error. In the kill-region function, the most likely error is that you will try to
kill text that is read-only and cannot be removed. So the kill-region function contains
code to handle this circumstance. This code, which makes up the body of the kill-
region function, is inside of a condition-case special form.
The template for condition-case looks like this:
(condition-case var
bodyform error-
handler...)
The second argument, bodyform, is straightforward. The condition-case special
form causes the Lisp interpreter to evaluate the code in bodyform. If no error occurs,
the special form returns the code’s value and produces the side-effects, if any.
94 Chapter 8: Cutting and Storing Text
In short, the bodyform part of a condition-case expression determines what should
happen when everything works correctly.
However, if an error occurs, among its other actions, the function generating the
error signal will define one or more error condition names.
An error handler is the third argument to condition-case. An error handler has
two parts, a condition-name and a body. If the condition-name part of an error handler
matches a condition name generated by an error, then the body part of the error
handler is run.
As you will expect, the condition-name part of an error handler may be either a
single condition name or a list of condition names.
Also, a complete condition-case expression may contain more than one error
handler. When an error occurs, the first applicable handler is run.
Lastly, the first argument to the condition-case expression, the var argument, is
sometimes bound to a variable that contains information about the error. However, if
that argument is nil, as is the case in kill-region, that information is discarded.
Section 8.3: copy-region-as-kill 95
In brief, in the kill-region function, the code condition-case works like this:
If no errors, run only this code but, if errors, run
this other code.
8.3 copy-region-as-kill
The copy-region-as-kill function copies a region of text from a buffer and (via either kill-
append or kill-new) saves it in the kill-ring.
If you call copy-region-as-kill immediately after a kill-region command, Emacs
appends the newly copied text to the previously copied text. This means that if you
yank back the text, you get it all, from both this and the previous operation. On the
other hand, if some other command precedes the copy-region-as-kill, the function
copies the text into a separate entry in the kill ring.
Here is the complete text of the version 22 copy-region-as-kill function:
(defun copy-region-as-kill (beg end)
"Save the region as if killed, but don't kill it.
In Transient Mark mode, deactivate the mark.
If `interprogram-cut-function' is non-nil, also save the text for a window system cut and paste."
(interactive "r")
(if (eq last-command 'kill-region)
(kill-append (filter-buffer-substring beg end) (< end beg))
(kill-new (filter-buffer-substring beg end))) (if transient-mark-
mode
(setq deactivate-mark t)) nil)
As usual, this function can be divided into its component parts:
(defun copy-region-as-kill (argument-list)
"documentation..." (interactive
"r") body...)
The arguments are beg and end and the function is interactive with "r", so the two
arguments must refer to the beginning and end of the region. If you have been reading
through this document from the beginning, understanding these parts of a function is
almost becoming routine.
The documentation is somewhat confusing unless you remember that the word
“kill” has a meaning different from usual. The Transient Mark and interprogram-cut-
function comments explain certain side-effects.
After you once set a mark, a buffer always contains a region. If you wish, you can
use Transient Mark mode to highlight the region temporarily. (No one wants to
highlight the region all the time, so Transient Mark mode highlights it only at
appropriate times. Many people turn off Transient Mark mode, so the region is never
highlighted.)
Also, a windowing system allows you to copy, cut, and paste among different
programs. In the X windowing system, for example, the interprogram-cut-function
function is x-select-text, which works with the windowing system’s equivalent of the
Emacs kill ring.
The body of the copy-region-as-kill function starts with an if clause. What this
clause does is distinguish between two different situations: whether or not this
command is executed immediately after a previous kill-region command. In the first
Section 8.3: copy-region-as-kill 97
case, the new region is appended to the previously copied text. Otherwise, it is
inserted into the beginning of the kill ring as a separate piece of text from the
previous piece.
The last two lines of the function prevent the region from lighting up if Transient
Mark mode is turned on.
The body of copy-region-as-kill merits discussion in detail.
the same object inside the computer, but with different names. equal determines
whether the structure and contents of two expressions are the same.
If the previous command was kill-region, then the Emacs Lisp interpreter calls the
prepended before the previous text. On the other hand, if the value of the variable
end is greater than the value of the variable beg, the text will be appended after the
previous text.
When the newly saved text will be prepended, then the string with the new text will
be concatenated before the old text:
(concat string cur)
But if the text will be appended, it will be concatenated after the old text:
(concat cur string))
To understand how this works, we first need to review the concat function. The
concat function links together or unites two strings of text. The result is a string. For
example:
(concat "abc" "def")
⇒ "abcdef"
(concat (car
'("first element" "second element")) " modified")
⇒ "first element modified"
We can now make sense of kill-append: it modifies the contents of the kill ring.
The kill ring is a list, each element of which is saved text. The kill-append function
uses the kill-new function which in turn uses the setcar function.
trees
⇒ (maple oak pine)
(The value returned by the setcdr expression is nil since that is what the cdr is set to.)
To repeat, in kill-new, the nthcdr function takes the cdr a number of times that is one
less than the maximum permitted size of the kill ring and setcdr sets the cdr of that
element (which will be the rest of the elements in the kill ring) to nil. This prevents the
kill ring from growing too long.
The next to last expression in the kill-new function is
(setq kill-ring-yank-pointer kill-ring)
The kill-ring-yank-pointer is a global variable that is set to be the kill-ring.
Even though the kill-ring-yank-pointer is called a ‘pointer’, it is a variable just like
the kill ring. However, the name has been chosen to help humans understand how
the variable is used.
Now, to return to an early expression in the body of the function:
(if (fboundp 'menu-bar-update-yank-menu)
Section 8.3: copy-region-as-kill 103
setcar
setcdr setcar changes the first element of a list; setcdr changes the second and
subsequent elements of a list.
For example:
(setq triple (list 1 2 3)) (setcar triple '37)
triple
⇒ (37 2 3)
triple
⇒ (37 "foo" "bar")
progn Evaluate each argument in sequence and then return the value of the
last.
For example:
(progn 1 2 3 4)
⇒4
save-restriction
109
Record whatever narrowing is in effect in the current buffer, if any, and
restore that narrowing after evaluating the arguments.
search-forward
Search for a string, and if the string is found, move point. With a
regular expression, use the similar re-search-forward. (See Chapter 12
Section 8.7: Searching Exercises
nil
rose violet
buttercup
In the diagram, each box represents a word of computer memory that holds a Lisp
object, usually in the form of a memory address. The boxes, i.e., the addresses, are in
pairs. Each arrow points to what the address is the address of, either an atom or
another pair of addresses. The first box is the electronic address of ‘rose’ and the
arrow points to ‘rose’; the second box is the address of the next pair of boxes, the
first part of which is the address of ‘violet’ and the second part of which is the
address of the next pair. The very last box points to the symbol nil, which marks the
end of the list.
When a variable is set to a list with an operation such as setq, it stores the
address of the first box in the variable. Thus, evaluation of the expression
(setq bouquet '(rose violet buttercup))
creates a situation like this:
111
bouquet
nil
In this example, the symbol bouquet holds the address of the first pair of boxes.
This same list can be illustrated in a different sort of box notation like this:
bouquet
(Symbols consist of more than pairs of addresses, but the structure of a symbol is
made up of addresses. Indeed, the symbol bouquet consists of a group of
addressboxes, one of which is the address of the printed word ‘bouquet’, a second of
which is the address of a function definition attached to the symbol, if any, a third of
which is the address of the first pair of address-boxes for the list (roseviolet
buttercup), and so on. Here we are showing that the symbol’s third address-box
points to the first pair of address-boxes for the list.)
If a symbol is set to the cdr of a list, the list itself is not changed; the symbol
simply has an address further down the list. (In the jargon, car and cdr are “non-
destructive”.) Thus, evaluation of the following expression
(setq flowers (cdr bouquet))
produces this:
bouquet flowers
nil
The value of flowers is (violetbuttercup), which is to say, the symbol flowers holds the
address of the pair of address-boxes, the first of which holds the address of violet,
and the second of which holds the address of buttercup.
A pair of address-boxes is called a cons cell or dotted pair. See Section “Cons Cell
and List Types” in The GNU Emacs Lisp Reference Manual, and Section “Dotted Pair
112 Chapter 9: How Lists are Implemented
Notation” in The GNU Emacs Lisp Reference Manual, for more information about cons
cells and dotted pairs.
The function cons adds a new pair of addresses to the front of a series of
addresses like that shown above. For example, evaluating the expression
(setq bouquet (cons 'lily bouquet)) produces:
bouquet flowers
nil
buttercup
lily violet
rose
Section 9.1: Symbols as a Chest of Drawers
However, this does not change the value of the symbol flowers, as you can see by
evaluating the following, (eq (cdr (cdr bouquet)) flowers) which returns t for true.
Until it is reset, flowers still has the value (violetbuttercup); that is, it has the
address of the cons cell whose first address is of violet. Also, this does not alter any
of the pre-existing cons cells; they are all still there.
Thus, in Lisp, to get the cdr of a list, you just get the address of the next cons cell
in the series; to get the car of a list, you get the address of the first element of the list;
to cons a new element on a list, you add a new cons cell to the front of the list. That is
all there is to it! The underlying structure of Lisp is brilliantly simple!
And what does the last address in a series of cons cells refer to? It is the address
of the empty list, of nil.
In summary, when a Lisp variable is set to a value, it is provided with the address
of the list to which the variable refers.
directions to map to
symbol name bouquet
directions to
symbol definition [none]
directions to map to
variable name (rose violet buttercup)
directions to
property list [not described here]
9.2 Exercise
Set flowers to violet and buttercup. Cons two more flowers on to this list and set this
new list to more-flowers. Set the car of flowers to a fish. What does the more-flowers
list now contain?
Section 10.2: The kill-ring-yank-pointer Variable
kill-ring kill-ring-yank-pointer
Both the variable kill-ring and the variable kill-ring-yank-pointer are pointers. But
the kill ring itself is usually described as if it were actually what it is composed of.
The kill-ring is spoken of as if it were the list rather than that it points to the list.
Conversely, the kill-ring-yank-pointer is spoken of as pointing to a list.
These two ways of talking about the same thing sound confusing at first but make
sense on reflection. The kill ring is generally thought of as the complete structure of
data that holds the information of what has recently been cut out of the Emacs
buffers. The kill-ring-yank-pointer on the other hand, serves to indicate—that is, to
point to—that part of the kill ring of which the first element (the car) will be
inserted.
11.1 while
The while special form tests whether the value returned by evaluating its first
argument is true or false. This is similar to what the Lisp interpreter does with an if;
what the interpreter does next, however, is different.
In a while expression, if the value returned by evaluating the first argument is
false, the Lisp interpreter skips the rest of the expression (the body of the
expression) and does not evaluate it. However, if the value is true, the Lisp
interpreter evaluates the body of the expression and then again tests whether the
first argument to while is true or false. If the value returned by evaluating the first
argument is again true, the Lisp interpreter again evaluates the body of the
expression.
The template for a while expression looks like this:
(while true-or-false-test body...)
So long as the true-or-false-test of the while expression returns a true value when
it is evaluated, the body is repeatedly evaluated. This process is called a loop since
the Lisp interpreter repeats the same thing again and again, like an airplane doing a
loop. When the result of evaluating the true-or-false-test is false, the Lisp interpreter
does not evaluate the rest of the while expression and exits the loop.
Clearly, if the value returned by evaluating the first argument to while is always
true, the body following will be evaluated again and again . . . and again . . . forever.
Conversely, if the value returned is never true, the expressions in the body will never
be evaluated. The craft of writing a while loop consists of choosing a mechanism such
that the true-or-false-test returns true just the number of times that you want the
subsequent expressions to be evaluated, and then have the test return false.
Thus, to create a while loop that tests whether there are any items in the list
animals, the first part of the loop will be written like this:
(while animals ...
When the while tests its first argument, the variable animals is evaluated. It returns a
list. So long as the list has elements, the while considers the results of the test to be
true; but when the list is empty, it considers the results of the test to be false.
To prevent the while loop from running forever, some mechanism needs to be
provided to empty the list eventually. An oft-used technique is to have one of the
subsequent forms in the while expression set the value of the list to be the cdr of the
list. Each time the cdr function is evaluated, the list will be made shorter, until
eventually only the empty list will be left. At this point, the test of the while loop will
return false, and the arguments to the while will no longer be evaluated.
118 Chapter 11: Loops and Recursion
For example, the list of animals bound to the variable animals can be set to be the
cdr of the original list with the following expression:
(setq animals (cdr animals))
If you have evaluated the previous expressions and then evaluate this expression,
you will see (giraffeliontiger) appear in the echo area. If you evaluate the expression
again, (liontiger) will appear in the echo area. If you evaluate it again and yet again,
(tiger) appears and then the empty list, shown by nil.
A template for a while loop that uses the cdr function repeatedly to cause the
true-or-false-test eventually to test false looks like this:
(while test-whether-list-is-empty body...
set-list-to-cdr-of-list)
This test and use of cdr can be put together in a function that goes through a list
and prints each element of the list on a line of its own.
lion
tiger nil
Each element of the list is printed on a line of its own (that is what the function
print does) and then the value returned by the function is printed. Since the last
expression in the function is the while loop, and since while loops always return nil, a
nil is printed after the last element of the list.
(About 2500 years ago, Pythagoras and others developed the beginnings of number
theory by considering questions such as this.)
Suppose you want to know how many pebbles you will need to make a triangle
with 7 rows?
120 Chapter 11: Loops and Recursion
Clearly, what you need to do is add up the numbers from 1 to 7. There are two
ways to do this; start with the smallest number, one, and add up the list in sequence,
1, 2, 3, 4 and so on; or start with the largest number and add the list going down: 7,
6, 5, 4 and so on. Because both mechanisms illustrate common ways of writing while
loops, we will create two examples, one counting up and the other counting down. In
this first example, we will start with 1 and add 2, 3, 4 and so on.
If you are just adding up a short list of numbers, the easiest way to do it is to add
up all the numbers at once. However, if you do not know ahead of time how many
numbers your list will have, or if you want to be prepared for a very long list, then
you need to design your addition so that what you do is repeat a simple process
many times instead of doing a more complex process once.
For example, instead of adding up all the pebbles all at once, what you can do is
add the number of pebbles in the first row, 1, to the number in the second row, 2,
and then add the total of those two rows to the third row, 3. Then you can add the
number in the fourth row, 4, to the total of the first three rows; and so on.
The critical characteristic of the process is that each repetitive action is simple. In
this case, at each step we add only two numbers, the number of pebbles in the row
and the total already found. This process of adding two numbers is repeated again
and again until the last row has been added to the total of all the preceding rows. In a
more complex loop the repetitive action might not be so simple, but it will be
simpler than doing everything all at once.
(triangle 7)
The sum of the first four numbers is 10 and the sum of the first seven numbers is
28.
Section 11.1: while 123
11.1.4 Loop with a Decrementing Counter
Another common way to write a while loop is to write the test so that it determines
whether a counter is greater than zero. So long as the counter is greater than zero,
the loop is repeated. But when the counter is equal to or less than zero, the loop is
stopped. For this to work, the counter has to start out greater than zero and then be
made smaller and smaller by a form that is evaluated repeatedly.
The test will be an expression such as (>counter0) which returns t for true if the
value of counter is greater than zero, and nil for false if the value of counter is equal to
or less than zero. The expression that makes the number smaller and smaller can be
a simple setq such as (setqcounter(1-counter)), where 1- is a built-in function in
Emacs Lisp that subtracts 1 from its argument.
124 Chapter 11: Loops and Recursion
The template for a decrementing while loop looks like this:
(while (> counter 0) body... ; true-or-false-test
(reverse animals)
Here is how you could reverse the list using a while loop:
(setq animals '(gazelle giraffe lion tiger))
(reverse-list-with-while animals)
And here is how you could use the dolist macro:
(setq animals '(gazelle giraffe lion tiger))
(reverse-list-with-dolist animals)
In Info, you can place your cursor after the closing parenthesis of each expression
and type C-xC-e; in each case, you should see
(tiger lion giraffe gazelle) in the echo
area.
For this example, the existing reverse function is obviously best. The while loop is
just like our first example (see Section 11.1.1 “A while Loop and a List”, page 116).
The while first checks whether the list has elements; if so, it constructs a new list by
adding the first element of the list to the existing list (which in the first iteration of
the loop is nil). Since the second element is prepended in front of the first element,
and the third element is prepended in front of the second element, the list is
reversed.
In the expression using a while loop, the (setqlist(cdrlist)) expression shortens the
list, so the while loop eventually stops. In addition, it provides the cons expression
with a new first element by creating a new and shorter list at each repetition of the
loop.
The dolist expression does very much the same as the while expression, except
that the dolist macro does some of the work you have to do when writing a while
expression.
Like a while loop, a dolist loops. What is different is that it automatically shortens
the list each time it loops—it cdrs down the list on its own—and it automatically
binds the car of each shorter version of the list to the first of its arguments.
In the example, the car of each shorter version of the list is referred to using the
symbol ‘element’, the list itself is called ‘list’, and the value returned is called ‘value’.
The remainder of the dolist expression is the body.
The dolist expression binds the car of each shorter version of the list to element
and then evaluates the body of the expression; and repeats the loop. The result is
returned in value.
⇒ (2 1 0)
The way to use dotimes is to operate on some expression number number of times
and then return the result, either as a list or an atom.
Here is an example of a defun that uses dotimes to add up the number of pebbles
in a triangle.
(defun triangle-using-dotimes (number-of-rows)
"Using `dotimes', add up the number of pebbles in a triangle."
(let ((total 0)) ; otherwise a total is a void variable
(dotimes (number number-of-rows)
(setq total (+ total (1+ number)))) total))
(triangle-using-dotimes 4)
11.3 Recursion
A recursive function contains code that tells the Lisp interpreter to call a program
that runs exactly like itself, but with slightly different arguments. The code runs
exactly the same because it has the same name. However, even though the program
has the same name, it is not the same entity. It is different. In the jargon, it is a
different “instance”.
Eventually, if the program is written correctly, the slightly different arguments
will become sufficiently different from the first arguments that the final instance will
stop.
lion
tiger nil
An argument of 3 or 4
Suppose that triangle-recursively is called with an argument of 3.
Step 1 Evaluate the do-again-test.
The if expression is evaluated first. This is the do-again test and
returns false, so the else-part of the if expression is evaluated. (Note
that in this example, the do-again-test causes the function to call itself
when it tests false, not when it tests true.)
Step 2 Evaluate the innermost expression of the else-part.
The innermost expression of the else-part is evaluated, which
decrements 3 to 2. This is the next-step-expression.
Step 3 Evaluate the triangle-recursively function.
The number 2 is passed to the triangle-recursively function.
We already know what happens when Emacs evaluates triangle-
recursively with an argument of 2. After going through the sequence of
actions described earlier, it returns a value of 3. So that is what will
happen here.
Section 11.3: Recursion 133
Step 4 Evaluate the addition.
3 will be passed as an argument to the addition and will be added to
the number with which the function was called, which is 3.
The value returned by the function as a whole will be 6.
Now that we know what will happen when triangle-recursively is called with an
argument of 3, it is evident what will happen if it is called with an argument of
4:
In the recursive call, the evaluation of
(triangle-recursively (1- 4)) will return
the value of evaluating
(triangle-recursively 3) which is 6 and this value will be added to 4 by the
addition in the third line.
The value returned by the function as a whole will be 10.
Each time triangle-recursively is evaluated, it evaluates a version of itself— a
different instance of itself—with a smaller argument, until the argument is small
enough so that it does not evaluate itself.
Note that this particular design for a recursive function requires that operations
be deferred.
Before (triangle-recursively7) can calculate its answer, it must call
(triangle-recursively6); and before (triangle-recursively6) can calculate its answer, it
must call (triangle-recursively5); and so on. That is to say, the calculation that (triangle-
recursively7) makes must be deferred until (triangle-recursively6) makes its
calculation; and (triangle-recursively 6) must defer until (triangle-recursively5)
completes; and so on.
If each of these instances of triangle-recursively are thought of as different robots,
the first robot must wait for the second to complete its job, which must wait until the
third completes, and so on.
There is a way around this kind of waiting, which we will discuss in Section
11.3.7 “Recursion without Deferments”, page 136.
•
•
The basic pattern is:
If a list be empty, return nil.
Else, act on the beginning of the list (the car of the list)
− through a recursive call by the function on the rest (the cdr) of the list,
− and, optionally, combine the acted-on element, using cons, with the results
of acting on the rest.
Here is an example:
(defun square-each (numbers-list)
"Square each of a NUMBERS LIST, recursively."
(if (not numbers-list) ; do-again-test nil
(cons
(* (car numbers-list) (car numbers-list))
(square-each (cdr numbers-list))))) ; next-step-expression
•
•
But when the list has at least one element,
− act on the beginning of the list (the car of the list),
− and make a recursive call on the rest (the cdr) of the list.
•
•
If a list be empty, return nil.
Else, if the beginning of the list (the car of the list) passes a test
− act on that element and combine it, using cons with
− a recursive call by the function on the rest (the cdr) of the list.
• Otherwise, if the beginning of the list (the car of the list) fails the test
− skip on that element,
− and, recursively call the function on the rest (the cdr) of the list.
Here is an example that uses cond:
(defun keep-three-letter-words (word-list)
"Keep three letter words in WORD-LIST." (cond
;; First do-again-test: stop-condition
((not word-list) nil)
•
•
What happens when we call this function with an argument of 7?
The first instance of the triangle-recursively function adds the number 7 to the
value returned by a second instance of triangle-recursively, an instance that has been
passed an argument of 6. That is to say, the first calculation is:
(+ 7 (triangle-recursively 6))
Section 11.3: Recursion 139
The first instance of triangle-recursively—you may want to think of it as a little robot
—cannot complete its job. It must hand off the calculation for
(triangle-recursively6) to a second instance of the program, to a second robot. This
second individual is completely different from the first one; it is, in the jargon, a
“different instantiation”. Or, put another way, it is a different robot. It is the same
model as the first; it calculates triangle numbers recursively; but it has a different
serial number.
And what does (triangle-recursively6) return? It returns the number 6 added to
the value returned by evaluating triangle-recursively with an argument of 5. Using the
robot metaphor, it asks yet another robot to help it.
Now the total is:
(+ 7 6 (triangle-recursively 5)) And what
happens next?
(+ 7 6 5 (triangle-recursively 4))
Each time triangle-recursively is called, except for the last time, it creates another
instance of the program—another robot—and asks it to make a calculation.
Eventually, the full addition is set up and performed:
(+ 7 6 5 4 3 2 1)
This design for the function defers the calculation of the first step until the
second can be done, and defers that until the third can be done, and so on. Each
deferment means the computer must remember what is being waited on. This is not
a problem when there are only a few steps, as in this example. But it can be a
problem when there are more steps.
14 The phrase tail recursive is used to describe such a process, one that uses constant
space.
140 Chapter 11: Loops and Recursion
(triangle-recursive-helper (+ sum counter) ; sum (1+ counter) ;
counter number))) ; number
Install both function definitions by evaluating
them, then call triangle-initialization with 2 rows:
(triangle-initialization 2)
⇒3
The initialization function calls the first instance of the helper function with
three arguments: zero, zero, and a number which is the number of rows in the
triangle.
The first two arguments passed to the helper function are initialization values.
These values are changed when triangle-recursive-helper invokes new instances.15
Let’s see what happens when we have a triangle that has one row. (This triangle
will have one pebble in it!) triangle-initialization will call its helper with the
arguments 001. That
function will run the conditional test whether (>counternumber):
(> 0 1)
and find that the result is false, so it will invoke the else-part of the if clause:
(triangle-recursive-helper
(+ sum counter) ; sum plus counter ⇒ sum
(1+ counter) ; increment counter ⇒ counter number) ; number
stays the same
Section 11.4: Looping Exercise
(triangle-recursive-helper 0 1 1)
Again, (>counternumber) will be false, so again, the Lisp interpreter will evaluate
triangle-recursive-helper, creating a new instance with new arguments. This new
instance will be;
(triangle-recursive-helper
(+ sum counter) ; sum plus counter ⇒ sum
(1+ counter) ; increment counter ⇒ counter number) ; number
stays the same
(triangle-recursive-helper 1 2 1)
In this case, the (>counternumber) test will be true! So the instance will return the
value of the sum, which will be 1, as expected.
Now, let’s pass triangle-initialization an argument of 2, to find out how many
pebbles there are in a triangle with two rows.
That function calls (triangle-recursive-helper002).
In stages, the instances called will be:
sum counter number
(triangle-recursive-helper 0 1 2)
(triangle-recursive-helper 1 2 2)
(triangle-recursive-helper 3 3 2)
When the last instance is called, the (>counternumber) test will be true, so the
instance will return the value of sum, which will be 3.
This kind of pattern helps when you are writing functions that can use many
resources in a computer.
12.3 forward-sentence
The command to move the cursor forward a sentence is a straightforward
illustration of how to use regular expression searches in Emacs Lisp. Indeed, the
function looks longer and more complicated than it is; this is because the function is
145
designed to go backwards as well as forwards; and, optionally, over more than one
sentence. The function is usually bound to the key command M-e.
Here is the code for forward-sentence:
(defun forward-sentence (&optional arg)
"Move forward to next end of sentence. With argument, repeat.
With negative argument, move backward repeatedly to start of sentence.
The variable `sentence-end' is a regular expression that matches ends of sentences. Also,
every paragraph boundary terminates sentences as well."
(interactive "p")
(or arg (setq arg 1))
(let ((opoint (point))
(sentence-end (sentence-end)))
(while (< arg 0)
(let ((pos (point))
(par-beg (save-excursion (start-of-paragraph-text) (point)))) (if (and (re-search-
backward sentence-end par-beg t)
(or (< (match-end 0) pos)
(re-search-backward sentence-end par-beg t)))
(goto-char (match-end 0))
(goto-char par-beg)))
(setq arg (1+ arg)))
(while (> arg 0)
(let ((par-end (save-excursion (end-of-paragraph-text) (point)))) (if (re-search-forward
sentence-end par-end t)
(skip-chars-backward " \t\n")
(goto-char par-end)))
(setq arg (1- arg)))
(constrain-to-field nil opoint t)))
The function looks long at first sight and it is best to look at its skeleton first, and
then its muscle. The way to see the skeleton is to look at the expressions that start in
the left-most columns:
(defun forward-sentence (&optional arg)
"documentation..."
(interactive "p")
(or arg (setq arg 1))
(let ((opoint (point)) (sentence-end (sentence-end)))
(while (< arg 0)
(let ((pos (point))
(par-beg (save-excursion (start-of-paragraph-text) (point)))) rest-of-body-of-
while-loop-when-going-backwards
(while (> arg 0)
(let ((par-end (save-excursion (end-of-paragraph-text) (point)))) rest-of-body-of-while-
loop-when-going-forwards
handle-forms-and-equivalent
146 Chapter 12: Regular Expression Searches
This looks much simpler! The function definition consists of documentation, an
interactive expression, an or expression, a let expression, and while loops.
Let’s look at each of these parts in turn.
We note that the documentation is thorough and understandable.
The function has an interactive"p" declaration. This means that the processed
prefix argument, if any, is passed to the function as its argument. (This will Section
12.3: forward-sentence
be a number.) If the function is not passed an argument (it is optional) then the
argument arg will be bound to 1.
When forward-sentence is called non-interactively without an argument, arg is
bound to nil. The or expression handles this. What it does is either leave the value of
arg as it is, but only if arg is bound to a value; or it sets the value of arg to 1, in the
case when arg is bound to nil.
Next is a let. That specifies the values of two local variables, opoint and sentence-
end. The local value of point, from before the search, is used in the constrain-to-field
function which handles forms and equivalents. The sentence-end variable is set by
the sentence-end function.
The first parts of the function are routine: the function’s argument list consists of
one optional argument. Documentation follows.
The lower case ‘p’ in the interactive declaration means that the processed prefix
argument, if any, is passed to the function. This will be a number, and is the repeat
count of how many paragraphs point will move. The or expression in the next line
handles the common case when no argument is passed to the function, which occurs
if the function is called from other code rather than interactively. This case was
described earlier. (See Section 12.3 “forward-sentence”, page 143.) Now we reach the
end of the familiar part of this function.
The variable opoint is just the value of point. As you can guess, it is used in a
constrain-to-field expression, just as in forward-sentence.
The variable fill-prefix-regexp is set to the value returned by evaluating the following
list:
(and fill-prefix
(not (equal fill-prefix ""))
(not paragraph-ignore-fill-prefix)
(regexp-quote fill-prefix))
This is an expression whose first element is the and special form.
As we learned earlier (see “The kill-new function”, page 97), the and special form
evaluates each of its arguments until one of the arguments returns a value of nil, in
which case the and expression returns nil; however, if none of the arguments returns
a value of nil, the value resulting from evaluating the last argument is returned.
(Since such a value is not nil, it is considered true in Lisp.) In other words, an and
expression returns a true value only if all its arguments are true.
In this case, the variable fill-prefix-regexp is bound to a non-nil value only if the
following four expressions produce a true (i.e., a non-nil) value when they are
evaluated; otherwise, fill-prefix-regexp is bound to nil.
fill-prefix
When this variable is evaluated, the value of the fill prefix, if any, is returned.
If there is no fill prefix, this variable returns nil.
(not(equalfill-prefix"")
This expression checks whether an existing fill prefix is an empty
string, that is, a string with no characters in it. An empty string is not a
useful fill prefix.
(notparagraph-ignore-fill-prefix)
This expression returns nil if the variable paragraph-ignore-fillprefix has been
turned on by being set to a true value such as t.
(regexp-quotefill-prefix)
This is the last argument to the and special form. If all the arguments to
the and are true, the value resulting from evaluating this expression
will be returned by the and expression and bound to the variable fill-
prefix-regexp,
The result of evaluating this and expression successfully is that fill-prefixregexp will
be bound to the value of fill-prefix as modified by the regexp-quote function. What
regexp-quote does is read a string and return a regular expression that will exactly
match the string and match nothing else. This means that fill-prefix-regexp will be set
152 Chapter 12: Regular Expression Searches
to a value that will exactly match the fill prefix if the fill prefix exists. Otherwise, the
variable will be set to nil.
The next two local variables in the let* expression are designed to remove
instances of ‘^’ from parstart and parsep, the local variables which indicate the
paragraph start and the paragraph separator. The next expression sets parsep again.
That is to handle fill prefixes.
This is the setting that requires the definition call let* rather than let. The true-
or-false-test for the if depends on whether the variable fill-prefix-regexp evaluates to
nil or some other value.
If fill-prefix-regexp does not have a value, Emacs evaluates the else-part of the if
expression and binds parsep to its local value. (parsep is a regular expression that
matches what separates paragraphs.)
But if fill-prefix-regexp does have a value, Emacs evaluates the then-part of the if
expression and binds parsep to a regular expression that includes the fill-prefix-
regexp as part of the pattern.
Specifically, parsep is set to the original value of the paragraph separate regular
expression concatenated with an alternative expression that consists of the fill-prefix-
regexp followed by optional whitespace to the end of the line. The whitespace is
defined by "[\t]*$".) The ‘\\|’ defines this portion of the regexp as an alternative to
parsep.
According to a comment in the code, the next local variable, sp-parstart, is used for
searching, and then the final two, start and found-start, are set to nil.
Now we get into the body of the let*. The first part of the body of the let* deals
with the case when the function is given a negative argument and is therefore
moving backwards. We will skip this section.
;; between paragraphs
;; Move forward over separator lines... (while (and (not
(eobp))
(progn (move-to-left-margin) (not (eobp)))
(looking-at parsep))
Section 12.4: forward-paragraph: a Goldmine of Functions 153
(forward-line 1))
;; This decrements the loop
(unless (eobp) (setq arg (1- arg))) ;; ... and one
more line. (forward-line 1)
(if fill-prefix-regexp
;; There is a fill prefix; it overrides parstart;
;; we go forward line by line (while (and (not
(eobp))
(progn (move-to-left-margin) (not (eobp)))
(not (looking-at parsep))
(looking-at fill-prefix-regexp))
(forward-line 1))
;; There is no fill prefix;
;; we go forward character by character
(while (and (re-search-forward sp-parstart nil 1)
(progn (setq start (match-beginning 0))
(goto-char start)
(not (eobp)))
(progn (move-to-left-margin)
(not (looking-at parsep))) (or (not
(looking-at parstart)) (and use-hard-newlines
(not (get-text-property (1- start) 'hard))))) (forward-char 1))
is only invoked for its side effect, which is to move point to the left margin of the
current line.
The looking-at function is also self-explanatory; it returns true if the text after point
matches the regular expression given as its argument.
The rest of the body of the loop looks difficult at first, but makes sense as you come to
understand it.
First consider what happens if there is a fill prefix:
(if fill-prefix-regexp
;; There is a fill prefix; it overrides parstart;
;; we go forward line by line (while (and (not
(eobp))
(progn (move-to-left-margin) (not (eobp)))
(not (looking-at parsep))
(looking-at fill-prefix-regexp))
(forward-line 1))
This expression moves point forward line by line so long as four conditions are true:
1. Point is not at the end of the buffer.
2. We can move to the left margin of the text and are not at the end of the buffer.
3. The text following point does not separate paragraphs.
4. The pattern following point is the fill prefix regular expression.
The last condition may be puzzling, until you remember that point was moved to
the beginning of the line early in the forward-paragraph function. This means that if the
text has a fill prefix, the looking-at function will see it.
Consider what happens when there is no fill prefix.
(while (and (re-search-forward sp-parstart nil 1)
(progn (setq start (match-beginning 0))
(goto-char start)
(not (eobp)))
(progn (move-to-left-margin)
(not (looking-at parsep))) (or (not
(looking-at parstart)) (and use-hard-newlines
(not (get-text-property (1- start) 'hard))))) (forward-char 1))
This while loop has us searching forward for sp-parstart, which is the combination of
possible whitespace with the local value of the start of a paragraph or of a paragraph
separator. (The latter two are within an expression starting \(?: so that they are not
referenced by the match-beginning function.)
The two expressions,
(setq start (match-beginning 0))
(goto-char start) mean go to the start of the text matched by the regular
expression search.
The (match-beginning0) expression is new. It returns a number specifying the
location of the start of the text that was matched by the last search.
Section 12.4: forward-paragraph: a Goldmine of Functions 155
12.5 Review
Here is a brief summary of some recently introduced functions.
while Repeatedly evaluate the body of the expression so long as the first
element of the body tests true. Then return nil. (The expression is
evaluated only for its side effects.) For example:
(let ((foo 2))
(while (> foo 0)
(insert (format "foo is %d.\n" foo))
(setq foo (1- foo))))
⇒ foo is 2. foo is
1. nil
(The insert function inserts its arguments at point; the format function
returns a string formatted from its arguments the way message
formats its arguments; \n produces a new line.)
re-search-forward
Search for a pattern, and if the pattern is found, move point to rest just
after it.
Takes four arguments, like search-forward:
1. A regular expression that specifies the pattern to search for.
(Remember to put quotation marks around this argument!)
2. Optionally, the limit of the search.
Section 13.1: The count-words-example Function 157
3. Optionally, what to do if the search fails, return nil or an error
message.
4. Optionally, how many times to repeat the search; if negative,
thesearch goes backwards.
let* Bind some variables locally to particular values, and then evaluate the remaining
arguments, returning the value of the last one. While binding the local
variables, use the local values of variables bound earlier, if any.
For example:
(let* ((foo 7)
(bar (* 3 foo))) (message "`bar'
is %d." bar)) ⇒ ‘bar’ is 21.
match-beginning
Return the position of the start of the text found by the last regular
expression search.
looking-at
Return t for true if the text after point matches the argument, which
should be a regular expression.
eobp Return t for true if point is at the end of the accessible part of a buffer. The end
of the accessible part is the end of the buffer if the buffer is not
narrowed; it is the end of the narrowed part if the buffer is narrowed.
The function counts words within a region. This means that the argument list
must contain symbols that are bound to the two positions, the beginning and end of
the region. These two positions can be called ‘beginning’ and ‘end’ respectively. The
first line of the documentation should be a single sentence, since that is all that is
printed as documentation by a command such as apropos. The interactive expression
will be of the form ‘(interactive"r")’, since that will cause Emacs to pass the beginning
and end of the region to the function’s argument list. All this is routine.
The body of the function needs to be written to do three tasks: first, to set up
conditions under which the while loop can count words, second, to run the while
loop, and third, to send a message to the user.
When a user calls count-words-example, point may be at the beginning or the end
of the region. However, the counting process must start at the beginning of the
region. This means we will want to put point there if it is not already there.
Executing (goto-charbeginning) ensures this. Of course, we will want to return point
to its expected position when the function finishes its work. For this reason, the body
must be enclosed in a save-excursion expression.
The central part of the body of the function consists of a while loop in which one
expression jumps point forward word by word, and another expression counts those
jumps. The true-or-false-test of the while loop should test true so long as point
should jump forward, and false when point is at the end of the region.
We could use (forward-word1) as the expression for moving point forward word
by word, but it is easier to see what Emacs identifies as a “word” if we use a regular
expression search.
A regular expression search that finds the pattern for which it is searching leaves
point after the last character matched. This means that a succession of successful
word searches will move point forward word by word.
As a practical matter, we want the regular expression search to jump over
whitespace and punctuation between words as well as over the words themselves. A
regexp that refuses to jump over interword whitespace would never jump more than
one word! This means that the regexp should include the whitespace and
punctuation that follows a word, if any, as well as the word itself. (A word may end a
buffer and not have any following whitespace or punctuation, so that part of the
regexp must be optional.)
Thus, what we want for the regexp is a pattern defining one or more word
constituent characters followed, optionally, by one or more characters that are not
word constituents. The regular expression for this is:
\w+\W*
The buffer’s syntax table determines which characters are and are not word
constituents. For more information about syntax, see Section “Syntax Tables” in The
GNU Emacs Lisp Reference Manual.
The search expression looks like this:
(re-search-forward "\\w+\\W*")
160 Chapter 13: Counting via Repetition and Regexps
(Note that paired backslashes precede the ‘w’ and ‘W’. A single backslash has special
meaning to the Emacs Lisp interpreter. It indicates that the following character is
interpreted differently than usual. For example, the two characters, ‘\n’, stand for
‘newline’, rather than for a backslash followed by ‘n’. Two backslashes in a row stand
for an ordinary, unspecial backslash, so Emacs Lisp interpreter ends of seeing a
single backslash followed by a letter. So it discovers the letter is special.)
We need a counter to count how many words there are; this variable must first
be set to 0 and then incremented each time Emacs goes around the while loop. The
incrementing expression is simply:
(setq count (1+ count))
Finally, we want to tell the user how many words there are in the region. The
message function is intended for presenting this kind of information to the user. The
message has to be phrased so that it reads properly regardless of how many words
there are in the region: we don’t want to say that “there are 1 words in the region”.
The conflict between singular and plural is ungrammatical. We can solve this
problem by using a conditional expression that evaluates different messages
depending on the number of words in the region. There are three possibilities: no
words in the region, one word in the region, and more than one word. This means
that the cond special form is appropriate.
Section 13.1: The count-words-example Function 161
In the count-words-example definition, the value of the end of the region is held by
the variable end which is passed as an argument to the function. Thus, we can add
end as an argument to the regular expression search expression:
(re-search-forward "\\w+\\W*" end)
However, if you make only this change to the count-words-example definition and
then test the new version of the definition on a stretch of whitespace, you will
receive an error message saying ‘Searchfailed’.
What happens is this: the search is limited to the region, and fails as you expect
because there are no word-constituent characters in the region. Since it fails, we
receive an error message. But we do not want to receive an error message in this
case; we want to receive the message “The region does NOT have any words.”
The solution to this problem is to provide re-search-forward with a third
argument of t, which causes the function to return nil rather than signal an error if
the search fails.
However, if you make this change and try it, you will see the message “Counting
words in region ... ” and . . . you will keep on seeing that message . . ., until you type C-
g (keyboard-quit).
Here is what happens: the search is limited to the region, as before, and it fails
because there are no word-constituent characters in the region, as expected.
Consequently, the re-search-forward expression returns nil. It does nothing else. In
particular, it does not move point, which it does as a side effect if it finds the search
target. After the re-search-forward expression returns nil, the next expression in the
while loop is evaluated. This expression increments the count. Then the loop repeats.
The true-or-false-test tests true because the value of point is still less than the value
of end, since the re-search-forward expression did not move point. . . . and the cycle
repeats . . .
The count-words-example definition requires yet another modification, to cause
the true-or-false-test of the while loop to test false if the search fails. Put another
way, there are two conditions that must be satisfied in the true-or-false-test before
the word count variable is incremented: point must still be within the region and the
search expression must have found a word to count.
Since both the first condition and the second condition must be true together, the
two expressions, the region test and the search expression, can be joined with an and
special form and embedded in the while loop as the true-or-false-test, like this:
(and (< (point) end) (re-search-forward "\\w+\\W*" end t))
(For information about and, see “The kill-new function”, page 97.)
The re-search-forward expression returns t if the search succeeds and as a side
effect moves point. Consequently, as words are found, point is moved through the
region. When the search expression fails to find another word, or when point
reaches the end of the region, the true-or-false-test tests false, the while loop exits,
and the count-words-example function displays one or other of its messages.
164 Chapter 13: Counting via Repetition and Regexps
This is the function that the user will call. It will be interactive. Indeed, it will be
similar to our previous versions of this function, except that it will call recursive-
count-words to determine how many words are in the region.
We can readily construct a template for this function, based on our previous
versions:
;; Recursive version; uses regular expression search
(defun count-words-example (beginning end)
"documentation..."
(interactive-expression...)
((= 1 count)
(message
"The region has 1 word."))
(t
(message
"The region has %d words." count)))))) Next, we need
to write the recursive counting function.
A recursive function has at least three parts: the do-again-test, the next-
stepexpression, and the recursive call.
The do-again-test determines whether the function will or will not be called
again. Since we are counting words in a region and can use a function that moves
point forward for every word, the do-again-test can check whether point is still
within the region. The do-again-test should find the value of point and determine
whether point is before, at, or after the value of the end of the region. We can use the
point function to locate point. Clearly, we must pass the value of the end of the region
to the recursive counting function as an argument.
In addition, the do-again-test should also test whether the search finds a word. If
it does not, the function should not call itself again.
The next-step-expression changes a value so that when the recursive function is
supposed to stop calling itself, it stops. More precisely, the next-step-expression
changes a value so that at the right time, the do-again-test stops the recursive
function from calling itself again. In this case, the next-step-expression can be the
expression that moves point forward, word by word.
The third part of a recursive function is the recursive call.
Somewhere, we also need a part that does the work of the function, a part that
does the counting. A vital part!
But already, we have an outline of the recursive counting function:
(defun recursive-count-words (region-end)
"documentation..." do-again-test next-
step-expression recursive call)
Now we need to fill in the slots. Let’s start with the simplest cases first: if point is
at or beyond the end of the region, there cannot be any words in the region, so the
function should return zero. Likewise, if the search fails, there are no words to count,
so the function should return zero.
On the other hand, if point is within the region and the search succeeds, the
function should call itself again.
Thus, the do-again-test should look like this:
(and (< (point) region-end)
(re-search-forward "\\w+\\W*" region-end t))
Note that the search expression is part of the do-again-test—the function returns
t if its search succeeds and nil if it fails. (See Section 13.1.1 “The Whitespace Bug in
count-words-example”, page 158, for an explanation of how re-searchforward works.)
168 Chapter 13: Counting via Repetition and Regexps
;;; 1. do-again-test
(if (and (< (point) region-end)
(re-search-forward "\\w+\\W*" region-end t))
;;; 3. else-part
0))
Let’s examine how this works:
If there are no words in the region, the else part of the if expression is evaluated
and consequently the function returns zero.
If there is one word in the region, the value of point is less than the value of
region-end and the search succeeds. In this case, the true-or-false-test of the if
expression tests true, and the then-part of the if expression is evaluated. The
counting expression is evaluated. This expression returns a value (which will be the
value returned by the whole function) that is the sum of one added to the value
returned by a recursive call.
Meanwhile, the next-step-expression has caused point to jump over the first (and
in this case only) word in the region. This means that when (recursive-
countwordsregion-end) is evaluated a second time, as a result of the recursive call, the
value of point will be equal to or greater than the value of region end. So this time,
recursive-count-words will return zero. The zero will be added to one, and the original
evaluation of recursive-count-words will return one plus zero, which is one, which is
the correct amount.
Clearly, if there are two words in the region, the first call to recursive-countwords
returns one added to the value returned by calling recursive-count-words on a region
containing the remaining word—that is, it adds one to one, producing two, which is
the correct amount.
Similarly, if there are three words in the region, the first call to recursive-count-
words returns one added to the value returned by calling recursive-count-words on a
region containing the remaining two words—and so on and so on.
With full documentation the two functions look like this: The
recursive function:
(defun recursive-count-words (region-end)
"Number of words between point and REGION-END."
;;; 1. do-again-test
(if (and (< (point) region-end)
(re-search-forward "\\w+\\W*" region-end t))
170 Chapter 13: Counting via Repetition and Regexps
;;; 3. else-part
0)) The
wrapper:
;;; Recursive version
(defun count-words-example (beginning end) "Print number
of words in the region.
visiting the file already exists Emacs returns that one. In this case, the buffer may be
narrowed and must be widened. If we wanted to be fully user-friendly, we would
arrange to save the restriction and the location of point, but we won’t.
The (goto-char(point-min)) expression moves point to the beginning of the buffer.
Then comes a while loop in which the work of the function is carried out. In the
loop, Emacs determines the length of each definition and constructs a lengths’ list
containing the information.
Emacs kills the buffer after working through it. This is to save space inside of
Emacs. My version of GNU Emacs 19 contained over 300 source files of interest; GNU
Emacs 22 contains over a thousand source files. Another function will apply lengths-
list-file to each of the files.
179
Finally, the last expression within the let expression is the lengths-list variable; its
value is returned as the value of the whole function.
You can try this function by installing it in the usual fashion. Then place your cursor
after the following expression and type C-xC-e (eval-last-sexp).
(lengths-list-file
"/usr/local/share/emacs/22.1/lisp/emacs-lisp/debug.el")
You may need to change the pathname of the file; the one here is for GNU Emacs
version 22.1. To change the expression, copy it to the *scratch* buffer and edit it.
Also, to see the full length of the list, rather than a truncated version, you may have to
evaluate the following:
(custom-set-variables '(eval-expression-print-length nil))
(See Section 16.2 “Specifying Variables using defcustom”, page 197. Then evaluate the
lengths-list-file expression.)
The lengths’ list for debug.el takes less than a second to produce and looks like this
in GNU Emacs 22:
(83 113 105 144 289 22 30 97 48 89 25 52 52 88 28 29 77 49 43 290 232 587)
(Using my old machine, the version 19 lengths’ list for debug.el took seven seconds
to produce and looked like this:
(75 41 80 62 20 45 44 68 45 12 34 235)
The newer version of debug.el contains more defuns than the earlier one; and my new
machine is much faster than the old one.)
Note that the length of the last definition in the file is first in the list.
;;; true-or-false-test
(while list-of-files
(setq lengths-list
(append lengths-list
(lengths-list-file "./lisp/macros.el")
⇒ (283 263 480 90)
(lengths-list-file "./lisp/mail/mailalias.el")
⇒ (38 32 29 95 178 180 321 218 324)
(lengths-list-file "./lisp/hex-util.el")
⇒ (82 71)
(recursive-lengths-list-many-files
182 Chapter 14: Counting Words in a defun
'("./lisp/macros.el"
"./lisp/mail/mailalias.el"
"./lisp/hex-util.el"))
⇒ (283 263 480 90 38 32 29 95 178 180 321 218 324 82 71)
1
If current-time-list is nil the three timestamps are
(1351051674579989697 . 1000000000), (1173477761000000000 .
Section 14.9: Prepare the Data for Display in a Graph 185
(let (el-files-list
(current-directory-list
(directory-files-and-attributes directory t)))
;; while we are in the current directory
(while current-directory-list
(cond
;; check to see whether filename ends in '.el' ;; and if so, add
its name to a list.
((equal ".el" (substring (car (car current-directory-list)) -3)) (setq el-files-list
(cons (car (car current-directory-list)) el-files-list)))
;; check whether filename is that of a directory
((eq t (car (cdr (car current-directory-list))))
;; decide whether to skip or recurse (if
(equal "."
(substring (car (car current-directory-list)) -1))
;; then do nothing since filename is that of
;; current directory or parent, "." or ".."
()
;; else descend into the directory and repeat the process (setq el-files-list
(append
(files-in-below-directory
(car (car current-directory-list))) el-files-list)))))
;; move to the next filename in the list; this also
;; shortens the list so the while loop eventually comes to an end
(setq current-directory-list (cdr current-directory-list)))
;; return the filenames el-files-list))
The files-in-below-directory directory-files function takes one argument, the name
of a directory.
Thus, on my system,
(length
(files-in-below-directory "/usr/local/share/emacs/22.1.1/lisp/")) tells me that in and
below my Lisp sources directory are 1031 ‘.el’ files.
files-in-below-directory returns a list in reverse alphabetical order. An
expression to sort the list in alphabetical order looks like this:
(sort
(files-in-below-directory "/usr/local/share/emacs/22.1.1/lisp/") 'string-lessp)
With a sorted list of numbers, this is easy: count how many elements of the list
are smaller than 10, then, after moving past the numbers just counted, count how
many are smaller than 20, then, after moving past the numbers just counted, count
how many are smaller than 30, and so on. Each of the numbers, 10, 20, 30, 40, and
the like, is one larger than the top of that range. We can call the list of such numbers
the top-of-ranges list.
If we wished, we could generate this list automatically, but it is simpler to write a
list manually. Here it is:
(defvar top-of-ranges
'(10 20 30 40 50
60 70 80 90 100
110 120 130 140 150
160 170 180 190 200
210 220 230 240 250
260 270 280 290 300)
"List specifying ranges for `defuns-per-range'.") To change the
ranges, we edit this list.
Next, we need to write the function that creates the list of the number of
definitions within each range. Clearly, this function must take the sorted-lengths and
the top-of-ranges lists as arguments.
The defuns-per-range function must do two things again and again: it must count
the number of definitions within a range specified by the current top-of-range value;
and it must shift to the next higher value in the top-of-ranges list after counting the
number of definitions in the current range. Since each of these actions is repetitive,
we can use while loops for the job. One loop counts the number of definitions in the
range defined by the current top-of-range value, and the other loop selects each of
the top-of-range values in turn.
Several entries of the sorted-lengths list are counted for each range; this means
that the loop for the sorted-lengths list will be inside the loop for the top-ofranges list,
like a small gear inside a big gear.
The inner loop counts the number of definitions within the range. It is a simple
counting loop of the type we have seen before. (See Section 11.1.3 “A loop with an
incrementing counter”, page 118.) The true-or-false test of the loop tests whether
the value from the sorted-lengths list is smaller than the current value of the top of
the range. If it is, the function increments the counter and tests the next value from
the sorted-lengths list.
The inner loop looks like this:
(while length-element-smaller-than-top-of-range
(setq number-within-range (1+ number-within-range))
(setq sorted-lengths (cdr sorted-lengths)))
The outer loop must start with the lowest value of the top-of-ranges list, and then
be set to each of the succeeding higher values in turn. This can be done with a loop
like this:
188 Chapter 14: Counting Words in a defun
;; Outer loop.
(while top-of-ranges
;; Inner loop.
(while (and
;; Need number for numeric test.
Section 14.9: Prepare the Data for Display in a Graph 189
(car sorted-lengths)
(< (car sorted-lengths) top-of-range))
(setq defuns-per-range-list
(cons number-within-range defuns-per-range-list)) (setq number-
within-range 0); Reset count to zero.
;; Exit outer loop and count the number of defuns larger than ;; the
largest top-of-range value.
(setq defuns-per-range-list
(cons
(length sorted-lengths) defuns-per-range-list))
long as the list has at least one number within it, but returns nil if the list is empty.
The and expression first evaluates the (carsorted-lengths) expression, and if it is nil,
returns false without evaluating the < expression. But if the (carsorted-lengths)
expression returns a non-nil value, the and expression evaluates the < expression,
and returns that value as the value of the and expression. This way, we avoid an
error.
(For information about and, see “The kill-new function”, page 97.)
Here is a short test of the defuns-per-range function. First, evaluate the expression
that binds (a shortened) top-of-ranges list to the list of values, then evaluate the
expression for binding the sorted-lengths list, and then evaluate the defuns-per-range
function.
;; (Shorter list than we will use later.)
(setq top-of-ranges
'(110 120 130 140 150
160 170 180 190 200))
(setq sorted-lengths
'(85 86 110 116 122 129 154 176 179 200 265 300 300))
;; Fill in asterisks.
(while (> actual-height 0)
(setq insert-list (cons "*" insert-list))
(setq actual-height (1- actual-height)))
;; Fill in blanks.
(while (> number-of-top-blanks 0)
(setq insert-list (cons " " insert-list)) (setq number-of-
top-blanks (1- number-of-top-blanks)))
;; Fill in graph-symbols.
(while (> actual-height 0)
(setq insert-list (cons graph-symbol insert-list))
(setq actual-height (1- actual-height)))
;; Fill in graph-blanks.
(while (> number-of-top-blanks 0)
(setq insert-list (cons graph-blank insert-list)) (setq number-of-
top-blanks (1- number-of-top-blanks)))
(while numbers-list
(setq from-position (point))
(insert-rectangle
(column-of-graph height (car numbers-list)))
197
(goto-char from-position) (forward-
char symbol-width) ;; Draw graph
column by column.
(sit-for 0)
(setq numbers-list (cdr numbers-list))) ;; Place point
for X axis labels.
(forward-line height)
(insert "\n")
))
The one unexpected expression in this function is the (sit-for0) expression in the
while loop. This expression makes the graph printing operation more interesting to
watch than it would be otherwise. The expression causes Emacs to sit or do nothing
for a zero length of time and then redraw the screen. Placed here, it causes Emacs to
redraw the screen column by column. Without it, Emacs would not redraw the
screen until the function exits.
We can test graph-body-print with a short list of numbers.
1. Install graph-symbol, graph-blank, column-of-graph, which are in Chapter 15
“Readying a Graph”, page 187, and graph-body-print.
2. Copy the following expression:
(graph-body-print '(1 2 3 4 6 4 3 5 7 6 5 2 3))
3. Switch to the *scratch* buffer and place the cursor where you want the graph to
start.
4. Type M-: (eval-expression).
5. Yank the graph-body-print expression into the minibuffer with C-y (yank).
6. Press RET to evaluate the graph-body-print expression.
Emacs will print a graph like this:
*
* **
* ****
*** ****
********* * ************
*************
15.2 The recursive-graph-body-print Function
The graph-body-print function may also be written recursively. The recursive solution
is divided into two parts: an outside wrapper that uses a let expression to determine
the values of several variables that need only be found once, such as the maximum
height of the graph, and an inside function that is called recursively to print the
graph.
The wrapper is uncomplicated:
(defun recursive-graph-body-print (numbers-list) "Print a bar graph of
the NUMBERS-LIST.
198 Chapter 15: Readying a Graph
The numbers-list consists of the Y-axis values."
(let ((height (apply 'max numbers-list)) (symbol-width (length graph-
blank)) from-position)
(recursive-graph-body-print-internal numbers-
list height symbol-width)))
The recursive function is a little more difficult. It has four parts: the do-againtest,
the printing code, the recursive call, and the next-step-expression. The doagain-test
is a when expression that determines whether the numbers-list contains any
remaining elements; if it does, the function prints one column of the graph using the
printing code and calls itself again. The function calls itself again according to the
value produced by the next-step-expression which causes the call to act on a shorter
version of the numbers-list.
(defun recursive-graph-body-print-internal (numbers-
list height symbol-width) "Print a bar graph.
Used within recursive-graph-body-print function."
(when numbers-list
(setq from-position (point))
(insert-rectangle
(column-of-graph height (car numbers-list)))
(goto-char from-position)
(forward-char symbol-width)
(sit-for 0) ; Draw graph column by column.
(recursive-graph-body-print-internal
(cdr numbers-list) height symbol-width)))
Section 15.4: Exercise
15.4 Exercise
Write a line graph version of the graph printing functions.
200 Chapter 16: Your .emacs File
16 Your .emacs File
“You don’t have to like Emacs to like it”—this seemingly paradoxical statement is the
secret of GNU Emacs. The plain, out-of-the-box Emacs is a generic tool. Most people
who use it customize it to suit themselves.
GNU Emacs is mostly written in Emacs Lisp; this means that by writing expressions
in Emacs Lisp you can change or extend Emacs.
There are those who appreciate Emacs’s default configuration. After all, Emacs
starts you in C mode when you edit a C file, starts you in Fortran mode when you edit
a Fortran file, and starts you in Fundamental mode when you edit an unadorned file.
This all makes sense, if you do not know who is going to use Emacs. Who knows
what a person hopes to do with an unadorned file? Fundamental mode is the right
default for such a file, just as C mode is the right default for editing C code. (Enough
programming languages have syntaxes that enable them to share or nearly share
features, so C mode is now provided by CC mode, the C Collection.)
But when you do know who is going to use Emacs—you, yourself—then it makes
sense to customize Emacs.
For example, I seldom want Fundamental mode when I edit an otherwise
undistinguished file; I want Text mode. This is why I customize Emacs: so it suits me.
You can customize and extend Emacs by writing or adapting a ~/.emacs file. This
is your personal initialization file; its contents, written in Emacs Lisp, tell Emacs
what to do.16
A ~/.emacs file contains Emacs Lisp code. You can write this code yourself; or you
can use Emacs’s customize feature to write the code for you. You can combine your
own expressions and auto-written Customize expressions in your .emacs file.
(I myself prefer to write my own expressions, except for those, particularly fonts,
that I find easier to manipulate using the customize command. I combine the two
methods.)
Most of this chapter is about writing expressions yourself. It describes a simple
.emacs file; for more information, see Section “The Init File” in The GNU Emacs
Manual, and Section “The Init File” in The GNU Emacs Lisp Reference Manual.
16 You may also add .el to ~/.emacs and call it a ~/.emacs.el file. In the past, you were
forbidden to type the extra keystrokes that the name ~/.emacs.el requires, but now you may.
The new format is consistent with the Emacs Lisp file naming conventions; the old format
saves typing.
201
(Dumped copies of Emacs load more quickly. However, once a file is Section 16.2:
Specifying Variables using defcustom
loaded and dumped, a change to it does not lead to a change in Emacs unless you
load it yourself or re-dump Emacs. See Section “Building Emacs” in The GNU Emacs
Lisp Reference Manual, and the INSTALL file.)
Three other site-wide initialization files are loaded automatically each time you
start Emacs, if they exist. These are site-start.el, which is loaded before your .emacs
file, and default.el, and the terminal type file, which are both loaded after your .emacs
file.
Settings and definitions in your .emacs file will overwrite conflicting settings and
definitions in a site-start.el file, if it exists; but the settings and definitions in a
default.el or terminal type file will overwrite those in your .emacs file. (You can
prevent interference from a terminal type file by setting term-file-prefix to nil. See
Section 16.11 “A Simple Extension”, page 207.)
The INSTALL file that comes in the distribution contains descriptions of the site-
init.el and site-load.el files.
The loadup.el, startup.el, and loaddefs.el files control loading. These files are in the
lisp directory of the Emacs distribution and are worth perusing.
The loaddefs.el file contains a good many suggestions as to what to put into your
own .emacs file, or into a site-wide initialization file.
17 This section suggests settings that are more suitable for writers. For programmers, the
default mode will be set to the corresponding prog-mode automatically based on the type of
the file. And it’s perfectly fine if you want to keep the fundamental mode as the default mode.
205
Section 16.4: Text and Auto Fill Mode
18 We use setq-default here because text-mode is buffer-local. If we use setq, it will only
apply to the current buffer, whereas using setq-default will also apply to newly created buffers.
This is not recommended for programmers.
206 Chapter 16: Your .emacs File
16.5 Mail Aliases
Here is a setq that turns on mail aliases, along with more reminders.
;;; Message mode
; To enter message mode, type 'C-x m'
; To enter RMAIL (for reading mail),
; type 'M-x rmail'
(setq mail-aliases t)
This setq sets the value of the variable mail-aliases to t. Since t means true, the line
says, in effect, “Yes, use mail aliases.”
Mail aliases are convenient short names for long email addresses or for lists of
email addresses. The file where you keep your aliases is ~/.mailrc. You write an alias
like this:
alias geo george@foobar.wiz.edu
When you write a message to George, address it to ‘geo’; the mailer will automatically
expand ‘geo’ to the full address.
toloaded; the second is the name of the file to be loaded. The third argument is
documentation for the function, and the fourth tells whether the function can be
called interactively. The fifth argument tells what type of object—autoload can
handle a keymap or macro as well as a function (the default is a function).
Here is a typical example:
(autoload 'html-helper-mode
"html-helper-mode" "Edit HTML documents" t)
(html-helper-mode is an older alternative to html-mode, which is a standard part of the
distribution.)
This expression autoloads the html-helper-mode function. It takes it from the html-
helper-mode.el file (or from the byte compiled version html-helpermode.elc, if that
exists.) The file must be located in a directory specified by load-path. The
documentation says that this is a mode to help you edit documents written in the
HyperText Markup Language. You can call this mode interactively by typing M-xhtml-
helper-mode. (You need to duplicate the function’s regular documentation in the
autoload expression because the regular function is not yet loaded, so its
documentation is not available.)
See Section “Autoload” in The GNU Emacs Lisp Reference Manual, for more
information.
211
16.11 A Simple Extension: line-to-top-of-window
Here is a simple extension to Emacs that moves the line that point is on to the top of
the window. I use this all the time, to make text easier to read.
You can put the following code into a separate file and then load it from your
.emacs file, or you can include it within your .emacs file.
Here is the definition:
;;; Line to top of window;
;;; replace three keystroke sequence C-u 0 C-l
(defun line-to-top-of-window ()
"Move the line that point is on to top of window."
(interactive)
(recenter 0))
Now for the key binding.
Function keys as well as mouse button events and non-ascii characters are written
within square brackets, without quotation marks.
I bind line-to-top-of-window to my F6 function key like this:
(global-set-key [f6] 'line-to-top-of-window)
For more information, see Section “Rebinding Keys in Your Init File” in The GNU
Emacs Manual.
If you run two versions of GNU Emacs, such as versions 27 and 28, and use one
.emacs file, you can select which code to evaluate with the following conditional:
(cond
((= 27 emacs-major-version)
;; evaluate version 27 code
( ... ))
((= 28 emacs-major-version)
;; evaluate version 28 code
( ... )))
For example, recent versions blink their cursors by default. I hate such blinking, as
well as other features, so I placed the following in my .emacs file19:
(when (>= emacs-major-version 21)
(blink-cursor-mode 0)
;; Insert newline when you press 'C-n' (next-line)
;; at the end of the buffer
(setq next-line-add-newlines t)
;; Turn on image viewing (auto-image-file-mode t)
;; Turn on menu bar (this bar has text)
;; (Use numeric argument to turn on)
19 When I start instances of Emacs that do not load my .emacs file or any site file, I also
turn off blinking: emacs -q --no-site-file -eval '(blink-cursor-mode nil)'
Or nowadays, using an even more sophisticated set of options, emacs -Q
-D
212 Chapter 16: Your .emacs File
(menu-bar-mode 1)
;; Turn off tool bar (this bar has icons)
;; (Use numeric argument to turn on)
(tool-bar-mode nil)
;; Turn off tooltip mode for tool bar
;; (This mode causes icon explanations to pop up)
;; (Use numeric argument to turn on)
(tooltip-mode nil)
;; If tooltips turned on, make tips appear promptly
(setq tooltip-delay 0.1) ; default is 0.7 second )
Section 16.12: X11 Colors
20 I also run more modern window managers, such as Enlightenment, Gnome, or KDE; in
those cases, I often specify an image rather than a plain color.
214 Chapter 16: Your .emacs File
;; Translate 'C-h' to <DEL>. ; (keyboard-
translate ?\C-h ?\C-?)
the mode, and so on. However, the format looks complicated because of two features
we have not discussed.
The first string in the mode line is a dash or hyphen, ‘-’. In the old days, it would
have been specified simply as "-". But nowadays, Emacs can add properties to a
string, such as highlighting or, as in this case, a help feature. If you place your mouse
cursor over the hyphen, some help information appears (By default, you must wait
seven-tenths of a second before the information appears. You can change that timing
by changing the value of tooltip-delay.) The new string format has a special syntax:
#("-" 0 1 (help-echo "mouse-1: select window, ..."))
The #( begins a list. The first element of the list is the string itself, just one ‘-’. The
second and third elements specify the range over which the fourth element applies.
A range starts after a character, so a zero means the range starts just before the first
character; a 1 means that the range ends just after the first character. The third
element is the property for the range. It consists of a property list, a property name,
in this case, ‘help-echo’, followed by a value, in this case, a string. The second, third,
and fourth elements of this new string format can be repeated.
See Section “Text Properties” in The GNU Emacs Lisp Reference Manual, and see
Section “Mode Line Format” in The GNU Emacs Lisp Reference Manual, for more
information.
mode-line-buffer-identification displays the current buffer name. It is a
list beginning (#("%12b"04.... The #( begins the list.
The ‘"%12b"’ displays the current buffer name, using the buffer-name function
with which we are familiar; the ‘12’ specifies the maximum number of characters
that will be displayed. When a name has fewer characters, whitespace is added to fill
out to this number. (Buffer names can and often should be longer than 12 characters;
this length works well in a typical 80 column wide window.)
:eval says to evaluate the following form and use the result as a string to display.
In this case, the expression displays the first component of the full system name. The
end of the first component is a ‘.’ (period), so I use the string-match function to tell
me the length of the first component. The substring from the zeroth character to that
length is the name of the machine.
This is the expression:
(:eval (substring
217
(system-name) 0 (string-match "\\..+" (system-name))))
‘%[’ and ‘%]’ cause a pair of square brackets to appear for each recursive editing
level. ‘%n’ says “Narrow” when narrowing is in effect. ‘%P’ tells you the percentage of
the buffer that is above the bottom of the window, or “Top”, “Bottom”, or “All”. (A
lower case ‘p’ tell you the percentage above the top of the window.) ‘%-’ inserts
enough dashes to fill out the line.
Remember, you don’t have to like Emacs to like it—your own Emacs can have
different colors, different commands, and different keys than a default Emacs.
On the other hand, if you want to bring up a plain out-of-the-box Emacs, with no
customization, type:
emacs -q
214 Chapter 16: Your .emacs File
This will start an Emacs that does not load your ~/.emacs initialization file. A plain,
default Emacs. Nothing more.
219
Section 17.1: debug
17 Debugging
GNU Emacs has two debuggers, debug and edebug. The first is built into the internals
of Emacs and is always with you; the second requires that you instrument a function
before you can use it.
Both debuggers are described extensively in Section “Debugging Lisp Programs”
in The GNU Emacs Lisp Reference Manual. In this chapter, I will walk through a short
example of each.
17.1 debug
Suppose you have written a function definition that is intended to return the sum of
the numbers 1 through a given number. (This is the triangle function discussed
earlier. See “Example with Decrementing Counter”, page 123, for a discussion.)
However, your function definition has a bug. You have mistyped ‘1=’ for ‘1-’.
Here is the broken definition:
(defun triangle-bugged (number)
"Return sum of numbers 1 through NUMBER inclusive."
(let ((total 0))
(while (> number 0)
(setq total (+ total number))
(setq number (1= number))) ; Error here. total))
If you are reading this in Info, you can evaluate this definition in the normal
fashion. You will see triangle-bugged appear in the echo area.
Now evaluate the triangle-bugged function with an argument of 4:
(triangle-bugged 4)
This will create and enter a *Backtrace* buffer that says:
---------- Buffer: *Backtrace* ---------Debugger entered--Lisp
error: (void-function 1=)
(1= number)
(setq number (1= number))
(while (> number 0) (setq total (+ total number))
(setq number (1= number)))
(let ((total 0)) (while (> number 0) (setq total ...)
(setq number ...)) total) triangle-bugged(4) eval((triangle-
bugged 4) nil) eval-expression((triangle-bugged 4) nil nil 127)
funcall-interactively(eval-expression (triangle-bugged 4) nil nil 127) call-interactively(eval-
expression nil nil) command-execute(eval-expression)
---------- Buffer: *Backtrace* ----------
(I have reformatted this example slightly; the debugger does not fold long lines. As
usual, you can quit the debugger by typing q in the *Backtrace* buffer.)
220 Chapter 17: Debugging
In practice, for a bug as simple as this, the Lisp error line will tell you what you
need to know to correct the definition. The function 1= is void.
However, suppose you are not quite certain what is going on? You can read the
complete backtrace.
Emacs automatically starts the debugger that puts you in the *Backtrace* buffer.
You can also start the debugger manually as described below.
Read the *Backtrace* buffer from the bottom up; it tells you what Emacs did that
led to the error. Emacs made an interactive call to C-xC-e (eval-last-sexp), which led to
the evaluation of the triangle-bugged expression. Each line above tells you what the
Lisp interpreter evaluated next.
The third line from the top of the buffer is
(setq number (1= number))
Emacs tried to evaluate this expression; in order to do so, it tried to evaluate the
inner expression shown on the second line from the top:
(1= number)
This is where the error occurred; as the top line says:
Debugger entered--Lisp error: (void-function 1=)
You can correct the mistake, re-evaluate the function definition, and then run your
test again.
17.2 debug-on-entry
Emacs starts the debugger automatically when your function has an error.
Incidentally, you can start the debugger manually for all versions of Emacs; the
advantage is that the debugger runs even if you do not have a bug in your code.
Sometimes your code will be free of bugs!
You can enter the debugger when you call the function by calling debug-onentry.
Type:
M-x debug-on-entry RET triangle-bugged RET
Section 17.2: debug-on-entry
strings, and if that function doesn't return nil, then that string (or list) is added to the
front of the kill ring and the string (or first string in the list) is returned as the latest kill.
If N is not zero, and if `yank-pop-change-selection' is non-nil, use
`interprogram-cut-function' to transfer the kill at the new yank point into the
window system selection. If optional arg DO-NOT-MOVE is non-nil, then don't
actually move the yanking point; just return the Nth kill forward."
The let expression declares a variable that will be only usable within the bounds
of this function. This variable is called interprogram-paste and is for copying to
another program. It is not for copying within this instance of GNU Emacs. Most
window systems provide a facility for interprogram pasting. Sadly, that facility
usually provides only for the last element. Most windowing systems have not
adopted a ring of many possibilities, even though Emacs has provided it for decades.
The if expression has two parts, one if there exists interprogram-paste and one if not.
Let us consider the else-part of the current-kill function. (The then-part uses the
kill-new function, which we have already described. See “The kill-new function”, page
97.)
(or kill-ring (error "Kill ring is empty")) (let ((ARGth-kill-
element
(nthcdr (mod (- n (length kill-ring-yank-pointer))
(length kill-ring)) kill-
ring))) (or do-not-move
(setq kill-ring-yank-pointer ARGth-kill-element))
(car ARGth-kill-element))
The code first checks whether the kill ring has content; otherwise it signals an error.
Note that the or expression is very similar to testing length with an if:
(if (zerop (length kill-ring)) ; if-part
(error "Kill ring is empty")) ; then-part
;; No else-part
If there is not anything in the kill ring, its length must be zero and an error message
sent to the user: ‘Killringisempty’. The current-kill function uses an or expression which
is simpler. But an if expression reminds us what goes on.
This if expression uses the function zerop which returns true if the value it is
testing is zero. When zerop tests true, the then-part of the if is evaluated. The then-
part is a list starting with the function error, which is a function that is similar to the
message function (see Section 1.8.5 “The message Function”, page 14) in that it prints
a one-line message in the echo area. However, in addition to printing a message,
error also stops evaluation of the function within which it is embedded. This means
that the rest of the function will not be evaluated if the length of the kill ring is zero.
Then the current-kill function selects the element to return. The selection depends
on the number of places that current-kill rotates and on where kill-ringyank-pointer
points.
Next, either the optional do-not-move argument is true or the current value of kill-
ring-yank-pointer is set to point to the list. Finally, another expression returns the first
element of the list even if the do-not-move argument is true.
In my opinion, it is slightly misleading, at least to humans, to use the term “error”
as the name of the error function. A better term would be “cancel”. Strictly speaking,
of course, you cannot point to, much less rotate a pointer to a list that has no length,
so from the point of view of the computer, the word “error” is correct. But a human
Section B.1: The current-kill Function 231
expects to attempt this sort of thing, if only to find out whether the kill ring is full or
empty. This is an act of exploration.
From the human point of view, the act of exploration and discovery is not
necessarily an error, and therefore should not be labeled as one, even in the bowels
of a computer. As it is, the code in Emacs implies that a human who is acting
virtuously, by exploring his or her environment, is making an error. This is bad. Even
though the computer takes the same steps as it does when there is an error, a term
such as “cancel” would have a clearer connotation.
Among other actions, the else-part of the if expression sets the value of kill-ring-
yank-pointer to ARGth-kill-element when the kill ring has something in it and the
value of do-not-move is nil.
The code looks like this:
(nthcdr (mod (- n (length kill-ring-yank-pointer))
(length kill-ring)) kill-ring)))
This needs some examination. Unless it is not supposed to move the pointer, the
current-kill function changes where kill-ring-yank-pointer points. That is what the
(setqkill-ring-yank-pointerARGth-kill-element)) expression does. Also, clearly, ARGth-
kill-element is being set to be equal to some cdr of the kill ring, using the nthcdr
function that is described in an earlier section. (See Section 8.3 “copy-region-as-kill”,
page 93.) How does it do this?
As we have seen before (see Section 7.3 “nthcdr”, page 80), the nthcdr function
works by repeatedly taking the cdr of a list—it takes the cdr of the cdr of the cdr . . .
The two following expressions produce the same result:
(setq kill-ring-yank-pointer (cdr kill-ring))
⇒1
We can guess what the - function does. It is like + but subtracts instead of adds;
the - function subtracts its second argument from its first. Also, we already know
what the length function does (see Section 7.2.1 “length”, page 79). It returns the
length of a list.
And n is the name of the required argument to the current-kill function.
So when the first argument to nthcdr is zero, the nthcdr expression returns the whole
list, as you can see by evaluating the following:
;; kill-ring-yank-pointer and kill-ring have a length of four
;; and (mod (- 0 4) 4) ⇒ 0
(nthcdr (mod (- 0 4) 4)
'("fourth line of text"
"third line"
"second piece of text"
"first some text"))
When the first argument to the current-kill function is one, the nthcdr expression
returns the list without its first element.
(nthcdr (mod (- 1 4) 4)
'("fourth line of text"
"third line"
"second piece of text"
"first some text"))
Incidentally, both kill-ring and kill-ring-yank-pointer are global variables. That
means that any expression in Emacs Lisp can access them. They are not like the local
variables set by let or like the symbols in an argument list. Local variables can only
be accessed within the let that defines them or the function that specifies them in an
argument list (and within expressions called by them).
(See Section 3.5 “let Prevents Confusion”, page 32, and Section 3.1 “The defun Macro”,
page 26.)
B.2 yank
After learning about current-kill, the code for the yank function is almost easy.
The yank function does not use the kill-ring-yank-pointer variable directly. It calls
insert-for-yank which calls current-kill which sets the kill-ringyank-pointer variable.
The code looks like this:
(defun yank (&optional arg)
"Reinsert (\"paste\") the last stretch of killed text. More precisely, reinsert the stretch of
killed text most recently killed OR yanked. Put point at end, and set mark at beginning. With
just \\[universal-argument] as argument, same but put point at beginning (and mark at end).
With argument N, reinsert the Nth most recently killed stretch of killed text.
Section B.1: The current-kill Function 233
When this command inserts killed text into the buffer, it honors `yank-excluded-
properties' and `yank-handler' as described in the doc string for `insert-for-yank-1',
which see.
After it yanks the appropriate element, if the optional argument is a cons rather
than a number or nothing, it puts point at beginning of the yanked text and mark at
its end.
(The prog1 function is like progn but returns the value of its first argument rather
than the value of its last argument. Its first argument is forced to return the buffer’s
mark as an integer. You can see the documentation for these functions by placing
point over them in this buffer and then typing C-hf (describe-function) followed by a
RET; the default is the function.)
The last part of the function tells what to do when it succeeds.
B.3 yank-pop
After understanding yank and current-kill, you know how to approach the yank-pop
function. Leaving out the documentation to save space, it looks like this:
(defun yank-pop (&optional arg)
"..."
(interactive "*p")
(if (not (eq last-command 'yank))
(error "Previous command was not a yank"))
(setq this-command 'yank) (unless arg
(setq arg 1))
(let ((inhibit-read-only t)
(before (< (point) (mark t)))) (if before
(funcall (or yank-undo-function 'delete-region) (point) (mark t))
(funcall (or yank-undo-function 'delete-region) (mark t) (point)))
(setq yank-undo-function nil)
(set-marker (mark-marker) (point) (current-buffer))
(insert-for-yank (current-kill arg))
;; Set the window start back where it was in the yank command, ;; if possible.
(set-window-start (selected-window) yank-window-start t) (if before
;; This is like exchange-point-and-mark, ;; but doesn't
activate the mark.
;; It is cleaner to avoid activation, even though the command ;; loop would
deactivate the mark because we inserted text. (goto-char (prog1 (mark t)
(set-marker (mark-marker)
(point)
(current-buffer))))))
nil)
The function is interactive with a small ‘p’ so the prefix argument is processed
and passed to the function. The command can only be used after a previous yank;
otherwise an error message is sent. This check uses the variable last-command which
235
is set by yank and is discussed elsewhere. (See Section 8.3 “copy-region-as-kill”, page
93.)
The let clause sets the variable before to true or false depending whether point is
before or after mark and then the region between point and mark is deleted. This is
the region that was just inserted by the previous yank and it is this text that will be
replaced.
funcall calls its first argument as a function, passing remaining arguments to it.
The first argument is whatever the or expression returns. The two remaining
arguments are the positions of point and mark set by the preceding yank command.
There is more, but that is the hardest part.
These considerations suggest the following outline for the print-graph function:
(defun print-graph (numbers-list)
"documentation..." (let
((height ...
...))
(print-Y-axis height ... )
(graph-body-print numbers-list)
(print-X-axis ... )))
We can work on each part of the print-graph function definition in turn.
5-
238 Appendix C: A Graph with Labeled Axes
1-
The function should be passed the height of the graph, and then should construct
and insert the appropriate numbers and marks.
It is easy enough to see in the figure what the Y axis label should look like; but to
say in words, and then to write a function definition to do the job is another matter.
It is not quite true to say that we want a number and a tic every five lines: there are
only three lines between the ‘1’ and the ‘5’ (lines 2, 3, and 4), but four lines between
the ‘5’ and the ‘10’ (lines 6, 7, 8, and 9). It is better to say that we want a number and
a tic mark on the base line (number 1) and then that we want a number and a tic on
the fifth line from the bottom and on every line that is a multiple of five.
The next issue is what height the label should be? Suppose the maximum height
of tallest column of the graph is seven. Should the highest label on the Y axis be ‘5 -’,
and should the graph stick up above the label? Or should the highest label be ‘ 7-’, and
mark the peak of the graph? Or should the highest label be 10-, which is a multiple of
five, and be higher than the topmost value of the graph?
The latter form is preferred. Most graphs are drawn within rectangles whose
sides are an integral number of steps long—5, 10, 15, and so on for a step distance of
five. But as soon as we decide to use a step height for the vertical axis, we discover
that the simple expression in the varlist for computing the height is wrong. The
expression is (apply'maxnumbers-list). This returns the precise height, not the
maximum height plus whatever is necessary to round up to the nearest multiple of
five. A more complex expression is required.
As usual in cases like this, a complex problem becomes simpler if it is divided
into several smaller problems.
First, consider the case when the highest value of the graph is an integral
multiple of five—when it is 5, 10, 15, or some higher multiple of five. We can use this
value as the Y axis height.
A fairly simply way to determine whether a number is a multiple of five is to
divide it by five and see if the division results in a remainder. If there is no remainder,
the number is a multiple of five. Thus, seven divided by five has a remainder of two,
and seven is not an integral multiple of five. Put in slightly different language, more
reminiscent of the classroom, five goes into seven once, with a remainder of two.
However, five goes into ten twice, with no remainder: ten is an integral multiple of
five.
(% 7 5)
(% 10 5)
The first expression returns 2 and the second expression returns 0.
To test whether the returned value is zero or some other number, we can use the
zerop function. This function returns t if its argument, which must be a number, is
zero.
(zerop (% 7 5)) ⇒ nil
(zerop (% 10 5))
⇒t
Thus, the following expression will return t if the height of the graph is evenly
divisible by five:
(zerop (% height 5))
(The value of height, of course, can be found from (apply'maxnumbers-list).)
On the other hand, if the value of height is not a multiple of five, we want to reset
the value to the next higher multiple of five. This is straightforward arithmetic using
functions with which we are already familiar. First, we divide the value of height by
five to determine how many times five goes into the number. Thus, five goes into
twelve twice. If we add one to this quotient and multiply by five, we will obtain the
value of the next multiple of five that is larger than the height. Five goes into twelve
twice. Add one to two, and multiply by five; the result is fifteen, which is the next
multiple of five that is higher than twelve. The Lisp expression for this is:
(* (1+ (/ height 5)) 5)
For example, if you evaluate the following, the result is 15:
(* (1+ (/ 12 5)) 5)
All through this discussion, we have been using 5 as the value for spacing labels
on the Y axis; but we may want to use some other value. For generality, we should
replace 5 with a variable to which we can assign a value. The best name I can think
of for this variable is Y-axis-label-spacing.
Using this term, and an if expression, we produce the following:
(if (zerop (% height Y-axis-label-spacing)) height
;; else
(* (1+ (/ height Y-axis-label-spacing)) Y-axis-label-spacing))
This expression returns the value of height itself if the height is an even multiple of
the value of the Y-axis-label-spacing or else it computes and returns a value of height
that is equal to the next higher multiple of the value of the Y-axis-labelspacing.
We can now include this expression in the let expression of the print-graph
function (after first setting the value of Y-axis-label-spacing):
(defvar Y-axis-label-spacing 5
"Number of lines from one Y axis label to next.")
240 Appendix C: A Graph with Labeled Axes
...
(let* ((height (apply 'max numbers-list))
(height-of-top-line
(if (zerop (% height Y-axis-label-spacing)) height
;; else
(* (1+ (/ height Y-axis-label-spacing)) Y-axis-label-
spacing))) (symbol-width (length graph-blank)))) ...
(Note use of the let* function: the initial value of height is computed once by the
(apply'maxnumbers-list) expression and then the resulting value of height is used to
compute its final value. See “The let* expression”, page 148, for more about let*.)
This value will be calculated by the print-graph function in its varlist as full-Y-label-
width and passed on. (Note that we did not think to include this in the varlist when
we first proposed it.)
To make a complete vertical axis label, a tic mark is concatenated with a number;
and the two together may be preceded by one or more spaces depending on how
long the number is. The label consists of three parts: the (optional) leading spaces,
Section C.2: The print-Y-axis Function 241
the number, and the tic mark. The function is passed the value of the number for the
specific row, and the value of the width of the top line, which is calculated (just once)
by print-graph.
(defun Y-axis-element (number full-Y-label-width) "Construct a NUMBERed
label element.
A numbered element looks like this ` 5 - ', and is padded
as needed so all line up with the element for the largest
number." (let* ((leading-spaces
(- full-Y-label-width
(length
(concat (number-to-string number) Y-axis-tic)))))
(concat
(make-string leading-spaces ? )
(number-to-string number) Y-axis-tic)))
The Y-axis-element function concatenates together the leading spaces, if any; the
number, as a string; and the tic mark.
To figure out how many leading spaces the label will need, the function subtracts
the actual length of the label—the length of the number plus the length of the tic
mark—from the desired label width.
Blank spaces are inserted using the make-string function. This function takes two
arguments: the first tells it how long the string will be and the second is a symbol for
the character to insert, in a special format. The format is a question mark followed
by a blank space, like this, ‘? ’. See Section “Character Type” in The GNU Emacs Lisp
Reference Manual, for a description of the syntax for characters.
(Of course, you might want to replace the blank space by some other character . . .
You know what to do.)
The number-to-string function is used in the concatenation expression, to convert
the number to a string that is concatenated with the leading spaces and the tic mark.
C.2.3 Create a Y Axis Column
The preceding functions provide all the tools needed to construct a function that
generates a list of numbered and blank strings to insert as the label for the vertical
axis:
(defun Y-axis-column (height width-of-label) "Construct list of Y axis
labels and blank strings.
For HEIGHT of line above base and WIDTH-OF-LABEL."
(let (Y-axis)
3. Switch to the *scratch* buffer and place the cursor where you want the axis
labels to start.
Section C.2: The print-Y-axis Function 243
;; tic-width ...
(* symbol-width X-axis-label-spacing)
;; number-of-X-ticks
(if (zerop (% (X-length tic-width)))
(/ (X-length tic-width))
(1+ (/ (X-length tic-width))))
Section C.3: The print-X-axis
All this leads us directly to the function for printing the X axis tic line:
(defun print-X-axis-tic-line
(number-of-X-tics X-axis-leading-spaces X-axis-tic-element)
"Print ticks for X axis."
(insert X-axis-leading-spaces)
(insert X-axis-tic-symbol) ; Under first column.
;; Insert second tic in the right spot.
246 Appendix C: A Graph with Labeled Axes
(insert (concat
(make-string
(- (* symbol-width X-axis-label-spacing) ;; Insert white
space up to second tic symbol.
(* 2 (length X-axis-tic-symbol)))
?)
X-axis-tic-symbol)) ;; Insert
remaining ticks.
(while (> number-of-X-tics 1)
(insert X-axis-tic-element)
(setq number-of-X-tics (1- number-of-X-tics)))) The line of
numbers is equally straightforward:
Function 247
First, we create a numbered element with blank spaces before each number:
(defun X-axis-element (number)
"Construct a numbered X axis element." (let ((leading-
spaces
(- (* symbol-width X-axis-label-spacing)
(length (number-to-string number))))) (concat (make-
string leading-spaces ? )
(number-to-string number))))
Next, we create the function to print the numbered line, starting with the number
1 under the first column:
(defun print-X-axis-numbered-line
(number-of-X-tics X-axis-leading-spaces)
"Print line of X-axis numbers"
(let ((number X-axis-label-spacing))
(insert X-axis-leading-spaces)
(insert "1")
(insert (concat
(make-string
;; Insert white space up to next number.
(- (* symbol-width X-axis-label-spacing) 2)
?)
(number-to-string number))) ;; Insert
remaining numbers.
(setq number (+ number X-axis-label-spacing))
(while (> number-of-X-tics 1)
(insert (X-axis-element number))
(setq number (+ number X-axis-label-spacing))
(setq number-of-X-tics (1- number-of-X-tics)))))
Finally, we need to write the print-X-axis that uses print-X-axis-tic-line and print-X-
axis-numbered-line.
The function must determine the local values of the variables used by both print-
X-axis-tic-line and print-X-axis-numbered-line, and then it must call them. Also, it must
print the carriage return that separates the two lines.
The function consists of a varlist that specifies five local variables, and calls to
each of the two line printing functions:
(defun print-X-axis (numbers-list)
"Print X axis labels to length of NUMBERS-LIST."
(let* ((leading-spaces
(make-string full-Y-label-width ? ))
;; symbol-width is provided by graph-body-print
(tic-width (* symbol-width X-axis-label-spacing))
(X-length (length numbers-list))
(X-tic
(concat
248 Appendix C: A Graph with Labeled Axes
(make-string
;; Make a string of blanks.
(- (* symbol-width X-axis-label-spacing)
(length X-axis-tic-symbol))
?)
Section C.4: Printing the Whole Graph 249
| | | | |
1 5 10 15 20
The final version is different from what we planned in two ways: first, it contains
additional values calculated once in the varlist; second, it carries an option to specify
the labels’ increment per row. This latter feature turns out to be essential; otherwise,
a graph may have more rows than fit on a display or on a sheet of paper.
This new feature requires a change to the Y-axis-column function, to add vertical-
step to it. The function looks like this:
;;; Final version.
(defun Y-axis-column
(height width-of-label &optional vertical-step) "Construct list of labels for
Y axis.
HEIGHT is maximum height of graph.
WIDTH-OF-LABEL is maximum width of label. VERTICAL-STEP, an
option, is a positive integer that specifies how much a Y axis
label increments for each line. For example, a step of 5 means
that each line is five units of the graph."
(let (Y-axis
(number-per-line (or vertical-step 1)))
(while (> height 1)
(if (zerop (% height Y-axis-label-spacing)) ;; Insert label.
(setq Y-axis
(cons
(Y-axis-element
(* height number-per-line)
width-of-label) Y-axis)) ;; Else, insert blanks.
(setq Y-axis
(cons
(make-string width-of-label ? ) Y-axis)))
(setq height (1- height))) ;; Insert
base line.
(setq Y-axis (cons (Y-axis-element (or vertical-step
1) width-of-label)
Y-axis))
(nreverse Y-axis)))
The values for the maximum height of graph and the width of a symbol are
computed by print-graph in its let expression; so graph-body-print must be changed to
accept them.
;;; Final version.
(defun graph-body-print (numbers-list height symbol-width) "Print a bar graph of
the NUMBERS-LIST.
The numbers-list consists of the Y-axis values.
HEIGHT is maximum height of graph.
SYMBOL-WIDTH is number of each column."
(let (from-position)
Section C.4: Printing the Whole Graph 251
(while numbers-list
(setq from-position (point))
(insert-rectangle
(column-of-graph height (car numbers-list)))
(goto-char from-position)
(forward-char symbol-width)
;; Draw graph column by column.
(sit-for 0)
(setq numbers-list (cdr numbers-list))) ;; Place point
for X axis labels.
(forward-line height)
(insert "\n")))
Finally, the code for the print-graph function:
;;; Final version.
(defun print-graph
(numbers-list &optional vertical-step)
"Print labeled bar graph of the NUMBERS-LIST. The numbers-
list consists of the Y-axis values.
3. Switch to the *scratch* buffer and place the cursor where you want the axis
labels to start.
4. Type M-: (eval-expression).
5. Yank the test expression into the minibuffer with C-y (yank).
6. Press RET to evaluate the expression.
Emacs will print a graph that looks like this:
10 -
*
** *
5- **** *
**** ***
* *********
************
2 - *************
| | | |
1 5 10 15
On the other hand, if you pass print-graph a vertical-step value of 2, by evaluating
this expression:
(print-graph '(3 2 5 6 7 5 3 4 6 4 3 2 1) 2)
The graph looks like this:
20 -
*
** *
10 - **** *
**** ***
* *********
************
3 - *************
| | | |
1 5 10 15
(A question: is the ‘2’ on the bottom of the vertical axis a bug or a feature? If you
think it is a bug, and should be a ‘1’ instead, (or even a ‘0’), you can modify the
sources.)
Section C.4: Printing the Whole Graph 253
(multiply-by-seven 3)
function argument
This expression returns 2. The 100 is passed to the function, which divides that
number by 50.
See Section “Lambda Expressions” in The GNU Emacs Lisp Reference Manual, for
more about lambda. Lisp and lambda expressions derive from the Lambda
Calculus.
1000 - *
**
**
**
**
750 - ***
***
***
***
****
500 - *****
******
******
******
*******
250 - ********
********* *
*********** *
************* *
50 - ***************** * *
| | | | | | | |
10 50 100 150 200 250 300 350
The largest group of functions contain 10–19 words and symbols each.
258
Appendix D: Free Software and Free Manuals
The biggest deficiency in free operating systems is not in the software—it is the
lack of good free manuals that we can include in these systems. Many of our most
important programs do not come with full manuals. Documentation is an essential
part of any software package; when an important free software package does not
come with a free manual, that is a major gap. We have many such gaps today.
Once upon a time, many years ago, I thought I would learn Perl. I got a copy of a
free manual, but I found it hard to read. When I asked Perl users about alternatives,
they told me that there were better introductory manuals—but those were not free.
Why was this? The authors of the good manuals had written them for O’Reilly
Associates, which published them with restrictive terms—no copying, no
modification, source files not available—which exclude them from the free software
community.
That wasn’t the first time this sort of thing has happened, and (to our
community’s great loss) it was far from the last. Proprietary manual publishers have
enticed a great many authors to restrict their manuals since then. Many times I have
heard a GNU user eagerly tell me about a manual that he is writing, with which he
expects to help the GNU project—and then had my hopes dashed, as he proceeded to
explain that he had signed a contract with a publisher that would restrict it so that
we cannot use it.
Given that writing good English is a rare skill among programmers, we can ill
afford to lose manuals this way.
Free documentation, like free software, is a matter of freedom, not price. The
problem with these manuals was not that O’Reilly Associates charged a price for
printed copies—that in itself is fine. The Free Software Foundation sells printed
copies (https://shop.fsf.org) of free GNU manuals (https://www.gnu.org/
doc/doc.html), too. But GNU manuals are available in source code form, while these
manuals are available only on paper. GNU manuals come with permission to copy
and modify; the Perl manuals do not. These restrictions are the problems.
The criterion for a free manual is pretty much the same as for free software: it is
a matter of giving all users certain freedoms. Redistribution (including commercial
redistribution) must be permitted, so that the manual can accompany every copy of
the program, on-line or on paper. Permission for modification is crucial too.
As a general rule, I don’t believe that it is essential for people to have permission
to modify all sorts of articles and books. The issues for writings are not necessarily
the same as those for software. For example, I don’t think you or I are obliged to give
permission to modify articles like this one, which describe our actions and our
views.
259
But there is a particular reason why the freedom to modify is crucial for
documentation for free software. When people exercise their right to modify the
software, and add or change its features, if they are conscientious they will change
the manual too—so they can provide accurate and usable documentation with the
modified program. A manual which forbids programmers to be conscientious and
finish the job, or more precisely requires them to write a new manual from scratch if
they change the program, does not fill our community’s needs.
While a blanket prohibition on modification is unacceptable, some kinds of limits
on the method of modification pose no problem. For example, requirements to
preserve the original author’s copyright notice, the distribution terms, or the list of
authors, are ok. It is also no problem to require modified versions to include notice
that they were modified, even to have entire sections that may not be deleted or
changed, as long as these sections deal with nontechnical topics. (Some GNU
manuals have them.)
These kinds of restrictions are not a problem because, as a practical matter, they
don’t stop the conscientious programmer from adapting the manual to fit the
modified program. In other words, they don’t block the free software community
from making full use of the manual.
However, it must be possible to modify all the technical content of the manual,
and then distribute the result in all the usual media, through all the usual channels;
otherwise, the restrictions do block the community, the manual is not free, and so we
need another manual.
Unfortunately, it is often hard to find someone to write another manual when a
proprietary manual exists. The obstacle is that many users think that a proprietary
manual is good enough—so they don’t see the need to write a free manual. They do
not see that the free operating system has a gap that needs filling.
Why do users think that proprietary manuals are good enough? Some have not
considered the issue. I hope this article will do something to change that.
Other users consider proprietary manuals acceptable for the same reason so
many people consider proprietary software acceptable: they judge in purely
practical terms, not using freedom as a criterion. These people are entitled to their
opinions, but since those opinions spring from values which do not include freedom,
they are no guide for those of us who do value freedom.
Please spread the word about this issue. We continue to lose manuals to
proprietary publishing. If we spread the word that proprietary manuals are not
sufficient, perhaps the next person who wants to help GNU by writing
documentation will realize, before it is too late, that he must above all make it free.
We can also encourage commercial publishers to sell free, copylefted manuals
instead of proprietary ones. One way you can help this is to check the distribution
terms of a manual before you buy it, and prefer copylefted manuals to non-
copylefted ones.
Note: The Free Software Foundation maintains a page on its Web site that lists free
books available from other publishers:
260 Appendix E: GNU Free Documentation License
https://www.gnu.org/doc/other-free-books.html
Appendix E GNU Free Documentation License
Version 1.3, 3 November 2008
Copyright 2000, 2001, 2002, 2007, 2008 Free Software Foundation, Inc.
https://fsf.org/
Index A
Accumulate, type of recursive
pattern................... 135 add-hook.............................
% 201 and.............................. 101, 149 Anonymous
% (remainder function) ............... 235 function ................. 249 apostrophe for
quoting.................. 3 append-to-buffer.....................
52 apply ................................ 189
apropos.............................. 187 Argument as local
’ variable ........... 124
' for quoting ........................... 3 ‘argument’ defined..................... 11 ‘argumentlist’
defined ............... 27 Argument, wrong type of
.............. 13 Arguments ............................ 11
Arguments’ data types................. 12
( Arguments, variable number of ........ 13
(debug) in code...................... 218 Asterisk for read-only buffer ........... 61 Auto
Fill mode turned on ............ 201
autoload............................. 206 Automatic mode
selection ............ 200 Axis, print
*
horizontal................. 241
* (multiplication)...................... 27 * for read-
Axis, print vertical ................... 234
only buffer.................. 61 *scratch* buffer
..................... 117
B
beginning-of-buffer ................. 65 ‘bind’ defined
. ......................... 16 Binding, dynamic......................
.emacs file ........................... 196 36 Binding, lexical........................ 36 Bindings,
.emacs file, beginning of.............. 199 key, fixing unpleasant....... 211
‘body’ defined ......................... 26 Body of
graph........................ 187
Buffer size............................. 24 Buffer, history of
/ word................. 21 buffer-file-name..................... 20
/ (division)............................ 69 buffer-menu, bound to key........... 204 buffer-
name .......................... 20 Bug, most insidious
type ............. 251 Building robots.......................
< 127
Byte compiling ......................... 7
<= (less than or equal)................ 120
>
> (greater than) ....................... 38
270 Index
Widening.............................. 73 Widening,
example of.................. 74 Word counting in a
defun ............ 167
Words and symbols in defun.......... 167
Words, counted recursively ........... 161
Words, duplicated.................... 223
Writing a function definition........... 26
Wrong type of argument............... 13
X
X axis printing ....................... 241
X-axis-element...................... 244
Y
Y axis printing ....................... 234
Y-axis-column....................... 239 Y-axis-column
Final version.......... 246
Y-axis-label-spacing............... 237 Y-axis-tic
.......................... 238 yank............................. 113, 230
yank-pop............................. 231
Z
zap-to-char .......................... 85 zerop
................................ 227
About the Author