Chapter 4. Searching and Modifying Buffers

There will be lots of times when you want to search through a buffer for a string, perhaps replacing it with something else. In this chapter we'll show a lot of powerful ways to do this. We'll cover the functions that perform searches and also show you how to form regular expressions, which add great flexibility to the kinds of searches you can do.

Inserting the Current Time

It is sometimes useful to insert the current date or time into a file as you edit it. For instance, right now, as I'm writing this, it's 10:30pm on Friday, 18 August, 1996. A few days ago, I was editing a file of Emacs Lisp code and I changed a comment that read

;; Each element of ENTRIES has the form
;; (NAME (VALUE-HIGH . VALUE-LOW))

to

;; Each element of ENTRIES has the form
;; (NAME (VALUE-HIGH . VALUE-LOW))
;; [14 Aug 96] I changed this so NAME can now be a symbol,
;; a string, or a list of the form (NAME . PREFIX) [bg]

I placed a timestamp in the comment because it could be useful when editing that code in the future to look back and see when this change was made.

A command that merely inserts the current time is simple, once you know that the function current-time-string yields today's date and time as a string.[18]

(defun insert-current-time ()
  "Insert the current time"
  (interactive "*")
  (insert (current-time-string)))

The section More Asterisk Magic later in this chapter explains the meaning of (interactive "*") and insert.

The simple function above is pretty inflexible, as it always results in inserting a string of the form "Sun Aug 18 22:34:53 1996" (in the style of the standard C library functions ctime and asctime). That's cumbersome if all you want is the date, or just the time, or if you prefer 12-hour time instead of 24-hour time, or dates in the form "18 Aug 1996" or "8/18/96" or "18/8/96".

Happily, we can get finer control if we're willing to do a little extra work. Emacs includes a few other time-related functions, notably current-time, which yields the current time in a raw form, and format-time-string, which can take such a time and format it in a wide variety of ways (in the style of C's strftime). For instance,

(format-time-string "%l.%M %p" (current-time))

returns "10.38 PM". (The format codes used here are %l, "hour from 1-12," %M, "minute from 00-59," and %p, "the string 'AM' or 'PM'." For a complete list of format codes, use describe-function on format-time-string.)

From here it's a short leap to providing two commands, one for inserting the current time and one for inserting the current date. We can also easily permit the format used by each to be user-configurable, based on a configuration variable the user can set. Let's call the two functions insert-time and insert-date. The corresponding configuration variables will be insert-time-format and insert-date-format.

User Options and Docstrings

First we'll define the variables.

(defvar insert-time-format "%X"
  "*Format for \\[insert-time] (c.f. 'format-time-string').")
(defvar insert-date-format "%x"
  "*Format for \\[insert-date] (c.f. 'format-time-string').")

There are two new things to note about these docstrings.

  • First, each begins with an asterisk (*). A leading asterisk has special meaning in defvar docstrings. It means that the variable in question is a user option. A user option is just like any other Lisp variable except that it's treated specially in two cases:

    • User options can be set interactively using set-variable, which prompts the user for a variable name (with completion of partially typed names) and a value. In some cases, the value can be entered in an intuitive way without having to dress it up in Lisp syntax; e.g., strings can be entered without their surrounding double-quotes.

      To set variables interactively when they aren't user options, you must do something like

      M-: (setq variable value) RET

      (using Lisp syntax for value).

    • User options, but not other variables, can be edited en masse using the option-editing mode available as M-x edit-options RET.[19]

  • The second new thing about these docstrings is that each contains the special construct \[command]. (Yes, it's \[…], but since it's written inside a Lisp string, the backslash has to be doubled: \\[…].) This syntax is magic. When the docstring is displayed to the user—such as when the user uses apropos or describe-variable—\[command] is replaced with a representation of a keybinding that invokes command. For example, if C-x t invokes insert-time, then the docstring

    "*Format for \\[insert-time] (c.f. 'format-time-string')."

    is displayed as

    *Format for C-x t (c.f. 'format-time-string').

    If there is no keybinding for insert-time, then M-x insert-time is used. If there are two or more keybindings for insert-time, Emacs chooses one.

    Suppose you want the string \[insert-time] to appear literally in a docstring. How could you prevent its keybinding being substituted? For this purpose there is a special escape sequence: \=. When \= precedes \[…], the magic replacement of \[…] doesn't happen. Of course, Lisp string syntax dictates that this be written as "…\\=\\[…]…".

    \= is also useful for escaping the asterisk at the beginning of a defvar docstring, if you don't want the variable to be a user option but you absolutely must have a docstring that begins with an asterisk.

All variables that are shared between two or more functions should be declared with defvar. Which of those should be user options? A rule of thumb is that if the variable directly controls a user-visible feature that a user might want to change, and if setting that variable is straightforward (i.e., no complex data structures or specially coded values), then it should be a user option.

More Asterisk Magic

Now that we've defined the variables that control insert-time and insert-date, here are the definitions of those simple functions.

(defun insert-time ()
  "Insert the current time according to insert-time-format."
  (interactive "*")
  (insert (format-time-string insert-time-format
                              (current-time))))
(defun insert-date ()
  "Insert the current date according to insert-date-format."
  (interactive "*")
  (insert (format-time-string insert-date-format
                              (current-time))))

The two functions are identical except that one uses insert-time-format where the other uses insert-date-format. The insert function takes any number of arguments (which must all be strings or characters) and inserts them one after another in the current buffer at the present location of point, moving point forward.

The main thing to notice about these functions is that each begins with

(interactive "*")

By now you know that interactive turns a function into a command and specifies how to obtain the function's arguments when invoked interactively. But we haven't seen * in the argument of interactive before, and besides, these functions take no arguments, so why does interactive have one?

The asterisk, when it is the first character in an interactive argument, means "abort this function if the current buffer is read-only." It is better to detect a read-only buffer before a function begins its work than to let it get halfway through then die from a "Buffer is read-only" error. In this case, if we omitted to check for read-onlyness, the call to insert would trigger its own "Buffer is read-only" error almost right away and no harm done. A more complicated function, though, might cause irreversible side effects (such as changing global variables), expecting to be able to finish, before discovering that it can't.



[18] How do you find this out in the first place? Using M-x apropos RET time RET, of course.

[19] Emacs 20.1, which was not yet released when this book went to press, will introduce a major new system for editing user options called "customize." Hooking user options into the "customize" system requires using special functions called defgroup and defcustom.

Get Writing GNU Emacs Extensions now with the O’Reilly learning platform.

O’Reilly members experience books, live events, courses curated by job role, and more from O’Reilly and nearly 200 top publishers.