每个主模式的代码都应当遵循一系列编码规范,包括局部键盘映射、语法表初始化、函数与变量命名以及钩子相关规范。
如果你使用 define-derived-mode 宏,它会自动处理其中大部分规范。See 定义派生模式。同时注意,基本模式是很多规范的例外,因为它代表 Emacs 的默认状态。
下面列出的规范仅为部分内容。每个主模式都应尽量与其他 Emacs 主模式保持整体一致,从而让 Emacs 整体更加协调。这里无法列出所有可能涉及一致性的细节;如果 Emacs 开发者指出你的主模式在某方面不符合通用规范,请进行兼容修改。
文档字符串中可以包含特殊文档子串 ‘\[command]’, ‘\{keymap}’ 和 ‘\<keymap>’,使帮助显示能自动适应用户自定义的按键绑定。See 文档中的按键绑定替换。
kill-all-local-variables。该函数会运行标准钩子 change-major-mode-hook,然后清除此前生效主模式的缓冲区局部变量。See 创建与删除缓冲区局部绑定。
major-mode 设置为该主模式命令对应的符号。describe-mode 依靠该值确定需要显示的文档。
mode-name 设置为模式的 “友好(pretty)” 名称,通常为字符串(其他形式参见 模式行的数据结构)。模式名称会显示在模式行中。
indent-line-function 设置为合适的函数,并可能需要定制其他缩进相关变量。See 代码自动缩进。
use-local-map 安装该局部映射。更多信息,See 活跃按键映射表。
该键盘映射应永久保存在名为 modename-mode-map 的全局变量中。通常由定义该模式的库完成变量设置。
关于编写模式键盘映射变量的代码建议,See 稳健定义变量的技巧。
主模式也可以重新绑定 M-n、M-p 和 M-s。M-n 与 M-p 的绑定通常应实现某种向前/向后移动功能,但不一定是光标移动。
如果主模式中某个命令能更适配当前文本并完成相同功能,重新绑定标准按键序列是合理的。例如,某编程语言编辑主模式可以重新定义 C-M-a,使其按该语言语法更好地跳转到函数开头。为适配主模式需求定制 C-M-a,推荐方式是设置 beginning-of-defun-function(see Moving over Balanced Expressions)调用模式专用函数。
如果某个标准按键的默认含义在该模式下基本无用,主模式重新绑定它也是合理的。例如小缓冲区模式会重新绑定 M-r,其默认功能在小缓冲区中几乎无用。Dired、Rmail 这类不允许文本自插入的主模式,可以合理地将字母与其他可打印字符重新定义为专用命令。
modename-mode-syntax-table 的变量中。See Syntax Tables。
modename-mode-abbrev-table 的变量中。如果主模式命令自身定义了缩写,应在调用 define-abbrev 时为 system-flag 参数传入 t。See Defining Abbrevs。
font-lock-defaults 设置缓冲区局部值。See Font Lock Mode。
context-menu-mode 时使用(see Menu Mouse Clicks in The Emacs Manual)。为此需要定义一个模式专用函数,根据缓冲区中 mouse-3 点击位置构建一个或多个菜单,并将该函数添加到 context-menu-functions 的缓冲区局部值中。
imenu-generic-expression、或 imenu-prev-index-position-function 与 imenu-extract-index-name-function 这两个变量、或 imenu-create-index-function 设置缓冲区局部值。See Imenu。
outline-regexp 或 outline-search-function 以及 outline-level 设置缓冲区局部值。See 大纲次要模式。
eldoc-documentation-functions 添加一个或多个缓冲区局部条目。
completion-at-point-functions 添加缓冲区局部条目,指定各类关键字的补全方式。See 普通缓冲区中的补全。
make-local-variable,而非 make-variable-buffer-local。后者会使该变量在之后所有设置过它的缓冲区中均为局部,会影响不使用该模式的缓冲区。模式不应当产生此类全局影响。See 缓冲区局部变量。
除极少数例外,Lisp 包中使用 make-variable-buffer-local 的合理场景,仅限仅在该包内部使用的变量。若用于其他包也会使用的变量,会造成相互干扰。
modename-mode-hook 的标准模式钩子(mode hook)。主模式命令的**最后一步**必须调用 run-mode-hooks。该函数会依次运行标准钩子 change-major-mode-after-body-hook、模式钩子、函数 hack-local-variables(缓冲区访问文件时),然后运行标准钩子 after-change-major-mode-hook。See 模式钩子。
define-derived-mode 宏定义,但并非强制要求。此类模式应在 delay-mode-hooks 表达式内部调用父模式命令(使用 define-derived-mode 会自动完成这一点)。See 定义派生模式 和 模式钩子。
change-major-mode-hook 设置缓冲区局部值。See 创建与删除缓冲区局部绑定。
mode-class、值为 special 的属性,示例如下:
(put 'funny-mode 'mode-class 'special)
这会告知 Emacs:即使 major-mode 默认值为 nil,在当前缓冲区为 Funny 模式时新建的缓冲区也不会继承该模式。默认情况下 major-mode 为 nil 时新建缓冲区会沿用当前缓冲区主模式(see Emacs 如何选择主模式),但此类special 模式会改用基本模式。Dired、Rmail、缓冲区列表等模式均使用该特性。
view-buffer 函数不会在 mode-class 为 special 的缓冲区中启用查看模式,因为这类模式通常自带类似查看模式的绑定。
如果父模式为 special 模式,define-derived-mode 宏会自动将派生模式标记为 special。特殊模式(Special mode)是此类模式方便继承的父模式;See 基础主模式。
auto-mode-alist 添加条目,为对应文件名指定该模式(see Emacs 如何选择主模式)。如果将模式命令定义为自动加载,应在调用 autoload 的同一文件中添加该条目。如果为模式命令使用了自动加载标记,也可以为添加该条目的代码使用自动加载标记(see autoload cookie)。如果不使用自动加载,在包含模式定义的文件中添加条目即可。
defvar 或 defcustom 设置模式相关变量,避免变量已有值时被重复初始化。See 定义全局变量。