9.8. The Lisp Modes


Emacs has three Lisp modes, listed here by their command names:


emacs-lisp-mode

Used for editing Emacs Lisp code, as covered in Chapter 11 (filename .emacs or suffix .el).


lisp-mode

Used for editing Lisp code intended for another Lisp system (suffix .l or .lisp).


lisp-interaction-mode

Used for editing and running Emacs Lisp code.

All three modes have the same basic functionality; they differ only in the support they give to running Lisp code.

All three Lisp modes understand the basic syntax elements common to all language modes. In addition, they have various commands that apply to the more advanced syntactic concepts of S-expressions, lists, and defuns. An S-expression (or syntactic expression) is any syntactically correct Lisp expression, be it an atom (number, symbol, variable, etc.), or parenthesized list. Lists are special cases of S-expressions, and defuns (function definitions) are special cases of lists. Several commands deal with these syntactic concepts; you will most likely become comfortable with a subset of them.

Table 9-11 shows the commands that handle S-expressions.

Table 9-11. S-expression commands

Keystrokes

Command name

Action

C-M-b

backward-sexp

Move backward by one S-expression.

C-M-f

forward-sexp

Move forward by one S-expression.

C-M-t

transpose-sexps

Transpose the two S-expressions around the cursor.

C-M-@

mark-sexp

Set mark to the end of the current S-expression; set the cursor to the beginning.

C-M-k

kill-sexp

Delete the S-expression following the cursor.

(none)

backward-kill-sexp

Delete the S-expression preceding the cursor.


Since an S-expression can be a wide variety of things, the actions of commands that handle S-expressions are determined by where your cursor is when you invoke them. If your cursor is on a ( or on a space preceding one, the S-expression in question is taken to be the list that starts with that (. If your cursor is on some other character such as a letter or number (or preceding whitespace), the S-expression is taken to be an atom (symbol, variable, or constant).

For example, suppose your cursor is in this position:

(mary bob(dave (pete)) ed)

If you type C-M-f, the cursor moves like this:

(mary bob (dave (pete))ed)

That is, the cursor moves forward past the S-expression (dave (pete)), which is a list. However, say your cursor is positioned like this:

(marybob (dave (pete)) ed)

When you type C-M-f, it moves here:

(mary bob(dave (pete)) ed)

In this case, the S-expression is the atom bob.

The commands moving in lists are shown in Table 9-12.

Table 9-12. Commands for moving in lists

Keystrokes

Command name

Action

C-M-n

forward-list

Move forward by one list.

C-M-p

backward-list

Move backward by one list.

C-M-d

down-list

Move forward and down one parenthesis level.

(none)

up-list

Move forward out of one parenthesis level.

C-M-u

backward-up-list

Move backward out of one parenthesis level.


As a mnemonic device, you can think of lists as analogous to lines and S-expressions as analogous to characters; thus, C-n and C-p appear in list motion commands, whereas C-f and C-b appear in S-expression motion commands. C-M-n and C-M-p work similarly to C-M-f and C-M-b, respectively, except that you must position the cursor so that there is a list in front or back of it to move across that is, there must be an opening or closing parenthesis on, after, or before the cursor. If there is no parenthesis, Emacs signals an error. For example, if your cursor is positioned like this:

(fred bob (dave (pete)) ed)

and you type C-M-n, Emacs complains with the message:

Containing expression ends prematurely

However, if your cursor is here:

(fred bob (dave (pete)) ed)

the "next list" is actually (dave (pete)), and the cursor ends up like this if you type C-M-n:

(fred bob (dave (pete))ed)

The commands for moving up or down lists enable you to get inside or outside them. For example, say your cursor is here:

(fred bob (dave (pete)) ed)

typing C-M-d moves the cursor here:

(fred bob (dave (pete)) ed)

This is the result because fred is the next level down after its enclosing list. Typing C-M-d again has this result:

(fred bob (dave (pete)) ed)

You are now inside the list (dave (pete)). At this point, typing C-M-u does the opposite of what C-M-d does: it moves the cursor back and outside of the two lists. But if you type M-x up-list Enter, you will move forward as well as out, resulting in this:

(fred bob (dave (pete))ed)

The commands for defuns listed in Table 9-13 are more straightforward.

Table 9-13. Commands for working with functions

Keystrokes

Command name

Action

C-M-a

beginning-of-defun

Move to the beginning of the current function.

C-M-e

end-of-defun

Move to the end of the current function.

C-M-h

mark-defun

Put the cursor at the beginning of the function, put the mark at the end.


These commands work properly only when the (defun that starts the current function is at the beginning of a line.

9.8.1 Indentation in Lisp Modes

The Lisp modes provide "flashing" of matching left parentheses; if the matching parenthesis is outside of the current window, the line it is on appears in the minibuffer. The Lisp modes also provide indentation via the Tab key and C-j for newline-and-indent (except in Lisp interaction mode, described later in this chapter). The indentation style supported by the Lisp modes "knows" a lot about Lisp keywords and list syntax; unfortunately, it is not easily customized.[12]

[12] The indentation style is bound up in the Emacs Lisp code for Lisp mode. If you are an experienced Lisp hacker, you can examine the code for lisp-mode.el in the Emacs Lisp directory and determine how to customize indentation the way you wish. A good place to start looking is the function lisp-indent-line.

Here is an example, a Lisp equivalent of the "times" C function shown earlier in the chapter, that illustrates the indentation style:

(defun times (x y)   (let ((i 0)         (result 0))     (while (< i x)       (setq result (+ result y)             i (1+ i)))     result))

The basic indentation value is 2; this value is used whenever code on the next line goes down a level in nesting. For example, the body of the function, after the line containing defun, is indented by 2. The (while... and result)) lines are indented by 2 with respect to the let because they are the body of the block let introduces.

Things like defun, let, and while are function calls, even though they act like keywords. The indentation convention for function calls is that if there are arguments on lines after the line where the function name and first argument appear, the additional arguments line up with the first one. In other words, this has the form:

(function-name arg1                arg2                arg3                ...)

The multiple arguments to setq in the preceding function provide another example of this.

However, the indentation of the line (result 0) shows that something a bit different happens with lists that are not function calls. The list in question is actually ((i 0) (result 0)), which is a list with two elements (both of which are also lists). The indentation style supported by the Lisp modes lines up these two elements.

Even though keyword-like terms such as let and while are actually function calls, the Lisp modes "understand" these functions to the extent that special indentation conventions are set up for them. For example, if we were to put the condition for the while-loop on a separate line and press Tab to indent it properly, the result would be:

    (while          (< i x)       (setq result (+ result y)             i (1+ i)))

Similar things happen with if and cond control structures; Chapter 11 contains properly indented examples.

Another remark about indentation conventions: the Lisp modes are geared toward a style in which multiple right parentheses are put on the same line immediately following each other, instead of on separate lines. For example, the line i (1+ i))) contains right parentheses that close off the 1+ function, the setq, and the while respectively. If you prefer, you can put your closing parentheses on separate lines, but if you press Tab to indent them, they won't line up properly with their matching open parentheses; you have to indent them manually.

In addition to the Tab and C-j commands for indentation, the Lisp modes support the command C-M-q (for indent-sexp), which indents every line in the S-expression just following the cursor. You can use this command, for example, to indent an entire function definition: just put the cursor right before the defun and type C-M-q.

9.8.2 Comments in Lisp Modes

Comments in the Lisp modes are handled by the universal comment command M-;, which indents out to comment-column (or, if there is text at that column, one space past the last character), inserts a semicolon, and puts the cursor just past it. If you want a comment to occupy an entire line (or to start anywhere other than at comment-column), you must move to where you want the comment to start and type the semicolon yourself. Note that if you press Tab on any line that contains only a comment, the comment moves out to comment-column. To get around this, use two or more semicolons; doing so causes Tab to leave the comments where they are. The Lisp modes also support the other comment commands discussed earlier in the chapter, including M-j to extend a comment to another line and M-x kill-comment Enter to get rid of a single-line comment. These features are common to all three Lisp modes; next, we discuss the features unique to each.

9.8.3 Emacs Lisp Mode Differences

Emacs Lisp mode was designed to be used with code meant to run within Emacs itself, so it facilitates running the code you type. Lisp is an interpreted (as opposed to purely compiled) language, so it is possible to blur the line between the write and run/debug phases of Lisp programming; Emacs Lisp mode takes some advantage of this opportunity, whereas Lisp interaction mode goes even further, as we'll see later. In Emacs Lisp mode, the command C-M-x (eval-defun) picks up the function definition around or after the cursor and evaluates it, meaning that it parses the function and stores it so that Emacs "knows" about the function when you invoke it.

Emacs Lisp mode also includes the command M-Tab (for lisp-complete-symbol),[13] which performs completion on the symbol (variable, function name, etc.) preceding the cursor, as described in Chapter 14. Thus, you can type the shortest unambiguous prefix for the symbol, followed by M-Tab, and Emacs tries to complete the symbol's name for you as far as it can. If it completes the symbol name, you can go on with whatever you are doing. If it doesn't, you haven't provided an unambiguous prefix. You can type more characters (to disambiguate further), or you can type M-Tab again, and a help window showing the choices pops up. Then you can type more characters and complete the symbol yourself, or you can try for completion again.

[13] This key binding may not work on all platforms. If it is intercepted by the operating system (as it is on Red Hat Linux), type Esc Tab instead (remember to release Esc before you press Tab).

9.8.4 Lisp Mode Differences

Lisp mode (as opposed to Emacs Lisp mode) is meant for use with Lisp processors other than the Emacs Lisp interpreter. Therefore it includes a couple of commands for interfacing to an external Lisp interpreter. The Lisp mode command C-c C-z (run-lisp) starts up your system's Lisp interpreter as a subprocess and creates the *lisp* buffer (with an associated window) for input and output.[14] If a Lisp subprocess already exists, C-c C-z uses it rather than creating a second one. You can send function definitions to the Lisp subprocess by putting the cursor anywhere within a function's definition and using C-M-x, which in this case stands for lisp-send-defun. This procedure causes the functions you define to become known to the Lisp interpreter so that you can invoke them later.

[14] This Lisp mode command (run-lisp) was designed to run with the franz Lisp system on BSD Unix systems, though it should work with other Lisp interpreters.

9.8.5 Working with Lisp Fragments

Emacs Lisp mode is probably the best thing to use if you are editing entire files of Emacs Lisp code, for example, if you are programming your own mode (as described in Chapter 11) or modifying an existing one. However, if you are editing "little" pieces of Lisp code (for example, making additions or modifications to your .emacs file), Emacs has more powerful features you can use that further blur the line between writing and running code.

9.8.5.1 Commands for evaluating a line of Lisp

The first of these is the command M-: (for eval-expression). This command enables you to type a one-line Lisp expression of any kind in the minibuffer; the expression is evaluated, and the result is printed in the minibuffer. This is an excellent, quick way to check the values of Emacs variables and to experiment with "internal" Emacs functions that aren't bound to keys or that require arguments. You can use the symbol completion command M-Tab while you are using eval-expression.

Unfortunately (or fortunately, depending on your point of view), Emacs doesn't normally let you use eval-expression. If you try pressing M-:, you will see the message loading novice . . . in the minibuffer. Then a window pops up with a message on the order of, "You didn't really mean to type that, did you?" You get three options: press Space to try the command only once, y to try it and enable it for future use with no questions asked, or n to do nothing.

If you want to use eval-expression, type y. This command actually results in the following line being put in your .emacs file:

(put 'eval-expression 'disabled nil)

If you are a knowledgeable Lisp programmer, you will understand that this addition sets the property disabled of the symbol eval-expression to nil. In other words, Emacs considers certain commands to be verboten to novice users and thus allows commands to be disabled. If you want to skip this entire procedure and just use eval-expression, simply put the above line in your .emacs file yourself (make sure you include the single quotes).

Another feature that helps you exercise Emacs Lisp code is C-x C-e (for eval-last-sexp). This command runs the line of Lisp that your cursor is on and prints its value in the minibuffer. C-x C-e is handy for testing single lines of code in an Emacs Lisp file.

9.8.5.2 Using Lisp interaction mode

An even more powerful feature is Lisp interaction mode. This is the mode the default buffer *scratch* is in. Filenames with no suffixes normally cause Emacs to go into Lisp interaction mode, though you can change this using the variable auto-mode-alist, described earlier in this chapter and in more detail in Chapter 10. You can also put any buffer in Lisp interaction mode by typing M-x lisp-interaction-mode Enter; to create an extra Lisp interaction buffer, just type C-x b (for switch-to-buffer), supply a buffer name, and put it in Lisp interaction mode.

Lisp interaction mode is identical to Emacs Lisp mode except for one important feature: C-j is bound to the command eval-print-last-sexp. This command takes the S-expression just before point, evaluates it, and prints the result in the buffer. To get the usual newline-and-indent functionality attached to C-j in other modes, you must press Enter, followed by Tab.

Remember that an S-expression is any syntactically valid expression in Lisp. Therefore, you can use C-j in Lisp interaction mode to check the values of variables, enter function definitions, run functions, and so on. For example, if you type auto-save-interval and press C-j, the value of that variable (300 by default) appears. If you type a defun and press C-j after the last right parenthesis, Emacs stores the function defined (for future invocation) and prints its name; in this case, C-j is similar to C-M-x (for eval-defun) except that the cursor must be after (as opposed to before or in the middle of) the function being defined. If you invoke a function, Emacs evaluates (runs) the expression and responds with whatever value the function returns.

C-j in Lisp interaction mode gives you an excellent way to play with, incrementally develop, and debug Emacs Lisp code, and since Emacs Lisp is "true" Lisp, it is even useful for developing some bits of code for other Lisp systems.



Learning GNU Emacs
Learning GNU Emacs, Third Edition
ISBN: 0596006489
EAN: 2147483647
Year: 2003
Pages: 161

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net