Function: define-alternatives
define-alternatives is a macro defined in simple.el.gz.
Signature
(define-alternatives COMMAND &rest CUSTOMIZATIONS)
Documentation
Define a new generic COMMAND which can have several implementations.
The argument COMMAND should be an unquoted symbol.
Running M-x (execute-extended-command) COMMAND RET for the first time prompts for the
alternative implementation to use and records the selected alternative.
Thereafter, M-x (execute-extended-command) COMMAND RET will automatically invoke the recorded selection.
Running C-u (universal-argument) M-x (execute-extended-command) COMMAND RET again prompts for an alternative
and overwrites the previous selection.
The macro creates a defcustom named COMMAND-alternatives.
CUSTOMIZATIONS, if non-nil, should be pairs of defcustom
keywords and values to add to the definition of that defcustom;
typically, these keywords will be :group and :version with the
appropriate values.
To be useful, the value of COMMAND-alternatives should be an
alist describing the alternative implementations of COMMAND.
The elements of this alist should be of the form
(ALTERNATIVE-NAME . FUNCTION)
where ALTERNATIVE-NAME is the name of the alternative to be shown
to the user as a selectable alternative, and FUNCTION is the
interactive function to call which implements that alternative.
The variable could be populated with associations describing the
alternatives either before or after invoking define-alternatives;
if the variable is not defined when define-alternatives is invoked,
the macro will create it with a nil value, and your Lisp program
should then populate it.
Probably introduced at or before Emacs version 24.4.
Source Code
;; Defined in /usr/src/emacs/lisp/simple.el.gz
;;; Generic dispatcher commands
;; Macro `define-alternatives' can be used to create generic commands.
;; Generic commands are commands that can have different alternative
;; implementations, and choosing among them is the matter of user
;; preference in each case. For example, you could have a generic
;; command `open' capable of "opening" a text file, a URL, a
;; directory, or a binary file, and each of these alternatives would
;; invoke a different Emacs function.
;; (define-alternatives COMMAND) creates a new interactive command
;; M-x COMMAND and a customizable variable COMMAND-alternatives.
;; Typically, the user will not need to customize this variable; packages
;; wanting to add alternative implementations should use
;;
;; ;;;###autoload (push '("My impl name" . my-impl-symbol) COMMAND-alternatives
(defmacro define-alternatives (command &rest customizations)
"Define a new generic COMMAND which can have several implementations.
The argument `COMMAND' should be an unquoted symbol.
Running `\\[execute-extended-command] COMMAND RET' for \
the first time prompts for the
alternative implementation to use and records the selected alternative.
Thereafter, `\\[execute-extended-command] COMMAND RET' will \
automatically invoke the recorded selection.
Running `\\[universal-argument] \\[execute-extended-command] COMMAND RET' \
again prompts for an alternative
and overwrites the previous selection.
The macro creates a `defcustom' named `COMMAND-alternatives'.
CUSTOMIZATIONS, if non-nil, should be pairs of `defcustom'
keywords and values to add to the definition of that `defcustom';
typically, these keywords will be :group and :version with the
appropriate values.
To be useful, the value of `COMMAND-alternatives' should be an
alist describing the alternative implementations of COMMAND.
The elements of this alist should be of the form
(ALTERNATIVE-NAME . FUNCTION)
where ALTERNATIVE-NAME is the name of the alternative to be shown
to the user as a selectable alternative, and FUNCTION is the
interactive function to call which implements that alternative.
The variable could be populated with associations describing the
alternatives either before or after invoking `define-alternatives';
if the variable is not defined when `define-alternatives' is invoked,
the macro will create it with a nil value, and your Lisp program
should then populate it."
(declare (indent defun))
(let* ((command-name (symbol-name command))
(varalt-name (concat command-name "-alternatives"))
(varalt-sym (intern varalt-name))
(varimp-sym (intern (concat command-name "--implementation"))))
`(progn
(defcustom ,varalt-sym nil
,(format "Alist of alternative implementations for the `%s' command.
Each entry must be a pair (ALTNAME . ALTFUN), where:
ALTNAME - The name shown at user to describe the alternative implementation.
ALTFUN - The function called to implement this alternative."
command-name)
:type '(alist :key-type string :value-type function)
,@customizations)
(put ',varalt-sym 'definition-name ',command)
(defvar ,varimp-sym nil "Internal use only.")
(defun ,command (&optional arg)
,(format "Run generic command `%s'.
If used for the first time, or with interactive ARG, ask the user which
implementation to use for `%s'. The variable `%s'
contains the list of implementations currently supported for this command."
command-name command-name varalt-name)
(interactive "P")
(when (or arg (null ,varimp-sym))
(let ((val (completing-read
,(format-message
"Select implementation for command `%s': "
command-name)
,varalt-sym nil t)))
(unless (string-equal val "")
(when (null ,varimp-sym)
(message
"Use `C-u M-x %s RET' to select another implementation"
,command-name)
(sit-for 3))
(customize-save-variable ',varimp-sym
(cdr (assoc-string val ,varalt-sym))))))
(if ,varimp-sym
(call-interactively ,varimp-sym)
(message "%s" ,(format-message
"No implementation selected for command `%s'"
command-name)))))))