(make-local-variable 'calc-proc-fun)
(setq major-mode 'calc-mode)
(setq mode-name "Calculator")
(use-local-map calc-mode-map))
The following are some possible extensions to the calculator mode, offered as exercises. If you try them, you will increase your understanding of the mode's code and Emacs Lisp programming in general.
• Add an operator ^
for "power" ( 4 5 ^
evaluates to 1024
). There is no built-in power function in Emacs Lisp, but you can use the built-in function expt
.
• Add support for octal (base 8) and/or hexadecimal (base 16) numbers. An octal number has a leading "0," and a hexadecimal has a leading "0x"; thus, 017 equals decimal 15, and 0x17 equals decimal 23.
• Add operators \+
and \*
to add/multiply all of the numbers on the stack, not just the top two (e.g., 4 5 6 \+
evaluates to 15
, and 4 5 6 \*
evaluates to 120
). [82]
• As an additional test of your knowledge of list handling in Lisp, complete the example (Example 5) from earlier in this chapter that searches compilation-error-regexp-alistfor a match to a compiler error message. (Hint: make a copy of the list, then pick off the top element repeatedly until either a match is found or the list is exhausted.)
11.6 Customizing Existing Modes
Now that you understand some of what goes into programming a major mode, you may decide you want to customize an existing one. Luckily, in most cases, you don't have to worry about changing any mode's existing Lisp code to do this; you may not even have to look at the code. All Emacs major modes have "hooks" for letting you add your own code to them. Appropriately, these are called mode-hooks . Every built-in major mode in Emacs has a mode hook called mode-name
-hook, where mode-name
is the name of the mode or the function that invokes it. For example, C mode has c-mode-hook, shell mode has shell-mode-hook, etc.
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. lambdais very much like defunin that it is used to define functions; the difference is that lambdadefines functions that don't have names (or, in Lisp parlance, "anonymous functions"). The format of lambdais:
(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 7we 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-cfollowed by a period). This is not as mnemonic a binding as C-c <for picture-movement-leftor C-c ^for picture-movement-up, so let's say you want to make C-c vthe binding for picture-movement-downinstead. 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-pictureis 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 lambdafunction 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 "
"))
(defun html-title( )
(interactive)
(insert ""))
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-cis 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.
Читать дальше