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

What exactly is a hook? It is a variable whose value is some Lisp code to run when the mode is invoked. When you invoke a mode, you run a Lisp function that typically does many things (e.g., sets up key bindings for special commands, creates buffers and local variables, etc.); the last thing a mode-invoking function usually does is run the mode's hook if it exists. Thus, hooks are "positioned" to give you a chance to override anything the mode's code may have set up. For example, any key bindings you define override the mode's default bindings.

We saw earlier that Lisp code can be used as the value of a Lisp variable; this use comes in handy when you create hooks. Before we show you exactly how to create a hook, we need to introduce yet another Lisp primitive function: lambda. lambda is very much like defun in that it is used to define functions; the difference is that lambda defines functions that don't have names (or, in Lisp parlance, "anonymous functions"). The format of lambda is:

(lambda (args)

  code)

where args are arguments to the function and code is the body of the function. To assign a lambda function as the value of a variable, you need to "quote" it to prevent it from being evaluated (run). That is, you use the form:

(setq var-name

      '(lambda ( )

         code))

Therefore, to create code for a mode hook, you could use the form:

(setq mode-name-hook

      '(lambda ( )

         code for mode hook))

However, it's quite possible that the mode you want to customize already has hooks defined. If you use the setq form, you override whatever hooks already exist. To avoid this, you can use the function add-hook instead:

(add-hook 'mode-name-hook

       '(lambda ( )

  code for mode hook))

The most common thing done with mode hooks is to change one or more of the key bindings for a mode's special commands. Here is an example: in Chapter 7 we saw that picture mode is a useful tool for creating simple line drawings. Several commands in picture mode set the default drawing direction. The command to set the direction to "down," picture-movement-down, is bound to C-c . (C-c followed by a period). This is not as mnemonic a binding as C-c < for picture-movement-left or C-c ^ for picture-movement-up, so let's say you want to make C-c v the binding for picture-movement-down instead. The keymap for picture mode is, not surprisingly, called picture-mode-map, so the code you need to set this key binding is this:

(define-key picture-mode-map "\C-cv" 'picture-movement-down)

The hook for picture mode is called edit-picture-hook (because edit-picture is the command that invokes picture mode). So, to put this code into the hook for picture mode, the following should go into your .emacs file:

(add-hook 'edit-picture-hook

      '(lambda ( )

         (define-key picture-mode-map "\C-cv" 'picture-movement-down)))

This instruction creates a lambda function with the one key binding command as its body. Then, whenever you enter picture mode (starting with the next time you invoke Emacs), this binding will be in effect.

As a slightly more complex example, let's say you create a lot of HTML pages. You use HTML mode (see Chapter 8), but you find that there are no Emacs commands that enter standard head and title tags, despite the fact that the help text reminds you of their importance. You want to write your own functions to insert these strings, and you want to bind them to keystrokes in HTML mode.

To do this, you first need to write the functions that insert the tag strings. The simplest approach would just be to insert the text:

(defun html-head ( )

  (interactive)

  (insert "<head></head>"))

(defun html-title( )

  (interactive)

  (insert "<title></title>"))

Remember that the calls to (interactive) are necessary so that Emacs can use these functions as user commands.

The next step is to write code that binds these functions to keystrokes in HTML mode's keymap, which is called html-mode-map, using the techniques described in Chapter 10. Assume you want to bind these functions to C-c C-h (head) and C-c C-t (title). C-c is used as a prefix key in many Emacs modes, such as the language modes we saw in the last chapter. Again, this is no problem:

(define-key html-mode-map"\C-c\C-h" 'html-head)

(define-key html-mode-map"\C-c\C-t" 'html-title))

Finally, you need to convert these lines of Lisp into a value for html-mode-hook. Here is the code to do this:

(add-hook 'html-mode-hook

      '(lambda ( )

         (define-key html-mode-map"\C-c\C-h" 'html-head)

         (define-key html-mode-map"\C-c\C-t" 'html-title)))

If you put this code in your .emacs file, together with the earlier function definitions, you get the desired functionality whenever you use HTML mode.

If you try using these functions, though, you'll find they have some noticeable drawbacks compared to the other tag insertion commands in HTML mode. For one thing, while the other helper commands leave your cursor in between the opening and closing tags, our insertions leave the cursor after the closing tag, which is not only inconsistent, but it's much less helpful. Also, while the other tags you insert can be customized in terms of your preferred capitalization, or wrapped around existing content in the document, our simple-minded insert calls give us no such capabilities.

Luckily, it's not hard to add the smarts we want. It turns out that HTML mode is defined in the file sgml-mode.el (we learned this by applying help's handy describe-function command, C-h f, to the mode-defining function HTML mode. Armed with this knowledge, it was an easy matter to pull up and study the Lisp code that makes it work using the find-library-file utility shown in "A Treasure Trove of Examples" earlier in this chapter. A little quick hunting to find a parallel example revealed that the tag support is implemented using a skeletal function generator. Without going into too much detail, it turns out that the code we want to use is this:

(define-skeleton html-head

  "HTML document header section."

  nil

  "<head>" _ "</head>")

(define-skeleton html-title