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

The compile package also includes similar support for the Unix grep (search files) command, thus effectively giving Emacs a multifile search capability. If you type M-x grep, you are prompted for arguments to send to grep—that is, a search pattern and filename(s). Emacs runs grep with the -n option, which tells it to print filenames and line numbers of matching lines.[58] The same happens as with M-x compile; you can type C-x ` to have Emacs visit the next matched line in its file.

9.2 Writing Code

We have already seen various examples of Emacs modes, including text mode (see Chapter 2) and shell mode (see Chapter 5). Special functionality like the buffer list (see Chapter 4) and Dired (see Chapter 5) are actually modes as well. All modes have two basic components: an Emacs Lisp package that implements the mode and a function that invokes it.

9.2.1 Language Modes

The version of Emacs on which this book is based (21.3.5) comes with language modes for Ada, assembly, awk, C, C++, Common Lisp, Fortran, ICON, Java, Lisp, MIM, Modula-2, Objective-C, Pascal, Pike, Perl, PROLOG, Python, Scheme, SGML, Simula, and SQL; future versions will undoubtedly add more. Many—but not all—of the language modes are "hooked" into Emacs so that if you visit a file with the proper filename suffix, you will automatically be put in the correct mode. To find out whether Emacs does this for the language you use, look up your language in the table of Emacs Lisp packages in Appendix B. If one or more suffixes is listed in the right-hand column, Emacs invokes the mode for files with those suffixes.

However, if no suffix is listed (or if your compiler supports a different suffix than the ones listed), you can set up Emacs to invoke the mode automatically when you visit your source files. You need to do two things: first, look again at the right-hand column in the package table entry for your language, and you will find the name of the function that invokes the mode (e.g., ada-mode, modula-2-mode). Second, you insert code in your .emacs file that tells Emacs to automatically load the proper package whenever you visit a file with the suffix for the language in question.

You need to write two lines of code for this customization. The first uses the autoload function, which tells Emacs where to look for commands it doesn't already know about. It sets up an association between a function and the package that implements the function so that when the function is invoked for the first time, Emacs loads the package to get the code. In our case, we need to create an association between a function that invokes a language mode and the package that implements the mode. This shows the format of autoload:

(autoload 'function "filename" "description" t)

Note the single quote preceding function and the double quotes around filename and description; for more details on this Lisp syntax, see Chapter 11. If you are a PHP programmer, for example, you can grab the latest Emacs PHP mode from http://sourceforge.net/projects/php-mode/ online. You would then put the following line in your .emacs file:

(autoload 'php-mode "php-mode" "PHP editing mode." t)

This tells Emacs to load the PHP package when the function php-mode is invoked for the first time.

The second line of code completes the picture by creating an association between the suffix for source files in your language and the mode-invoking function so that the function is automatically invoked when you visit a file with the proper suffix. This involves the Emacs global variable auto-mode-alist, covered in Chapter 10; it is a list of associations that Emacs uses to put visited files in modes according to their names. To create such an association for PHP mode so that Emacs puts all files with the suffix .php in that mode, add this line to your .emacs file:

(setq auto-mode-alist (cons '("\\.php$" . php-mode) auto-mode-alist))

This Lisp code sets up the following chain of events when you visit a file whose suffix indicates source code in your programming language. Let's say you visit the file pgm.php. Emacs reads the file, then finds an entry corresponding to the .php suffix in the auto-mode-alist and tries to invoke the associated function php-mode. It notices that the function php-mode doesn't exist, but that there is an autoload association between it and the PHP package. It loads that package and, finding the php-mode command, runs it. After this, your buffer is in PHP mode.

For some interpreted languages like Perl and Python, you will also want to update the interpreter-mode-alist global variable:

(setq interpreter-mode-alist

      (cons '("python" . python-mode) interpreter-mode-alist))

If your script file begins with the Unix interpreter prefix #!, Emacs checks that line to determine what language you are using. That can be especially helpful when the script file does not have a telltale extension like .py or .pl.

9.2.1.1 Syntax

Although language modes differ in exact functionality, they all support the same basic concepts. The most important of these involves knowledge of the syntax of the language in question—its characters, vocabulary, and certain aspects of its grammar. We have already seen that Emacs handles some syntactic aspects of human language. When you edit regular text, Emacs knows about words, sentences, and paragraphs: you can move the cursor and delete text with respect to those units. It also knows about certain kinds of punctuation, such as parentheses: when you type a right parenthesis, it "flashes" the matching left parenthesis by moving the cursor there for a second and then returning.[59] This is a convenient way of ensuring that your parentheses match correctly.

Emacs has knowledge about programming language syntax that is analogous to its knowledge of human language syntax. In general, it keeps track of the following basic syntactic elements:

• Words, which correspond to identifiers and numbers in most programming languages.

• Punctuation, which includes such things as operators (e.g., +, -, <, and >) and statement separators (e.g., semicolons).

• Strings, which are strings of characters to be taken literally and surrounded by delimiters (such as quotation marks).

• Parentheses, which can include such things as square brackets ([ and ]) and curly braces ({ and }) as well as regular parentheses.

вернуться

58

If grep -n is run on only one file, it just prints line numbers; Emacs forces it to print the filename as well in this case by appending the dummy file /dev/null to the grep command.

вернуться

59

Actually, there is a limit to how far back (in characters) Emacs searches for a matching open parenthesis: this is the value of the variable blink-matching-paren-distance, which defaults to 25,600. The duration of the "flash" is also configurable: it's the value (in seconds) of blink-matching-delay, whose default value is 1.