• The name of the mode that appears in the mode line in parentheses
• The local keymap that defines key bindings for commands in the mode
• Variables and constants known only within the Lisp code for the mode
• The special buffer the mode may use
Let's deal with these in order. The mode symbol is set by assigning the name of the function that implements the mode to the global variable major-mode, as in:
(setq major-mode 'calc-mode)
Similarly, the mode name is set by assigning an appropriate string to the global variable mode-name, as in:
(setq mode-name "Calculator")
The local keymap is defined using functions discussed in Chapter 10. In the case of the calculator mode, there is only one key sequence to bind (C-j), so we use a special form of the make-keymap command called make-sparse-keymap that is more efficient with a small number of key bindings. To use a keymap as the local map of a mode, we call the function use-local-map, as in:
(use-local-map calc-mode-map)
As we just saw, variables can be defined by using setq to assign a value to them, or by using let to define local variables within a function. The more "official" way to define variables is the defvar function, which allows documentation for the variable to be integrated into online help facilities such as C-h v (for describe-variable). The format is the following:
(defvar varname initial-value "description of the variable")
A variation on this is defconst, with which you can define constant values (that never change). For example:
(defconst calc-operator-regexp "[-+*/%]"
"Regular expression for recognizing operators.")
defines the regular expression to be used in searching for arithmetic operators. As you will see, we use the calc- as a prefix for the names of all functions, variables, and constants that we define for the calculator mode. Other modes use this convention; for example, all names in C++ mode begin with c++-. Using this convention is a good idea because it helps avoid potential name clashes with the thousands of other functions, variables, and so on in Emacs.
Making variables local to the mode is also desirable so that they are known only within a buffer that is running the mode.[80] To do this, use the make-local-variable function, as in:
(make-local-variable 'calc-stack)
Notice that the name of the variable, not its value, is needed; therefore a single quote precedes the variable name, turning it into a symbol.
Finally, various major modes use special buffers that are not attached to files. For example, the C-x C-b (for list-buffers) command creates a buffer called *Buffer List*. To create a buffer in a new window, use the pop-to-buffer function, as in:
(pop-to-buffer "*Calc*")
There are a couple of useful variations on pop-to-buffer. We won't use them in our mode example, but they are handy in other circumstances.
switch-to-buffer
Same as the C-x b command covered in Chapter 4; can also be used with a buffer name argument in Lisp.
set-buffer
Used only within Lisp code to designate the buffer used for editing; the best function to use for creating a temporary "work" buffer within a Lisp function.
11.5.2 More Lisp Basics: Lists
A Reverse Polish Notation calculator uses a data structure called a stack. Think of a stack as being similar to a spring-loaded dish stack in a cafeteria. When you enter a number into a RPN calculator, you push it onto the stack. When you apply an operator such as plus or minus, you pop the top two numbers off the stack, add or subtract them, and push the result back on the stack.
The list, a fundamental concept of Lisp, is a natural for implementing stacks. The list is the main concept that sets Lisp apart from other programming languages. It is a data structure that has two parts: the head and tail. These are known in Lisp jargon, for purely historical reasons, as car and cdr respectively. Think of these terms as "the first thing in the list" and "the rest of the list." The functions car and cdr, when given a list argument, return the head and tail of it, respectively.[81] Two functions are often used for making lists. cons (construct) takes two arguments, which become the head and tail of the list respectively. list takes a list of elements and makes them into a list. For example, this:
(list 2 3 4 5)
makes a list of the numbers from 2 to 5, and this:
(cons 1 (list 2 3 4 5))
makes a list of the numbers from 1 to 5. car applied to that list would return 1, while cdr would return the list (2 3 4 5).
These concepts are important because stacks, such as that used in the calculator mode, are easily implemented as lists. To push the value of x onto the stack calc-stack, we can just say this:
(setq calc-stack (cons x calc-stack))
If we want to get at the value at the top of the stack, the following returns that value:
(car calc-stack)
To pop the top value off the stack, we say this:
(setq calc-stack (cdr calc-stack))
Bear in mind that the elements of a list can be anything, including other lists. (This is why a list is called a recursive data structure.) In fact (ready to be confused?) just about everything in Lisp that is not an atom is a list. This includes functions, which are basically lists of function name, arguments, and expressions to be evaluated. The idea of functions as lists will come in handy very soon.
11.5.3 The Calculator Mode
The complete Lisp code for the calculator mode appears at the end of this section; you should refer to it while reading the following explanation. If you download or type the code in, you can use the calculator by typing M-x calc-mode Enter. You will be put in the buffer *Calc*. You can type a line of numbers and operators and then type C-j to evaluate the line. Table 11-7 lists the three commands in calculator mode.
Table 11-7. Calculator mode commands
| Command | Action |
|---|---|
= |
Print the value at the top of the stack. |
p |
Print the entire stack contents. |
c |
Clear the stack. |
80
Unfortunately, because such variables are defined before they are made local to the mode, there is still a problem with name clashes with global variables. Therefore, it is still important to use names that aren't already used for global variables. A good strategy for avoiding this is to use variable names that start with the name of the mode.
81
Experienced Lisp programmers should note that Emacs Lisp does not supply standard contractions like cadr, cdar, and so on.