24.2.4 定义派生模式

定义新主模式的推荐方式是使用 define-derived-mode 从已有模式进行派生。若没有密切相关的模式,应继承自 text-modespecial-modeprog-mode 之一。See 基础主模式。若这些均不适用,则可继承自 fundamental-mode(see 主模式)。

Macro: define-derived-mode variant parent name docstring keyword-args… body…

该宏将 variant 定义为主模式命令,使用 name 作为该模式名称的字符串形式。variantparent 应为不带引号的符号。

新定义的命令 variant 会先调用函数 parent,随后覆盖父模式的部分特性:

  • 新模式拥有独立的稀疏按键映射表,名称为 variant-mapdefine-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 拥有非 nilmode-class 符号属性,define-derived-mode 会将 variantmode-class 属性设为相同值。例如,这可保证若父模式为特殊模式,则派生模式同样为特殊模式(see 主模式编码规范)。

也可为 parent 指定 nil,使新模式无父模式。此时 define-derived-mode 仍按上述规则执行,但会省略所有与父模式相关的操作。 反之,可使用下文介绍的 derived-mode-set-parentderived-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 会自动完成该设置。

Function: derived-mode-p modes

若当前主模式继承自符号列表 modes 中的任意一个主模式,该函数返回非 nilmodes 也可直接传入单个模式符号,而非列表。

此外,本函数仍支持已废弃的调用方式:将 modes 以多个独立参数形式传入。

在检查当前主模式的父模式时,该函数会考虑由 define-derived-mode 设置的父模式,以及由下文介绍的 derived-mode-add-parents 添加的额外父模式。

Function: provided-mode-derived-p mode modes

若模式 mode 继承自符号列表 modes 中的任意一个主模式,该函数返回非 nil。 与 derived-mode-p 相同,modes 可传入单个符号,且同样支持已废弃的多参数调用方式。

在检查 mode 的父模式时,该函数会考虑由 define-derived-mode 设置的父模式,以及由下文介绍的 derived-mode-add-parents 添加的额外父模式。

主模式的继承关系图谱可通过以下底层函数访问与修改:

Function: derived-mode-set-parent mode parent

该函数声明模式 mode 继承自 parentdefine-derived-mode 在定义完 mode 后会调用此函数,以登记 mode 基于 parent 派生的关系。

Function: derived-mode-add-parents mode extra-parents

该函数允许在定义 mode 时使用的父模式之外,注册额外的父模式。当 modeextra-parents 中的模式存在相似性,且需要在目录局部变量、模式专属配置等场景中将 mode 视为这些模式的子模式时,可使用该函数。额外父模式以符号列表形式在 extra-parents 中指定。 derived-mode-pprovided-mode-derived-p 会将这些额外父模式视为 mode 的父模式之一。

Function: derived-mode-all-parents mode

该函数返回 mode 所有继承关系中的模式列表,按从最具体到最通用排序,并以 mode 自身开头。列表包含通过 derived-mode-add-parents 添加的额外父模式(若有)。


emacs

Emacs

org-mode

Orgmode

Donations

打赏

Copyright

© Jasper Hsu

Creative Commons

Creative Commons

Attribute

Attribute

Noncommercial

Noncommercial

Share Alike

Share Alike