defcustom 定义变量 ¶你可以使用 defcustom 定义变量,方便自己和他人通过 Emacs 的 customize 功能设置其值。(你不能使用 customize 编写函数定义,但可以在 .emacs 文件中编写 defun;事实上,你可以在 .emacs 中编写任意 Lisp 表达式。)
customize 功能依赖 defcustom 宏。虽然你可以使用 defvar 或 setq 定义用户可设置的变量,但 defcustom 宏是为此专门设计的。
你可以沿用编写 defvar 的经验来编写 defcustom 的前三个参数。defcustom 的第一个参数是变量名,第二个参数是变量初始值(若有),且仅在变量未被设置时生效,第三个参数是文档说明。
defcustom 的第四个及后续参数用于指定类型和选项,这些是 defvar 不具备的。(这些参数为可选。)
每个参数均由关键字和对应值组成,关键字以冒号 ‘:’ 开头。
例如,可自定义的用户选项变量 text-mode-hook 定义如下:
(defcustom text-mode-hook nil "进入文本模式及诸多相关模式时运行的标准钩子。" :type 'hook :options '(turn-on-auto-fill flyspell-mode) :group 'wp)
变量名为 text-mode-hook,无默认值,文档字符串说明了其用途。
:type 关键字告诉 Emacs 该变量应设置为何种类型的数据,以及如何在自定义缓冲区中显示该值。
:options 关键字指定变量的推荐值列表,通常用于钩子变量。该列表仅为建议而非强制限制,用户可将变量设为其他值;:options 后的列表旨在为用户提供便捷选项。
最后,:group 关键字告诉 Emacs 自定义命令该变量所属的组,方便查找定位。
defcustom 宏支持十多个关键字,更多信息可参考 编写自定义定义 in GNU Emacs Lisp 参考手册。
以 text-mode-hook 为例。
自定义该变量有两种方式:使用自定义命令,或手动编写对应表达式。
使用自定义命令时,输入:
M-x customize
找到文本编辑相关的组名为“Text”。进入该组后,Text Mode Hook 是第一个选项。你可以点击各个选项(如 turn-on-auto-fill)设置值。点击按钮:
Save for Future Sessions
后,Emacs 会向你的 .emacs 文件写入表达式,形式如下:
(custom-set-variables ;; custom-set-variables 由 Customize 自动添加。 ;; 手动编辑可能导致出错,请注意。 ;; 初始化文件应只包含一个该实例。 ;; 多个实例会导致功能异常。 '(text-mode-hook '(turn-on-auto-fill text-mode-hook-identify)))
(text-mode-hook-identify 函数用于告知 toggle-text-mode-auto-fill 哪些缓冲区处于文本模式,会自动启用。)
custom-set-variables 函数的工作方式与 setq 略有不同。我虽未深究差异,但会手动修改 .emacs 中的 custom-set-variables 表达式,以自认为合理的方式调整,从未出现问题。其他用户更倾向于使用自定义命令,让 Emacs 自动完成配置。
另一个 custom-set-… 系列函数是 custom-set-faces,用于设置各类文本的视觉样式。我长期以来设置了大量样式,有时会通过 customize 重新设置,有时则直接编辑 .emacs 中的 custom-set-faces 表达式。
第二种自定义 text-mode-hook 的方式是在 .emacs 文件中手动编写与 custom-set-… 函数无关的代码。
这样设置后,后续使用 customize 时会看到提示信息:
CHANGED outside Customize; operating on it here may be unreliable.
该信息仅为警告。点击
Save for Future Sessions
按钮后,Emacs 会在 .emacs 文件末尾附近写入 custom-set-… 表达式,该表达式会在你手写的表达式之后求值,从而覆盖手写配置,不会造成损坏。但这样做时需记住哪个表达式生效,否则可能造成混淆。
只要记住值的设置位置,就不会出现问题。无论如何,所有配置值最终都保存在初始化文件中,通常为 .emacs。
我个人几乎不使用 customize,大部分配置都是手动编写表达式。
顺带一提,更完整的定义类宏包括:defsubst 用于定义内联函数,语法与 defun 一致;defconst 用于将符号定义为常量,设计意图是程序和用户都不应修改其值。(你 technically 可以修改,因为它本质仍是变量,但建议不要这样做。)