22.2.5 Select among Command Alternatives

Sometimes it is useful to define a command that serves as a “generic dispatcher” capable of invoking one of a set of commands according to the user’s needs. For example, imagine that you want to define a command named ‘open’ that can “open” and display several different types of objects. Or you could have a command named ‘mua’ (which stands for Mail User Agent) that can read and send email using one of several email backends, such as Rmail, Gnus, or MH-E. The macro define-alternatives can be used to define such generic commands. A generic command is an interactive function whose implementation can be selected from several alternatives, as a matter of user preference.

Macro: define-alternatives command &rest customizations

This macro defines the new generic command, which can have several alternative implementations. The argument command should be an unquoted symbol.

When invoked, the macro creates an interactive Lisp closure (see Closures). When the user runs M-x command RET for the first time, Emacs asks to select one of the alternative implementations of command, offering completion for the names of these alternatives. These names come from the user option whose name is command-alternatives, which the macro creates (if it didn’t exist before). To be useful, this variable’s value should be an alist whose elements have the form (alt-name . alt-func), where alt-name is the name of the alternative and alt-func is the interactive function to be called if this alternative is selected. When the user selects an alternative, Emacs remembers the selection, and will thereafter automatically call that selected alternative without prompting when the user invokes M-x command again. To choose a different alternative, type C-u M-x command RET–then Emacs will again prompt for one of the alternatives, and the selection will override the previous one.

The variable command-alternatives can be created before calling define-alternatives, with the appropriate values; otherwise the macro creates the variable with a nil value, and it should then be populated with the associations describing the alternatives. Packages that wish to provide their own implementation of an existing generic command can use autoload cookies (see Autoload) to add to the alist, for example:

;;;###autoload (push '("My name" . my-foo-symbol) foo-alternatives

If the optional argument customizations is non-nil, it should consist of alternating defcustom keywords (typically :group and :version) and values to add to the definition of the defcustom command-alternatives.

Here is an example of a simple generic dispatcher command named open with 3 alternative implementations:

(define-alternatives open
  :group 'files
  :version "42.1")
(setq open-alternatives
      '(("file" . find-file)
	("directory" . dired)
	("hexl" . hexl-find-file)))