与主模式一样,编写次要模式也有相应规范(see 主模式)。这些规范将在下面说明。遵循它们最简单的方式是使用宏 define-minor-mode。See 定义次要模式。
nil,开启时为非 nil。如果该次要模式是缓冲区局部的,该变量也应当是缓冲区局部的。
该变量与 minor-mode-alist 配合使用,用于在模式行上显示次要模式名称。它还通过 minor-mode-map-alist 决定次要模式的按键映射是否生效(see 控制活跃按键映射表)。各个命令或钩子也可以检查它的值。
模式命令应接受一个可选参数。如果交互式调用且不带前缀参数,它应当切换模式状态(即关闭则开启,开启则关闭)。如果交互式调用并带有前缀参数,参数为正则开启模式,否则关闭。
如果模式命令从 Lisp 中调用(即非交互式),参数省略或为 nil 时应开启模式;参数为符号 toggle 时切换模式;其他情况则按照上述带数值前缀参数的交互式调用方式处理。
下面的示例展示了如何实现这种行为(与 define-minor-mode 宏生成的代码类似):
(interactive (list (or current-prefix-arg 'toggle)))
(let ((enable
(if (eq arg 'toggle)
(not foo-mode) ; this is the mode’s mode variable
(> (prefix-numeric-value arg) 0))))
(if enable
do-enable
do-disable))
这种略显复杂的行为设计,是为了方便用户交互式切换次要模式,同时也便于在模式钩子中直接启用次要模式,例如:
(add-hook 'text-mode-hook 'foo-mode)
无论 foo-mode 是否已经启用,这样写都能正确生效,因为从 Lisp 无参调用 foo-mode 命令时会无条件启用该次要模式。在模式钩子中禁用次要模式的写法会稍显繁琐:
(add-hook 'text-mode-hook (lambda () (foo-mode -1)))
不过这种用法并不常见。
连续两次启用或禁用同一个次要模式不应出错,且效果应与执行一次相同。换句话说,次要模式命令应当是幂等的。
minor-mode-alist 中添加一项(see Definition of minor-mode-alist)。该项应为如下形式的列表:
(mode-variable string)
其中 mode-variable 是控制次要模式启用的变量,string 是以空格开头的短字符串,用于在模式行上表示该模式。这些字符串必须简短,以便同时显示多个。
向 minor-mode-alist 添加项时,应使用 assq 检查是否已存在,避免重复。例如:
(unless (assq 'leif-mode minor-mode-alist) (push '(leif-mode " Leif") minor-mode-alist))
或者使用 add-to-list(see 修改列表变量):
(add-to-list 'minor-mode-alist '(leif-mode " Leif"))
此外,部分主模式规范(see 主模式编码规范)同样适用于次要模式:包括全局符号命名规范、初始化函数末尾使用钩子,以及按键映射和各类表的使用规范。
次要模式应尽可能支持通过自定义系统启用和关闭(see 自定义设置)。为此,模式变量应使用 defcustom 定义,通常指定 :type 'boolean。如果仅设置变量不足以启用模式,还应指定 :set 方法,通过调用模式命令来启用模式。在变量的文档字符串中说明:若非通过自定义系统设置该变量,可能不会生效。同时,使用自动加载标记标记该定义(see autoload cookie),并指定 :require,以便自定义该变量时会加载定义该模式的库。示例:
;;;###autoload (defcustom msb-mode nil "Toggle msb-mode. Setting this variable directly does not take effect; use either \\[customize] or the function `msb-mode'." :set 'custom-set-minor-mode :initialize 'custom-initialize-default :version "20.4" :type 'boolean :group 'msb :require 'msb)