可自定义变量(Customizable variables)(也称为 用户选项(user options))是可以通过自定义界面设置值的全局 Lisp 变量。与使用 defvar 定义的普通全局变量不同(see 定义全局变量),可自定义变量使用 defcustom 宏定义。除了内部会调用 defvar 之外,defcustom 还会声明该变量在自定义界面中如何显示、允许取哪些值等信息。
该宏将 option 声明为用户选项(即可自定义变量)。不要给 option 加引号。
参数 standard 是一个表达式,用于指定 option 的标准默认值。执行 defcustom 时会对 standard 求值,但不一定会立即将选项绑定为该值:
如果 option 已有默认值,则保持不变;
如果用户已保存过该选项的自定义设置,则以用户自定义值作为默认值;
否则,将 standard 求值后的结果作为默认值。
与 defvar 类似,该宏会将 option 标记为特殊变量,表示它始终使用动态绑定。如果 option 已处于词法绑定中,该词法绑定会持续到绑定结构结束为止。See Scoping 变量绑定的作用域规则。
standard 表达式还可能在其他时刻被求值 — 只要自定义系统需要知道 option 的标准默认值就会执行。因此请确保使用一个随时重复求值都不会产生副作用的表达式。
参数 doc 为该变量指定文档字符串。
如果某个 defcustom 未指定 :group,则会使用同一文件中最后一个用 defgroup 定义的组。这样一来,大多数 defcustom 都不需要显式写明 :group。
在 Emacs Lisp 模式下,当你使用快捷键 C-M-x(即 eval-defun)对一个 defcustom 形式进行求值时,eval-defun 的一项特殊机制会无条件地设置该变量,而不会检查变量的值是否为空。(该机制同样适用于 defvar,see 定义全局变量。)对已定义过的 defcustom 使用 eval-defun,如果存在 :set 函数(见下文),则会调用该函数。
如果你将 defcustom 写在 Emacs 预加载的 Elisp 文件中(see Building Emacs),在转储(dump)阶段设置的标准值可能不正确 —— 例如,因为它所依赖的其他变量尚未被赋予正确的值。这种情况下,可以使用下文介绍的 custom-reevaluate-setting,在 Emacs 启动完成后重新计算标准值。
除了 通用项关键字 中列出的通用关键字外,本宏还支持以下关键字:
:type type将 type 作为该选项的数据类型。它规定了哪些值是合法的,以及如何显示该值(see 定制类型)。每个 defcustom 都应当为此关键字指定一个值。
:options value-list ¶指定该选项常用的合理值列表。用户并不受限于只能使用这些值,但这些值会作为便捷选项提供给用户。
该关键字仅对部分类型有效,目前包括 hook、plist 和 alist。有关如何使用 :options 的说明,请查看对应类型的定义。
使用不同的 :options 值重新求值 defcustom 形式时,不会清除之前求值所添加的值,也不会清除通过 custom-add-frequent-value(见下文)添加的值。
:set setfunction ¶指定 setfunction 作为在使用 Customize 界面时修改此选项值的方式。函数
setfunction 应接收两个参数:一个符号(选项名称)和新值,并且需要执行
为该选项正确更新值所需的所有操作(这未必意味着简单地将该选项设为 Lisp 变量);
不过,最好不要以破坏性方式修改其值参数。setfunction 的默认值为
set-default-toplevel-value。
若 setfunction 已定义,那么在 Emacs Lisp 模式下使用 C-M-x 求值
defcustom 形式时,以及通过 setopt 宏修改 option 的值时
(see setopt),该函数也会被调用。
如果指定了此关键字,该变量的文档字符串应说明如何在手写的 Lisp 代码中完成相同
操作——既可直接调用 setfunction,也可使用 setopt。
:get getfunction ¶指定 getfunction 作为提取此选项值的方式。函数 getfunction 应接收
一个参数(一个符号),并返回 Custom 应当用作该符号当前值的内容(该内容未必是
该符号的 Lisp 值)。其默认值为 default-toplevel-value。
要正确使用 :get,你必须真正理解 Custom 的工作机制。它适用于那些在
Custom 中被当作变量处理、但实际上并未存储在 Lisp 变量中的值。如果为一个
确实存储在 Lisp 变量中的值指定 getfunction,几乎可以肯定是错误的。
:initialize function ¶function 应当是一个在 defcustom 被求值时用于初始化变量的函数。它应接收两个参数:选项名称(一个符号)和值。下面是一些供此用途使用的预定义函数:
custom-initialize-set使用该变量的 :set 函数初始化变量,但如果变量已经非空,则不再重新初始化。
custom-initialize-default与 custom-initialize-set 类似,但使用 set-default-toplevel-value来设置变量,而非该变量自身的 :set 函数。这通常是那些 :set 函数用于启用或禁用次要模式(minor mode)的变量的常用选择;使用此选项时,定义变量不会调用次要模式函数,但通过 Customize 定制变量时会调用。
custom-initialize-reset始终使用 :set 函数初始化变量。如果变量已经非空,则通过 :get 方法获取当前值,再调用 :set 函数将其重置。这是 :initialize 的默认函数。
custom-initialize-changed如果变量已经被设置或被定制过,则使用 :set 函数初始化变量;否则,直接使用 set-default-toplevel-value。
custom-initialize-delay行为与 custom-initialize-set 类似,但会将实际初始化延迟到下一次 Emacs 启动时。此函数应在预加载的文件中(或用于自动加载的变量)使用,以便初始化在运行时上下文而非构建时上下文中完成。它还有一个副作用:延迟后的初始化会通过 :set 函数执行。See Building Emacs。
:local value ¶若 value 为 t,则将 option 标记为自动缓冲区局部变量;若值为 permanent,则同时将 option 的 permanent-local 属性设为 t。See 创建与删除缓冲区局部绑定。
:risky value ¶将该变量的 risky-local-variable 属性设为 value。See 文件局部变量。
:safe function ¶将该变量的 safe-local-variable 属性设为 function。See 文件局部变量。
:set-after variables ¶在根据保存的定制设置变量时,确保先设置 variables 列出的变量,再设置本变量;即,延迟设置本变量,直到其他变量处理完毕。如果本变量必须依赖其他变量已设置为预期值才能正常工作,可使用 :set-after。
为用于开启某项功能的选项指定 :require 关键字会很有用。这会使得每当该选项被设置时,若对应功能尚未加载,Emacs 就会加载它。See 通用项关键字。示例如下:
(defcustom frobnicate-automatically nil "Non-nil means automatically frobnicate all buffers." :type 'boolean :require 'frobnicate-mode :group 'frobnicate)
若某个定制项的类型(如 hook(钩子)或 alist(关联列表))支持 :options 关键字,则你可以通过调用 custom-add-frequent-value,在 defcustom 声明外部为该类型的取值列表添加额外值。例如,如果你定义了一个函数 my-lisp-mode-initialization,打算从 emacs-lisp-mode-hook 中调用它,你可能希望将该函数添加到 emacs-lisp-mode-hook 的合理取值列表中,但又不想编辑其原始定义。你可以这样做:
(custom-add-frequent-value 'emacs-lisp-mode-hook 'my-lisp-mode-initialization)
针对定制选项 symbol(符号),将 value(值)添加到其合理取值列表中。
添加值的具体效果取决于 symbol 的定制类型。
由于求值 defcustom 形式时不会清除之前添加的值,因此 Lisp 程序可通过该函数,为尚未定义的用户选项添加取值。
在内部实现中,defcustom 会使用以下符号属性:standard-value 用于记录标准值对应的表达式,saved-value 用于记录用户通过定制缓冲区保存的值,customized-value 用于记录用户通过定制缓冲区设置、但未保存的值。See 符号属性。此外,还有 themed-value,用于记录由主题设置的值(see 自定义主题)。这些属性均为列表类型,其首个元素(car)是一个可求值为对应值的表达式。
该函数会重新求 symbol(符号)的标准值 ——symbol 应为通过 defcustom 声明的用户选项。若该变量已被定制过,则此函数会改为重新求其已保存值(saved value)。随后,函数会将该用户选项设置为这个重新求得的值(若选项定义了 :set 属性,则会使用该属性对应的函数完成设置)。
此函数适用于那些「在其值能被正确计算之前就已定义」的可定制选项。例如,Emacs 启动过程中,会对部分在预加载 Emacs Lisp 文件中定义、但初始值依赖仅在运行时可用信息的用户选项,调用该函数。
若 arg 是可定制变量,该函数返回非 nil 值。可定制变量需满足以下任一条件:
拥有 standard-value 或 custom-autoload 属性的变量
(通常意味着该变量由 defcustom 声明);或是另一个可定制变量的别名。