O'Reilly logo

Writing GNU Emacs Extensions by Bob Glickstein

Stay ahead with the world's most comprehensive technology and business learning platform.

With Safari, you learn the way you learn best. Get unlimited access to videos, live online training, learning paths, books, tutorials, and more.

Start Free Trial

No credit card required

Chapter 1. Customizing Emacs

This chapter introduces basic Emacs customizations, and teaches some Emacs Lisp along the way. One of the simplest and most common customizations is to move commands from one key to another. Perhaps you don’t like Emacs’s two-key sequence for saving files (C-x C-s) because you’ve been using some other editor where save is simply C-s. Or perhaps you sometimes accidentally type C-x C-c, which exits Emacs, when you mean to press only C-x, and you’d like accidental presses of C-x C-c to have a less drastic effect. Or perhaps, as in the example that follows, you need to work around an unusual expectation that Emacs has about your keyboard.

Backspace and Delete

Imagine you’re typing the word “Lisp” and you accidentally type “List.” To correct your typo, do you press the BACKSPACE key or the DELETE key?

The answer depends on your keyboard, but it’s not merely a question of how the key is labeled. Sometimes the key is labeled “Backspace,” sometimes it’s labeled “Delete,” sometimes “Erase,” and sometimes it’s not labeled with a word but has a left-pointing arrow or some other graphic. To Emacs, what matters isn’t the label but the numeric character code that the key generates when pressed. Regardless of the label on the key, the “move left and erase the previous character” key may generate an ASCII “backspace” code (decimal 8, usually denoted BS) or an ASCII “delete” code (decimal 127, usually denoted DEL).

In its default configuration, Emacs believes only DEL is the code meaning “move left and erase the previous character.” If you have a BACKSPACE/DELETE/ERASE key that generates a BS, it won’t do what you expect when you press it.

What’s worse is what your BACKSPACE/DELETE/ERASE key will do when you press it, if it’s a BS-generating key. Emacs presumes that since BS isn’t used for moving left and erasing the previous character, it’s available to perform another function. As it happens, BS is also the code sent when you press C-h. If you’re among those who don’t need C-h to mean “move left and erase the previous character,” then C-h is a pretty natural choice for a Help key, and in fact that’s what Emacs uses it for by default. Unfortunately, this means that if you have a BS-generating BACKSPACE/DELETE/ERASE key, then pressing it won’t backspace or delete or erase; it will invoke Emacs’s online help.

More than one tentative first-time Emacs user has been put off by the surprise that greets them the first time they try to erase a typo. Suddenly a new Emacs window—the Help window—pops up, prompting the hapless user to choose some Help subcommand. The Help window is so verbose and unexpected that it merely exacerbates the user’s astonishment. The natural panic reaction—hit C-g (“abort the current operation”) a bunch of times—is accompanied by a cacophonous ringing of the terminal bell. It’s no wonder that intelligent, well-meaning users who might otherwise have helped swell the ranks of fervent Emacs evangelists instead choose to continue struggling with safe, inoffensive vi.

It pains me to think of it, especially when the situation is so easily remedied.

When Emacs starts, it reads and executes the contents of the .emacs file in your home directory. Emacs Lisp is the language of this file, and as we will discover in the course of this book, there’s almost nothing you can’t customize in Emacs by writing some Emacs Lisp and putting it in .emacs. The first thing we’ll look at is adding some code to .emacs to make BS and DEL both do “back up and erase a character,” moving the Help command to some other key. First we’ll need to take a look at Lisp, the language of the .emacs file.

Lisp

Various forms of Lisp have been around since the 1950s. It is traditionally associated with artificial intelligence applications, for which Lisp is well-suited because it permits symbolic computation, can treat code as data, and simplifies building very complicated data structures. But Lisp is much more than just an AI language. It is applicable to a wide range of problems, a fact that is frequently overlooked by computer scientists but which is well known to Emacs users. Among the features that distinguish Lisp from other programming languages are:

Fully-parenthesized prefix notation

All expressions and function calls in Lisp are surrounded by parentheses,[1] and the function name always precedes the arguments to the function. So whereas in other languages you may be able to write:

x + y

to apply the + function to the arguments x and y, in Lisp you write

(+ x y)

“Prefix notation” means that the operator precedes the operands. When the operator is between the operands, it’s called “infix notation.”

Though unfamiliar, prefix notation has some benefits over infix notation. In infix languages, to write the sum of five variables you need four plus signs:

a + b + c + d + e

Lisp is more concise:

(+ a b c d e)

Also, questions of operator precedence do not arise. For example, is the value of

3 + 4 * 5

35 or 23? It depends on whether * has higher precedence than +. But in Lisp, the confusion vanishes:

(+ 3 (* 4 5))      ;result is 23
(* (+ 3 4) 5)      ;result is 35

(Comments in Lisp are introduced with a semicolon and continue to the end of the line.) Finally, while infix languages need commas to separate the arguments to a function:

foo(3 + 4, 5 + 6)

Lisp doesn’t need that extra bit of syntax:

(foo (+ 3 4) (+ 5 6))
List data type

Lisp has a built-in data type called a list. A list is a Lisp object containing zero or more other Lisp objects, surrounded by parentheses. Here are some lists:

(hello there)      ;list containing two "symbols"
(1 2 "xyz")        ;two numbers and a string
(a (b c))          ;a symbol and a sublist (containing two symbols)
()                 ;the empty list

Lists can be assigned to variables, passed as arguments to functions and returned from them, constructed with such functions as cons and append, and taken apart with such functions as car and cdr. We’ll be covering all that in plenty of detail later.

Garbage collection

Lisp is a garbage-collected language, which means that Lisp itself automatically reclaims the memory used by your program’s data structures. By contrast, with languages such as C, one must explicitly allocate memory with malloc when it’s needed, then explicitly release it with free. (The malloc/free approach and others like it in non-garbage-collecting languages are prone to abuse. Prematurely releasing allocated memory is one of the world’s greatest sources of program errors, and forgetting to release allocated memory can cause programs to “bloat” until all available memory is used up.)

For all the convenience that garbage collection affords the programmer, it also has a drawback: periodically, Emacs stops everything it’s doing and displays the message “Garbage collecting…” to the user. The user cannot use Emacs until garbage collection is finished.[2] This usually takes only a second or less, but it may happen very often. Later on we’ll learn some programming practices that help to reduce the amount of garbage collection that takes place.

The word expression usually means any piece of Lisp code or any Lisp data structure. All Lisp expressions, whether code or data, can be evaluated by the Lisp interpreter built into Emacs to make them yield some computational result. The effect of evaluating a variable is to access the Lisp object previously stored in the variable. Evaluating a list is the way to invoke Lisp functions, as we’ll see below.

Since the invention of Lisp, there have been many Lisp dialects, some of which barely resemble the others. MacLisp, Scheme, and Common Lisp are some of the better-known ones. Emacs Lisp is different from all of these. This book focuses only on Emacs Lisp.

Keys and Strings

The goal of this chapter is to make any BS-generating key work the same as any DEL-generating key. Unfortunately, C-h will no longer invoke the Help command. You’ll need to choose some other key to invoke Help; my own choice for the new Help key is META-question-mark.

The META Key

The META key works like the CONTROL key and the SHIFT key, which means that you hold it down while pressing some other key. Such keys are called modifiers. Not all keyboards have a META key, though. Sometimes the ALT key will serve the same purpose, but not all keyboards have an ALT key, either.

In any case, you don’t need to use the META key or the ALT key. The single keystroke META-x can always be replaced with the two-key sequence ESC x. (Note that ESC is not a modifier—you press it and release it like a normal key before pressing x.)

Binding Keystrokes to Commands

In Emacs, every keystroke invokes a command or is part of a multiple-key sequence that invokes a command. Commands are special kinds of Lisp functions, as we will see. Making a keystroke invoke a command such as Help is known as binding the keysequence to the command. We’ll need to execute some Lisp code to bind keys to commands. One Lisp function for doing this is global-set-key.

Here’s what a call to global-set-key looks like. Remember that a function call in Lisp is simply a parenthesized list. The first element of the list is the name of the function, and any remaining elements are the arguments. The function global-set-key takes two arguments: the keysequence to bind, and the command to bind it to.

(global-set-key  keysequence  command)

One important thing to note about Emacs Lisp is that it is case-sensitive.

The keysequence we’ve chosen is META-question-mark. How is this denoted in Emacs Lisp?

Denoting Keys in Strings

There are a few different ways to write a keysequence in Emacs Lisp notation. The simplest is to write the keys as a string. In Lisp, a string is a sequence of characters surrounded with double quotes.

"xyz"      ;three-character string

To get a double quote in the string itself, precede it with a backslash (\):

"I said, \"Look out!\""

This represents the string containing these characters:

I said, "Look out!"

To include a backslash in the string, precede it with another backslash.

An ordinary key is denoted by writing the character in a string. For instance, the keystroke q is denoted in Lisp by the string "q". The keystroke \ would be written as "\\”.

Special characters such as META-question-mark are denoted in strings using a special syntax: "\M-?". Even though there are four characters inside the double quotes, Emacs reads this as a string containing the single character called META-question-mark.[3]

In Emacs jargon, M-x is shorthand for META-x, and "\M-x" is the string version. CONTROL-x is abbreviated C-x in Emacs documentation, and in strings is written as: "\C-x". You can combine the CONTROL and META keys, too. CONTROL-META-x is denoted C-M-x and is written as "\C-\M-x" in strings. "\C-\M-x", incidentally, is interchangeable with "\M-\C-x" (META-CONTROL-x).

(CONTROL-x is also sometimes abbreviated ^x in documentation, corresponding to this alternative string syntax: "\^x".)

Now we know how to fill in the first argument to our global-set-key example:

(global-set-key "\M-?"  command)

(One other way to write the keysequence "\M-?" is "\e?". The string "\e" denotes the escape character, and M-x is the same as ESC x.)

Next we must figure out what belongs in place of command. This argument should be the name of the Help function that we want M-? to invoke—i.e., the function that C-h now invokes. In Lisp, functions are named with symbols. Symbols are like function names or variable names in other languages, although Lisp allows a wider variety of characters in symbols than most languages allow in their variable names. For instance, legal Lisp symbols include let* and up&down-p.

To What Is C-h Bound?

In order to find the symbol that names the Help command, we can use C-h b, which invokes another command called describe-bindings. This is one of the Help system’s many subcommands. It presents a window listing all the keybindings in effect. Looking through it for the C-h binding, we find this line:

C-h          help-command

This tells us that help-command is the symbol that names the function that invokes Help.

Our Lisp example is almost complete, but we can’t just write

(global-set-key "\M-?" help-command)       ;almost right!

This is wrong because of the way symbols are interpreted when they appear in Lisp expressions. If a symbol appears in the first position of a list, it’s the name of a function to execute. If it appears elsewhere, it’s a variable whose value needs to be retrieved. But when we run global-set-key as shown, we don’t want the value contained in help-command, whatever that may be. The value we want is the symbol help-command itself. In short, we wish to prevent the symbol from being evaluated before it’s passed to global-set-key. After all, as far as we know, help-command doesn’t have a value as a variable.

The way to prevent a symbol (or any Lisp expression) from being evaluated is to quote it by preceding it with a single quote ('). It looks like this:

(global-set-key "\M-?" 'help-command)

Our Lisp example is now complete. If you place this line in your .emacs file, then M-? will invoke help-command the next time you run Emacs, and in all future Emacs sessions. (Soon we’ll learn how to make Lisp expressions take effect immediately.) M-? b will invoke describe-bindings the way C-h b did before (and still does—at this point, both M-? and C-h are bound to help-command).

Incidentally, to illustrate the difference between quoting and not quoting, the same effect could be achieved with

(setq x 'help-command)             ;setq  assigns a variable
(global-set-key "\M-?" x)          ;use x's value

The first line sets the variable x to hold the symbol help-command. The second uses x’s value—the symbol help-command—as the binding for M-?. The only difference between this and the first example is that now you end up with a leftover variable named x that didn’t exist before.

Symbols aren’t the only things that may follow a ' character; any Lisp expression can be quoted, including lists, numbers, strings, and other kinds of expressions we’ll learn about later. Writing 'expr is shorthand for

(quote  expr)

which, when evaluated, yields expr. You might have noticed that a quote is required before the symbol help-command but not before the string argument, "\M-?". This is because in Lisp, strings are self-evaluating, which means that when the string is evaluated, the result is the string itself. So quoting it, while harmless, is redundant. Numbers, characters, and vectors are other types of self-evaluating Lisp expressions.

To What Should C-h Be Bound?

Now that we’ve bound help-command to M-?, the next thing to do is to change the binding for C-h. Using exactly the same process just described—that is, running describe-bindings (with either C-h b or M-? b at this point)—we find that the command invoked by DEL is delete-backward-char.

So we can write

(global-set-key "\C-h" 'delete-backward-char)

Now DEL and C-h do the same thing. If you put these lines into your .emacs file:

(global-set-key "\M-?" 'help-command)
(global-set-key "\C-h" 'delete-backward-char)

then in your future Emacs sessions, your BACKSPACE/DELETE/ERASE key will do the right thing, whether it sends a BS code or a DEL code. But how can we cause these changes to take effect in the current session? This requires explicit evaluation of these two Lisp expressions.

Evaluating Lisp Expressions

There are several ways to explicitly evaluate Lisp expressions.

  1. You can put the Lisp expressions in a file, then load the file. Suppose you place the expressions in a file named rebind.el. (Emacs Lisp filenames customarily end in .el.) You could then type M-x load-file RET rebind.el RET to cause Emacs to evaluate the contents of that file.

    If you placed those expressions into your .emacs file, you could load .emacs in the same way. But after you’ve been using Emacs for a while, your .emacs tends to grow, and if it’s very large, loading it could be slow. In that case, you wouldn’t want to load the entire file just to get the effect of a couple of small changes. That brings us to our next option.

  2. You can use the command eval-last-sexp, which is bound to[4] C-x C-e. (Sexp[5] is an abbreviation for S-expression, which in turn is short for symbolic expression, which is another name for “Lisp expression.”) This command evaluates the Lisp expression to the left of the cursor. So what you’d do is position the cursor at the end of the first line:

    (global-set-key "\M-?" 'help-command)▌
    (global-set-key "\C-h" 'delete-backward-char)

    and press C-x C-e; then move to the end of the second line:

    (global-set-key "\M-?" 'help-command)
    (global-set-key "\C-h" 'delete-backward-char)▌

    and press C-x C-e again. Note that each time you press C-x C-e, the result of evaluating global-set-key—the special symbol nil (which we’ll see again later)—is shown in Emacs’s message area at the bottom of the screen.

  3. You can use the command eval-expression, which is bound to M-:[6]. This command prompts you in the minibuffer (the area at the bottom of the screen) for a Lisp expression, then evaluates it and shows the result.

    eval-expression is one of a few commands considered by the makers of Emacs to be dangerous for novice users to try. Hogwash, I say; nevertheless, the command is initially disabled, so when you try to use it, Emacs tells you “You have typed M-:, invoking disabled command eval-expression.” Then it displays a description of eval-expression and prompts you as follows:

    You can now type
    Space to try the command just this once,
              but leave it disabled,
    Y to try it and enable it (no questions if you use it again),
    N to do nothing (command remains disabled).

    If you choose Y, Emacs adds the following Lisp expression to your .emacs:

    (put 'eval-expression 'disabled nil)

    (The put function relates to property lists, which we’ll see in the section on Symbol Properties in Chapter 3.) My advice is to put this in your .emacs yourself before you ever get this message from Emacs, so you’ll never have to bother with the “disabled command” warning. As soon as you put the put function in .emacs, of course, it’s a good idea to evaluate it so it takes effect in the present session, using eval-last-sexp as described above.

  4. You can use the *scratch* buffer. This buffer is automatically created when Emacs starts. The buffer is in Lisp Interaction mode. In this mode, pressing C-j invokes eval-print-last-sexp, which is like eval-last-sexp except that the result of the evaluation is inserted into the buffer at the location of the cursor. Another feature of Lisp Interaction mode is its ability to complete a partially typed Lisp symbol when you press M-TAB (which invokes lisp-complete-symbol). Lisp Interaction mode is particularly useful for testing and debugging Lisp expressions that are too long to type into the minibuffer, or that yield complicated data structures when evaluated.

Whichever method you use, evaluating the global-set-key expression results in the new bindings being used.

Apropos

Before wrapping up this first example, let’s discuss Emacs’s most important on-line help facility, apropos. Suppose you’re one of those who have both BS and DEL keys and think it’s a good idea for BS to erase the character preceding the cursor and DEL to erase the character following the cursor. You know that delete-backward-char is the command that accomplishes the former, but you don’t know which command achieves the latter. You strongly suspect that Emacs must have such a command. How do you find it?

The answer is to use the apropos command, which allows you to search all known variables and functions for a pattern you specify. Try this:[7]

M-x apropos RET delete RET

The result is a buffer listing all the matches for “delete” among Emacs’s variables and functions. If we search that buffer for occurrences of the word “character,” we narrow the field down to

backward-delete-char
Command: Delete the previous N characters (following if N is negative).
backward-delete-char-untabify
Command: Delete characters backward, changing tabs into spaces.
delete-backward-char
Command: Delete the previous N characters (following if N is negative).
delete-char
Command: Delete the following N characters (previous if N is negative).

The function delete-char is the one we want.

(global-set-key "\C-?" 'delete-char)

(For historical reasons, the way to write the DEL character is CONTROL-question-mark.)

You may invoke apropos with a prefix argument. In Emacs, pressing C-u before executing a command is a way to pass extra information to the command. Frequently, C-u is followed by a number; for instance, C-u 5 C-b means “move the cursor left 5 characters.” Sometimes the extra information is just the fact that you pressed C-u.

When apropos is invoked with a prefix argument, it not only reports Emacs functions and variables that match the search pattern, it also reports any existing keybindings for each command in the list. (This isn’t the default because finding the keybindings can be slow.) Using C-u M-x apropos RET delete RET and picking out occurrences of “character” as before, we come up with:

backward-delete-char                    (not bound to any keys)
Command: Delete the previous N characters (following if N is negative).
backward-delete-char-untabify           (not bound to any keys)
Command: Delete characters backward, changing tabs into spaces.
delete-backward-char                    C-h, DEL
Command: Delete the previous N characters (following if N is negative).
delete-char                             C-d
Command: Delete the following N characters (previous if N is negative).

This confirms that both C-h and DEL now invoke delete-backward-char, and also informs us that delete-char already has a binding: C-d. After we execute

(global-set-key "\C-?" 'delete-char)

if we run apropos again, we find

backward-delete-char                   (not bound to any keys)
Command: Delete the previous N characters (following if N is negative).
backward-delete-char-untabify          (not bound to any keys)
Command: Delete characters backward, changing tabs into spaces.
delete-backward-char                   C-h
Command: Delete the previous N characters (following if N is negative).
delete-char                            C-d, DEL
Command: Delete the following N characters (previous if N is negative).

When we know that the target of our search is an Emacs command, as opposed to a variable or function, we can further limit the scope of the search by using command-apropos (M-? a) instead of apropos. The difference between a command and other Lisp functions is that commands have been written specially to be invoked interactively, i.e., from a keybinding or with M-x. Functions that aren’t commands can only be invoked as function calls from other Lisp code or by such commands as eval-expression and eval-last-sexp. We’ll look at the roles of functions and commands more in the next chapter.



[1] The proliferation of parentheses in Lisp is a feature that Lisp critics cheerfully decry as a sure sign of its inferiority. According to them, Lisp stands for “Lots of Infernal Stupid Parentheses.” (In fact, Lisp stands for “List Processing.”) In my view, the much simpler syntax renders Lisp code more readable, not less, than code in other languages, as I hope you will agree.

[2] Emacs uses a mark-and-sweep garbage collection scheme, which is one of the easiest ways to implement garbage collection. There are other approaches to implementing garbage collection that would not be so intrusive from the user’s point of view; for instance, so-called “incremental” garbage collection can take place without bringing Emacs to a halt. Unfortunately, Emacs does not employ one of these more advanced approaches.

[3] You can use the length function, which returns the length of a string, to confirm this. If you evaluate (length "\M-?"), the result is 1. How to “evaluate” is covered later in this chapter.

[4] Technically, one should only speak of keysequences being bound to commands, not commands being bound to keysequences. (To say that a keysequence is “bound” to a command correctly signifies that there’s just one thing it can do—invoke that command. To say that a command is “bound” to a keysequence would mean that only one keysequence can invoke the command, but that’s never the case.) But this misuse of “bound to” is as common as the correct use, and rarely causes confusion.

[5] Pronounced “sex pee.” Unfortunately.

[6] This keybinding is new in Emacs 19.29. In prior versions, eval-expression was bound to M-ESC by default.

[7] All Emacs commands, regardless of which keys (if any) they’re bound to, can be invoked with M-x command-name RET. Naturally, M-x is itself just a keybinding for a command, execute-extended-command, which prompts for the name of a command to execute.

With Safari, you learn the way you learn best. Get unlimited access to videos, live online training, learning paths, books, interactive tutorials, and more.

Start Free Trial

No credit card required