有时定义一个充当「通用调度器」的命令会很有用,
它能够根据用户需求调用一组命令中的某一个。
例如,你可能想定义一个名为 ‘open’ 的命令,
用于「打开」并显示多种不同类型的对象。
或者你可以有一个名为 ‘mua’(邮件用户代理 Mail User Agent 的缩写)的命令,
它可以通过多种邮件后端(如 Rmail、Gnus 或 MH-E)读取和发送邮件。
宏 define-alternatives 可用于定义此类 通用命令(generic commands)。
通用命令是一种交互式函数,其具体实现可根据用户偏好从多个备选方案中选择。
该宏定义新的通用命令 command,该命令可拥有多个备选实现。 参数 command 应为未加引号的符号。
调用该宏时,会创建一个交互式 Lisp 闭包(see 闭包)。
当用户首次运行 M-x command RET 时,
Emacs 会要求用户从 command 的多个备选实现中选择一个,
并为这些备选方案的名称提供补全功能。
这些名称来自宏创建的用户选项 command-alternatives(如果该选项不存在)。
为保证可用性,该变量的值应为一个关联列表(alist),
其元素格式为 (alt-name . alt-func),
其中 alt-name 是备选方案的名称,
alt-func 是选中该备选方案时要调用的交互式函数。
当用户选择某个备选方案后,Emacs 会记住该选择;
此后用户再次调用 M-x command 时,
会自动调用该选中的备选方案,无需再次提示。
若要选择不同的备选方案,可键入 C-u M-x command RET——
此时 Emacs 会再次提示选择备选方案,且新选择会覆盖之前的设置。
变量 command-alternatives 可在调用 define-alternatives 之前创建并设置合适的值;
若未提前创建,该宏会创建值为 nil 的该变量,
之后需填充描述备选方案的关联项。
希望为已有通用命令提供自定义实现的包,
可使用 autoload 标记(see 自动加载)向该关联列表中添加内容,例如:
;;;###autoload (push '("My name" . my-foo-symbol) foo-alternatives
若可选参数 customizations 非 nil,
则应由交替出现的 defcustom 关键字(通常为 :group 和 :version)
以及要添加到 defcustom command-alternatives 定义中的值组成。
以下是一个简单的通用调度器命令示例,
命令名为 open,包含 3 个备选实现:
(define-alternatives open :group 'files :version "42.1")
(setq open-alternatives
'(("file" . find-file)
("directory" . dired)
("hexl" . hexl-find-file)))