Sams Teach Yourself Emacs in 24 Hours |  | ContentsIndex
Hour 16: Interfacing with the System |  | Previous HourNext Hour
Sections in this Hour: |  |

## Writing Your Own Commands to Execute Programs

Now that you are familiar with running different types of programs from Emacs, you might be interested in having a few specialized commands of your own to run. These commands could take care of running the program and even figuring out the command-line parameters for you.

For example, say you have a unique version control system which you work with regularly, and this system is different from the version control programs discussed in Hour 19. This system has the command checkout as a method for locking the file locally. What you most likely want is a command that runs checkout synchronously, and you want to make sure no errors occur.

To do this, you can create an example that serves as a template for almost any command you would like to bind. You start with the command call-process, a function that runs a synchronous subprocess. The parameters are PROGRAM, INPUT, OUTPUT, and DISPLAY, and command-line arguments follow. The program is a string representing the program to run (without arguments). INPUT specifies a stdin to use and OUTPUT represents the stdout. INPUT is either nil (no input) or a string representing the text to be sent to the subprocess. OUTPUT can be t, meaning the current buffer, or another buffer. DISPLAY means that the OUTPUT buffer is updated as new input is made available (even though you are calling your subprocess synchronously).

The next useful function you need to know is buffer-file-name, which returns the filename of the current buffer. This saves you time when you run your program. You can now write your program, which will look like this:

    (defun my-checkout ()
      "Check out the current buffer's file using our unique checkout program."
      (interactive)
      (save-excursion
         (let ((cb (current-buffer)))
            (set-buffer (get-buffer-create "*TEMP*"))
            (call-process "checkout" nil t nil (buffer-file-name cb))
            ;; Perform error checking here
            )))

This forms the baseline for any program you might want to write to call external programs. One of the important things to do is have the output go into a temporary buffer for examination later. This is what the (set-buffer (get-buffer-create... line does. When your current buffer is now the temporary one, you can call your subprocess with the buffer you saved in cb. The let command locally binds cb to the value of (current-buffer) so you can use it when your current buffer is something different.

Now that you have run your program, you might want to extend it to do error checking. Let's say the checkout program outputs the string:

    Gnarly error: You forgot to do something important.

After the comment referring to error checking, you would add the following code:

        (goto-char (point-min))
        (if (looking-at "Gnarly error:")
            (error (buffer-string)))

Here, the first line simply moves point to the beginning of the buffer. The next line checks the output to see whether there was a gnarly error or not. looking-at can take a regular expression as discussed in Hour 9, "Regular Expressions," but plain text works fine too. It returns t if there is a match. Finally, when there is an error, use the error command to report it with buffer-string as the text displayed in the minibuffer. Now that this is in your ~/.emacs file, you can run it whenever you want by typing M-x my-checkout Enter.

Now finish by showing this as a template for use by any command:

    (defun my-<program> ()
      "Run <program> on the current buffer's file."
      (interactive)
      (save-excursion
         (let ((cb (current-buffer)))
            (set-buffer (get-buffer-create "*TEMP*"))
            (call-process "<program>" nil t nil (buffer-file-name cb) "<other parameters>")
            ;; Perform error checking here
           (goto-char (point-min))
           (if (looking-at "<error text regular expression>")
               (error (buffer-string)))
            )))

For more detail on how to write programs, be sure to read Hour 24, "Installing Emacs Add-Ons."

Sams Teach Yourself Emacs in 24 Hours |  | ContentsIndex
Hour 16: Interfacing with the System |  | Previous HourNext Hour
Sections in this Hour: |  |

© Copyright Macmillan USA. All rights reserved.