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.

View in manual

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)))))))