Выбрать главу

The next two conditional expressions in the cond statement check if count is 1 or 2 and cause it to return "one" or "two" as appropriate. We could have written the first one using the same structure, but then we'd have missed out on an opportunity for a digression into Lisp trivia!

The last conditional expression is simply the atom t (true), which means its body is executed whenever all the preceding expressions failed. It returns the value many. Executing this function gives us results like these:

(how-many 1)

"one"

(how-many 0)

"no"

(how-many 3)

"many"

Combining these two helper functions into a mechanism to report the change count for our fancy command is easy.

(defun report-change-count (count)

  (message "Made %s %s." (how-many count) (pluralize "change" count)))

We get results like these:

(report-change-count 0)

"Made no changes."

(report-change-count 1)

"Made one change."

(report-change-count 1329)

"Made many changes."

11.3 Useful Built-in Emacs Functions

Many of the Emacs functions that exist and that you may write involve searching and manipulating the text in a buffer. Such functions are particularly useful in specialized modes, like the programming language modes described in Chapter 9. Many built-in Emacs functions relate to text in strings and buffers; the most interesting ones take advantage of Emacs's regular expression facility, which we introduced in Chapter 3.

We first describe the basic functions relating to buffers and strings that don't use regular expressions. Afterwards, we discuss regular expressions in more depth than was the case in Chapter 3, concentrating on the features that are most useful to Lisp programmers, and we describe the functions that Emacs makes available for dealing with regular expressions.

11.3.1 Buffers, Text, and Regions

Table 11-4 shows some basic Emacs functions relating to buffers, text, and strings that are only useful to Lisp programmers and thus aren't bound to keystrokes. We already saw a couple of them in the count-words-buffer example. Notice that some of these are predicates, and their names reflect this.

Table 11-4. Buffer and text functions

Function Value or action
point Character position of point.
mark Character position of mark.
point-min Minimum character position (usually 1).
point-max Maximum character position (usually size of buffer).
bolp Whether point is at the beginning of the line (t or nil).
eolp Whether point is at the end of the line.
bobp Whether point is at the beginning of the buffer.
eobp Whether point is at the end of the buffer.
insert Insert any number of arguments (strings or characters) into the buffer after point.
number-to-string Convert a numerical argument to a string.
string-to-number Convert a string argument to a number (integer or floating point).
char-to-string Convert a character argument to a string.
substring Given a string and two integer indices start and end, return the substring starting after start and ending before end. Indices start at 0. For example, (substring "appropriate" 2 5) returns "pro".
aref Array indexing function that can be used to return individual characters from strings; takes an integer argument and returns the character as an integer, using the ASCII code (on most machines). For example, (aref "appropriate" 3) returns 114, the ASCII code for r.

Many functions not included in the previous table deal with buffers and text, including some that you should be familiar with as user commands. Several commonly used Emacs functions use regions, which are areas of text within a buffer. When you are using Emacs, you delineate regions by setting the mark and moving the cursor. However, region-oriented functions (such as kill-region, indent-region, and shell-command-on-region—really, any function with region in its name) are actually more flexible when used within Emacs Lisp code. They typically take two integer arguments that are used as the character positions of the boundaries for the region on which they operate. These arguments default to the values of point and mark when the functions are called interactively.

Obviously, allowing point and mark as interactive defaults is a more general (and thus more desirable) approach than one in which only point and mark can be used to delineate regions. The r option to the interactive function makes it possible. For example, if we wanted to write the function translate-region-into-German, here is how we would start: