%filename%
Gets replaced by the name of the file being created.
%creator%
, %author%
These are synonyms; both get replaced by the name of the user creating the file.
%date%
Turns into the current date and time when the file is created.
%once%
Expands into boilerplate code for the C preprocessor to cause a header file to include itself only once, even if it's been included multiple times by other header files. (This sort of thing has been taken care of in more modern environments like Objective C and Java but can still be handy when working with traditional C compilers.)
%package%
Is replaced by the Java package which contains the file being created (assuming the file is a Java class). This package is determined by examining the directory structure in which the file is being placed.
%class%
Becomes the name of the Java class being defined in the file, assuming it's a Java source file.
The first function, find-template-file, is responsible for searching the directory hierarchy above the file being created, looking for a file with the right name to be considered a file template (if template-file-namehas been left at its default value, this looks for either a file named file-template or file-template-ext where ext is the extension at the end of the name of the file being created). It just keeps lopping the last directory off the path in which it's looking, starting with the location of the new file, and seeing if it can read a file with one of those names in the current directory, until it runs out of directories.
The function template-file-not-found-hookis the "main program" of the template system. It gets "hooked in" to the normal Emacs find-fileprocess, and called whenever find-filedoesn't find the file the user asked for (in other words, a new file is being created). It uses condition-case(a mechanism similar to exception handling in C++ and Java) to make sure it gets a chance to clean up after itself if the user cancels the process of filling in the template file. It checks whether the template file can be found, asks users if they want to use it, and (if they do) loads it into the new buffer and performs the placeholder substitutions. For an explanation of the list manipulation and funcallcode that makes the substitutions work, read the discussion of Calculator mode in the next section. Finally, it jumps to the beginning of the new buffer and marks it as unchanged (because, as far as users are concerned, it's a brand new buffer on which they've not yet had to expend any effort).
Immediately after the function definition is the chunk of code that hooks it into the find-filemechanism. The file-not-found-hooksis a variable that Emacs uses to keep track of things to do when a requested file is not found. (Giving you opportunities to change or enhance normal behavior through "hooks" is a wonderful trait of Emacs that is discussed in more depth following the Calculator mode example later in this chapter.) Our code checks to make sure it's not already hooked up (so you don't end up having it run twice or more if you re-load the library file during an Emacs session), and then installs our hook at the end of the list if it's not there.
The rest of the file is helper functions to handle the more complex placeholders. template-insert-java-packagefigures out the value that should replace %package%
, while template-insert-class-namefigures out the Java class name that replaces %class%
.
The last function call in the file, (provide 'template)
, records the fact that a "feature" named "template" has been loaded successfully. The providefunction works with requireto allow libraries to be loaded just once. When the function (require 'template)
is executed, Emacs checks whether the feature "template" has ever been provided. If it has, it does nothing, otherwise, it calls load-libraryto load it. It's a good practice to have your libraries support this mechanism, so that they can be gracefully and efficiently used by other libraries through the requiremechanism. You'll find this pattern throughout the Emacs library sources.
11.5 Programming a Major Mode
After you get comfortable with Emacs Lisp programming, you may find that that "little extra something" you want Emacs to do takes the form of a major mode. In previous chapters, we covered major modes for text entry, word processor input, and programming languages. Many of these modes are quite complicated to program, so we'll provide a simple example of a major mode, from which you can learn the concepts needed to program your own. Then, in the following section, you will learn how you can customize existing major modes without changing any of the Lisp code that implements them.
We'll develop Calculator mode, a major mode for a calculator whose functionality will be familiar to you if you have used the Unix dc (desk calculator) command. It is a Reverse Polish (stack-based) calculator of the type made popular by Hewlett-Packard. After explaining some of the principal components of major modes and some interesting features of the calculator mode, we will give the mode's complete Lisp code.
11.5.1 Components of a Major Mode
A major mode has various components that integrate it into Emacs. Some are:
• The symbol that is the name of the function that implements the mode
• 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-keymapcommand called make-sparse-keymapthat 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 letto define local variables within a function. The more "official" way to define variables is the defvarfunction, 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.
Читать дальше