24.2.2 Emacs 如何选择主模式

Emacs 在打开文件时,会根据文件名或文件内部信息,自动为缓冲区选择合适的主模式。它同时会处理文件文本中指定的局部变量。

Command: normal-mode &optional find-file

该函数为当前缓冲区设置合适的主模式与缓冲区局部变量绑定。它会调用 set-auto-mode(见下文)。从 Emacs 26.1 开始,该函数不再运行 hack-local-variables,该操作改在主模式初始化阶段的 run-mode-hooks 中执行(see 模式钩子)。

如果 normal-mode 的参数 find-file 非空,则表明该函数由 find-file 调用。此时它会处理文件首行 ‘-*-’ 格式或文件尾部的局部变量。变量 enable-local-variables 控制是否执行该操作。文件局部变量段的语法参见 See Local Variables in Files in The GNU Emacs Manual

如果以交互方式运行 normal-mode,参数 find-file 通常为 nil。此时 normal-mode 会无条件处理所有文件局部变量。

该函数会调用 set-auto-mode 选择并设置主模式。若未匹配到任何模式,缓冲区将保持 major-mode 默认值所指定的主模式(见下文)。

normal-mode 在调用主模式命令时使用 condition-case 捕获异常,并以 ‘文件模式指定错误(File mode specification error)’ 的形式报告原始错误信息。

Function: set-auto-mode &optional keep-mode-if-same

该函数为当前缓冲区选择并设置合适的主模式,决策依据按优先级依次为:文件首行 ‘-*-’ 标记、文件尾部的 ‘mode:’ 局部变量、‘#!’ 解释器行(通过 interpreter-mode-alist)、缓冲区开头文本(通过 magic-mode-alist),最后是所访问的文件名(通过 auto-mode-alist)。See How Major Modes are Chosen in The GNU Emacs Manual。若 enable-local-variablesnil,则 set-auto-mode 不会检查 ‘-*-’ 行与文件尾部的模式标记。

某些文件类型不适合通过扫描内容识别模式。例如 tar 归档文件尾部可能包含带有局部变量段的成员文件,不应将其模式应用于整个归档文件;又如 TIFF 图像文件首行可能恰好形似 ‘-*- 格式。为此,这类文件扩展名均已加入 inhibit-local-variables-regexps 列表。向该列表添加正则表达式可阻止 Emacs 从中搜索任何类型的局部变量(不仅限于模式标记)。

keep-mode-if-same 非空,且缓冲区已处于正确主模式,则该函数不会重复调用模式命令。例如 set-visited-file-name 会将其设为 t,避免清除用户已设置的缓冲区局部变量。

Function: set-buffer-major-mode buffer

该函数将 buffer 的主模式设为 major-mode 的默认值;若默认值为 nil,则使用当前缓冲区的主模式(如适用)。一个例外是:若缓冲区名为 *scratch*,则将模式设为 initial-major-mode

创建缓冲区的底层原语不使用该函数,但 switch-to-bufferfind-file-noselect 等中层命令在创建缓冲区时均会调用。

User Option: initial-major-mode

该变量的值决定初始 *scratch* 缓冲区的主模式,取值应为主模式命令对应的符号,默认值为 lisp-interaction-mode

Variable: interpreter-mode-alist

该变量用于为 ‘#!’ 行指定解释器的脚本文件匹配主模式。其值为关联列表,元素格式为 (regexp . mode),表示若文件解释器匹配 \\`regexp\\', 则使用 mode 模式。例如默认元素 ("python[0-9.]*" . python-mode)

Variable: magic-mode-alist

该变量为关联列表,元素格式为 (regexp . function),其中 regexp 为正则表达式,function 为函数或 nil。打开文件后,若缓冲区开头文本匹配 regexpfunction 非空,则 set-auto-mode 会调用该函数;若 functionnil,则交由 auto-mode-alist 决定模式。

Variable: magic-fallback-mode-alist

用法与 magic-mode-alist 相同,但仅在 auto-mode-alist 未匹配到模式时生效。

Variable: auto-mode-alist

该变量为关联列表,由文件名正则表达式与对应主模式命令组成。通常匹配文件名后缀,如 ‘.el’、‘.c’,但也可匹配其他规则。普通元素格式为 (regexp . mode-function)

示例:

(("\\`/tmp/fol/" . text-mode)
 ("\\.texinfo\\'" . texinfo-mode)
 ("\\.texi\\'" . texinfo-mode)
 ("\\.el\\'" . emacs-lisp-mode)
 ("\\.c\\'" . c-mode)
 ("\\.h\\'" . c-mode)
 ...)

当你打开一个文件时,如果其扩展文件名(see 文件名展开相关函数)在通过 file-name-sans-versions(see 文件名组成部分)去除版本号与备份后缀后,匹配了某个 regexp 正则表达式,set-auto-mode 就会调用对应的 mode-function。该功能让 Emacs 能够为绝大多数文件选择合适的主模式。

如果 auto-mode-alist 中的某个元素格式为 (regexp function t),那么在调用 function 之后,Emacs 会使用文件名中之前未匹配的部分,再次搜索 auto-mode-alist。这一特性对解压缩相关包非常实用:形如 ("\\.gz\\'" function t) 的条目可以先对文件解压,再根据去掉 ‘.gz’ 后的文件名,为解压后的文件设置正确模式。

如果 auto-mode-alist 中有多个元素的 regexp 都能匹配该文件名,Emacs 会使用第一个匹配项。

下面示例展示如何将多组模式规则添加到 auto-mode-alist 头部。(你可以在初始化文件中使用这类表达式。)

(setq auto-mode-alist
  (append
   ;; File name (within directory) starts with a dot.
   '(("/\\.[^/]*\\'" . fundamental-mode)
     ;; File name has no dot.
     ("/[^\\./]*\\'" . fundamental-mode)
     ;; File name ends in ‘.C’.
     ("\\.C\\'" . c++-mode))
   auto-mode-alist))
Variable: major-mode-remap-defaults

该变量是一个关联列表,用于指定激活某个主模式时实际应调用的函数。适用于可被多种主模式支持的文件格式,通过该变量可以指定默认使用的替代模式。

例如,某个第三方包提供了大幅改进的 Pascal 主模式,可以通过下面代码告知 normal-mode,对原本应使用 pascal-mode 的所有文件,改用 spiffy-pascal-mode

(add-to-list 'major-mode-remap-defaults '(pascal-mode . spiffy-pascal-mode))

该变量格式与 major-mode-remap-alist 相同。如果两个列表同时匹配某个主模式,优先使用 major-mode-remap-alist 中的条目。

Function: major-mode-remap mode

该函数根据 major-mode-remap-alistmajor-mode-remap-defaults,返回替代 mode 使用的主模式。如果这些变量未对该模式进行重映射,则返回 mode 本身。

当某个程序包需要为特定文件格式激活主模式时,应当使用此函数,并将该文件格式的标准主模式作为 mode 参数传入,以确定实际要激活的具体模式,从而兼顾用户的偏好设置。


emacs

Emacs

org-mode

Orgmode

Donations

打赏

Copyright

© Jasper Hsu

Creative Commons

Creative Commons

Attribute

Attribute

Noncommercial

Noncommercial

Share Alike

Share Alike