Function: define-alternatives

define-alternatives is a macro defined in simple.el.gz.

Signature

(define-alternatives COMMAND &rest CUSTOMIZATIONS)

Documentation

Define the new command COMMAND.

The argument COMMAND should be a symbol.

Running M-x (execute-extended-command) COMMAND RET for the first time prompts for which alternative to use and records the selected command as a custom variable.

Running C-u (universal-argument) M-x (execute-extended-command) COMMAND RET prompts again for an alternative and overwrites the previous choice.

The variable COMMAND-alternatives contains an alist with alternative implementations of COMMAND. define-alternatives does not have any effect until this variable is set.

CUSTOMIZATIONS, if non-nil, should be composed of alternating defcustom keywords and values to add to the declaration of COMMAND-alternatives (typically :group and :version).

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' is used to create generic commands.
;; Generic commands are these (like web, mail, news, encrypt, irc, etc.)
;; that can have different alternative implementations where choosing
;; among them is exclusively a matter of user preference.

;; (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 the new command `COMMAND'.

The argument `COMMAND' should be a symbol.

Running `\\[execute-extended-command] COMMAND RET' for \
the first time prompts for which
alternative to use and records the selected command as a custom
variable.

Running `\\[universal-argument] \\[execute-extended-command] COMMAND RET' \
prompts again for an alternative
and overwrites the previous choice.

The variable `COMMAND-alternatives' contains an alist with
alternative implementations of COMMAND.  `define-alternatives'
does not have any effect until this variable is set.

CUSTOMIZATIONS, if non-nil, should be composed of alternating
`defcustom' keywords and values to add to the declaration of
`COMMAND-alternatives' (typically :group and :version)."
  (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)))))))