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

Other such functions aren't available as user commands. Perhaps the most widely used one is looking-at. This function takes a regular expression argument and does the following: it returns t if the text after point matches the regular expression (nil otherwise); if there was a match, it saves the pieces surrounded by \\( and \\) for future use, as seen earlier. The function string-match is similar: it takes two arguments, a regexp and a string. It returns the starting index of the portion of the string that matches the regexp, or nil if there is no match.

The functions match-beginning and match-end can be used to retrieve the saved portions of the matched string. Each takes as an argument the number of the matched expression (as in \\n in replace-regexp replace strings) and returns the character position in the buffer that marks the beginning (for match-beginning) or end (for match-end) of the matched string. With the argument 0, the character position that marks the beginning/end of the entire string matched by the regular expression is returned.

Two more functions are needed to make the above usefuclass="underline" we need to know how to convert the text in a buffer to a string. No problem: buffer-string returns the entire buffer as a string; buffer-substring takes two integer arguments, marking the beginning and end positions of the substring desired, and returns the substring.

With these functions, we can write a bit of Lisp code that returns a string containing the portion of the buffer that matches the nth parenthesized subexpression:

(buffer-substring (match-beginning n (match-end n)))

In fact, this construct is used so often that Emacs has a built-in function, match-string, that acts as a shorthand; (match-string n) returns the same result as in the previous example.

An example should show how this capability works. Assume you are writing the Lisp code that parses compiler error messages, as in our previous example. Your code goes through each element in compilation-error-regexp-alist, checking if the text in a buffer matches the regular expression. If it matches, your code needs to extract the filename and the line number, visit the file, and go to the line number.

Although the code for going down each element in the list is beyond what we have learned so far, the routine basically looks like this:

for each element in compilation-error-regexp-alist

  (let ((regexp the regexp in the element)

        (file-subexp the number of the filename subexpression)

        (line-subexp the number of the line number subexpression))

    (if (looking-at regexp)

        (let ((filename (match-string file-subexp))

              (linenum (match-string line-subexp)))

          (find-file-other-window filename)

          (goto-line linenum))

      (otherwise, try the next element in the list)))

The second let extracts the filename from the buffer from the beginning to the end of the match to the file-subexp-th subexpression, and it extracts the line number similarly from the line-subexp-th subexpression (and converts it from a string to a number). Then the code visits the file (in another window, not the same one as the error message buffer) and goes to the line number where the error occurred.

The code for the calculator mode later in this chapter contains a few other examples of looking-at, match-beginning, and match-end.

11.3.5 Finding Other Built-in Functions

Emacs contains hundreds of built-in functions that may be of use to you in writing Lisp code. Yet finding which one to use for a given purpose is not so hard.

The first thing to realize is that you will often need to use functions that are already accessible as keyboard commands. You can use these by finding out what their function names are via the C-h k (for describe-key) command (see Chapter 14). This gives the command's full documentation, as opposed to C-h c (for describe-key-briefly), which gives only the command's name. Be carefuclass="underline" in a few cases, some common keyboard commands require an argument when used as Lisp functions. An example is forward-word; to get the equivalent of typing M-f, you have to use (forward-word 1).

Another powerful tool for getting the right function for the job is the command-apropos (C-h a) help function. Given a regular expression, this help function searches for all commands that match it and display their key bindings (if any) and documentation in a *Help* window. This can be a great help if you are trying to find a command that does a certain "basic" thing. For example, if you want to know about commands that operate on words, type C-h a followed by word, and you will see documentation on about a dozen and a half commands having to do with words.

The limitation with command-apropos is that it gives information only on functions that can be used as keyboard commands. Even more powerful is apropos, which is not accessible via any of the help keys (you must type M-x apropos Enter). Given a regular expression, apropos displays all functions, variables, and other symbols that match it. Be warned, though: apropos can take a long time to run and can generate very long lists if you use it with a general enough concept (such as buffer).

You should be able to use the apropos commands on a small number of well-chosen keywords and find the function(s) you need. Because, if a function seems general and basic enough, the chances are excellent that Emacs has it built-in.

After you find the function you are interested in, you may find that the documentation that apropos prints does not give you enough information about what the function does, its arguments, how to use it, or whatever. The best thing to do at this point is to search Emacs's Lisp source code for examples of the function's use. "A Treasure Trove of Examples" earlier in this chapter provides ways of finding out the names of directories Emacs loads libraries from and an easy way of looking at a library once you know its name. To search the contents of the library files you'll need to use grep or some other search facility to find examples, then edit the files found to look at the surrounding context. If you're ambitious you could put together the examples and concepts we've discussed so far to write an extension of the find-library-file command that searches the contents of the library files in each directory on the load path! Although most of Emacs's built-in Lisp code is not profusely documented, the examples of function use that it provides should be helpful—and may even give you ideas for your own functions.