elisp: Using Interactive
20.2.1 Using ‘interactive’
--------------------------
This section describes how to write the ‘interactive’ form that makes a
Lisp function an interactively-callable command, and how to examine a
command’s ‘interactive’ form.
-- Special Form: interactive arg-descriptor
This special form declares that a function is a command, and that
it may therefore be called interactively (via ‘M-x’ or by entering
a key sequence bound to it). The argument ARG-DESCRIPTOR declares
how to compute the arguments to the command when the command is
called interactively.
A command may be called from Lisp programs like any other function,
but then the caller supplies the arguments and ARG-DESCRIPTOR has
no effect.
The ‘interactive’ form must be located at top-level in the function
body, or in the function symbol’s ‘interactive-form’ property
(Symbol Properties). It has its effect because the command
loop looks for it before calling the function (Interactive
Call). Once the function is called, all its body forms are
executed; at this time, if the ‘interactive’ form occurs within the
body, the form simply returns ‘nil’ without even evaluating its
argument.
By convention, you should put the ‘interactive’ form in the
function body, as the first top-level form. If there is an
‘interactive’ form in both the ‘interactive-form’ symbol property
and the function body, the former takes precedence. The
‘interactive-form’ symbol property can be used to add an
interactive form to an existing function, or change how its
arguments are processed interactively, without redefining the
function.
There are three possibilities for the argument ARG-DESCRIPTOR:
• It may be omitted or ‘nil’; then the command is called with no
arguments. This leads quickly to an error if the command requires
one or more arguments.
• It may be a string; its contents are a sequence of elements
separated by newlines, one for each argument(1). Each element
consists of a code character (Interactive Codes) optionally
followed by a prompt (which some code characters use and some
ignore). Here is an example:
(interactive "P\nbFrobnicate buffer: ")
The code letter ‘P’ sets the command’s first argument to the raw
command prefix (Prefix Command Arguments). ‘bFrobnicate
buffer: ’ prompts the user with ‘Frobnicate buffer: ’ to enter the
name of an existing buffer, which becomes the second and final
argument.
The prompt string can use ‘%’ to include previous argument values
(starting with the first argument) in the prompt. This is done
using ‘format-message’ (Formatting Strings). For example,
here is how you could read the name of an existing buffer followed
by a new name to give to that buffer:
(interactive "bBuffer to rename: \nsRename buffer %s to: ")
If ‘*’ appears at the beginning of the string, then an error is
signaled if the buffer is read-only.
If ‘@’ appears at the beginning of the string, and if the key
sequence used to invoke the command includes any mouse events, then
the window associated with the first of those events is selected
before the command is run.
If ‘^’ appears at the beginning of the string, and if the command
was invoked through “shift-translation”, set the mark and activate
the region temporarily, or extend an already active region, before
the command is run. If the command was invoked without
shift-translation, and the region is temporarily active, deactivate
the region before the command is run. Shift-translation is
controlled on the user level by ‘shift-select-mode’; see
(emacs)Shift Selection.
You can use ‘*’, ‘@’, and ‘^’ together; the order does not matter.
Actual reading of arguments is controlled by the rest of the prompt
string (starting with the first character that is not ‘*’, ‘@’, or
‘^’).
• It may be a Lisp expression that is not a string; then it should be
a form that is evaluated to get a list of arguments to pass to the
command. Usually this form will call various functions to read
Minibuffers::) or directly from the keyboard (Reading
Input).
Providing point or the mark as an argument value is also common,
but if you do this _and_ read input (whether using the minibuffer
or not), be sure to get the integer values of point or the mark
after reading. The current buffer may be receiving subprocess
output; if subprocess output arrives while the command is waiting
for input, it could relocate point and the mark.
Here’s an example of what _not_ to do:
(interactive
(list (region-beginning) (region-end)
(read-string "Foo: " nil 'my-history)))
Here’s how to avoid the problem, by examining point and the mark
after reading the keyboard input:
(interactive
(let ((string (read-string "Foo: " nil 'my-history)))
(list (region-beginning) (region-end) string)))
*Warning:* the argument values should not include any data types
that can’t be printed and then read. Some facilities save
‘command-history’ in a file to be read in the subsequent sessions;
if a command’s arguments contain a data type that prints using
‘#<...>’ syntax, those facilities won’t work.
There are, however, a few exceptions: it is ok to use a limited set
of expressions such as ‘(point)’, ‘(mark)’, ‘(region-beginning)’,
and ‘(region-end)’, because Emacs recognizes them specially and
puts the expression (rather than its value) into the command
history. To see whether the expression you wrote is one of these
exceptions, run the command, then examine ‘(car command-history)’.
-- Function: interactive-form function
This function returns the ‘interactive’ form of FUNCTION. If
FUNCTION is an interactively callable function (Interactive
Call), the value is the command’s ‘interactive’ form
‘(interactive SPEC)’, which specifies how to compute its arguments.
Otherwise, the value is ‘nil’. If FUNCTION is a symbol, its
function definition is used.
---------- Footnotes ----------
(1) Some elements actually supply two arguments.