定义新主模式的推荐方式是使用 define-derived-mode 从已有模式进行派生。若没有密切相关的模式,应继承自 text-mode、special-mode 或 prog-mode 之一。See 基础主模式。若这些均不适用,则可继承自 fundamental-mode(see 主模式)。
该宏将 variant 定义为主模式命令,使用 name 作为该模式名称的字符串形式。variant 与 parent 应为不带引号的符号。
新定义的命令 variant 会先调用函数 parent,随后覆盖父模式的部分特性:
variant-map。define-derived-mode 会将父模式的按键映射设为新映射表的父映射,除非 variant-map 已被设置且已存在父映射。
variant-syntax-table 中,除非使用 :syntax-table 关键字另行指定(见下文)。define-derived-mode 会将父模式的语法表设为 variant-syntax-table 的父语法表,除非后者已被设置且其父表并非标准语法表。
variant-abbrev-table 中,除非使用 :abbrev-table 关键字另行指定(见下文)。
variant-hook。它会在执行完所有祖先模式的钩子后,通过 run-mode-hooks 运行该钩子,作为最后一步操作,之后再执行可能存在的 :after-hook 代码。See 模式钩子。
此外,可通过 body 指定覆盖父模式 parent 的其他特性。命令 variant 会在完成所有常规覆盖设置后、运行模式钩子之前,执行 body 中的表达式。
若父模式 parent 拥有非 nil 的 mode-class 符号属性,define-derived-mode 会将 variant 的 mode-class 属性设为相同值。例如,这可保证若父模式为特殊模式,则派生模式同样为特殊模式(see 主模式编码规范)。
也可为 parent 指定 nil,使新模式无父模式。此时 define-derived-mode 仍按上述规则执行,但会省略所有与父模式相关的操作。
反之,可使用下文介绍的 derived-mode-set-parent 与 derived-mode-add-parents 显式设置新模式的继承关系。
参数 docstring 为新模式指定文档字符串。define-derived-mode 会在该文档末尾自动添加关于模式钩子与按键映射的通用信息。若省略 docstring,则由 define-derived-mode 自动生成文档。
keyword-args 为关键字与值组成的键值对。除 :after-hook 外,其余关键字对应的值均会被求值。当前支持的关键字如下:
:syntax-table用于为新模式显式指定语法表。若指定值为 nil,新模式将使用与父模式 parent 相同的语法表;若父模式为 nil,则使用标准语法表。(注意:此处不遵循非关键字参数的惯例,nil 值不等同于不指定该参数。)
:abbrev-table用于为新模式显式指定缩写表。若指定值为 nil,新模式将使用与父模式 parent 相同的缩写表;若父模式为 nil,则使用 fundamental-mode-abbrev-table。(同样,nil 值 不等同于不指定该关键字。)
:interactive模式默认均为交互式命令。若指定值为 nil,此处定义的模式将不具备交互性。该设置适用于无需用户手动激活、仅用于特定格式缓冲区的模式。
:group若指定该关键字,其值应为该模式对应的自定义组。(并非所有主模式都拥有自定义组。)命令 customize-mode 会使用该设置。define-derived-mode 并不会自动创建指定的自定义组。
:after-hook该可选关键字指定一个单独的 Lisp 表达式,作为模式函数的最后一步操作,在模式钩子运行完成后执行。该表达式无需加引号。由于该表达式可能在模式函数结束后才被求值,因此不应访问模式函数的任何局部状态。:after-hook 常用于设置依赖于用户配置的模式特性,而这些配置可能在模式钩子中被修改。
以下为一个示例:
(defvar-keymap hypertext-mode-map "<down-mouse-3>" #'do-hyper-link) (define-derived-mode hypertext-mode text-mode "Hypertext" "Major mode for hypertext." (setq-local case-fold-search nil))
无需在定义中书写 interactive 声明;define-derived-mode 会自动完成该设置。
若当前主模式继承自符号列表 modes 中的任意一个主模式,该函数返回非 nil。
modes 也可直接传入单个模式符号,而非列表。
此外,本函数仍支持已废弃的调用方式:将 modes 以多个独立参数形式传入。
在检查当前主模式的父模式时,该函数会考虑由 define-derived-mode 设置的父模式,以及由下文介绍的 derived-mode-add-parents 添加的额外父模式。
若模式 mode 继承自符号列表 modes 中的任意一个主模式,该函数返回非 nil。
与 derived-mode-p 相同,modes 可传入单个符号,且同样支持已废弃的多参数调用方式。
在检查 mode 的父模式时,该函数会考虑由 define-derived-mode 设置的父模式,以及由下文介绍的 derived-mode-add-parents 添加的额外父模式。
主模式的继承关系图谱可通过以下底层函数访问与修改:
该函数声明模式 mode 继承自 parent。
define-derived-mode 在定义完 mode 后会调用此函数,以登记 mode 基于 parent 派生的关系。
该函数允许在定义 mode 时使用的父模式之外,注册额外的父模式。当 mode 与 extra-parents 中的模式存在相似性,且需要在目录局部变量、模式专属配置等场景中将 mode 视为这些模式的子模式时,可使用该函数。额外父模式以符号列表形式在 extra-parents 中指定。
derived-mode-p 与 provided-mode-derived-p 会将这些额外父模式视为 mode 的父模式之一。
该函数返回 mode 所有继承关系中的模式列表,按从最具体到最通用排序,并以 mode 自身开头。列表包含通过 derived-mode-add-parents 添加的额外父模式(若有)。