Emacs 在打开文件时,会根据文件名或文件内部信息,自动为缓冲区选择合适的主模式。它同时会处理文件文本中指定的局部变量。
该函数为当前缓冲区设置合适的主模式与缓冲区局部变量绑定。它会调用 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)’ 的形式报告原始错误信息。
该函数为当前缓冲区选择并设置合适的主模式,决策依据按优先级依次为:文件首行 ‘-*-’ 标记、文件尾部的 ‘mode:’ 局部变量、‘#!’ 解释器行(通过 interpreter-mode-alist)、缓冲区开头文本(通过 magic-mode-alist),最后是所访问的文件名(通过 auto-mode-alist)。See How Major Modes are Chosen in The GNU Emacs Manual。若 enable-local-variables 为 nil,则 set-auto-mode 不会检查 ‘-*-’ 行与文件尾部的模式标记。
某些文件类型不适合通过扫描内容识别模式。例如 tar 归档文件尾部可能包含带有局部变量段的成员文件,不应将其模式应用于整个归档文件;又如 TIFF 图像文件首行可能恰好形似 ‘-*-’ 格式。为此,这类文件扩展名均已加入 inhibit-local-variables-regexps 列表。向该列表添加正则表达式可阻止 Emacs 从中搜索任何类型的局部变量(不仅限于模式标记)。
若 keep-mode-if-same 非空,且缓冲区已处于正确主模式,则该函数不会重复调用模式命令。例如 set-visited-file-name 会将其设为 t,避免清除用户已设置的缓冲区局部变量。
该函数将 buffer 的主模式设为 major-mode 的默认值;若默认值为 nil,则使用当前缓冲区的主模式(如适用)。一个例外是:若缓冲区名为 *scratch*,则将模式设为 initial-major-mode。
创建缓冲区的底层原语不使用该函数,但 switch-to-buffer、find-file-noselect 等中层命令在创建缓冲区时均会调用。
该变量的值决定初始 *scratch* 缓冲区的主模式,取值应为主模式命令对应的符号,默认值为 lisp-interaction-mode。
该变量用于为 ‘#!’ 行指定解释器的脚本文件匹配主模式。其值为关联列表,元素格式为 (regexp . mode),表示若文件解释器匹配 \\`regexp\\', 则使用 mode 模式。例如默认元素 ("python[0-9.]*" . python-mode)。
该变量为关联列表,元素格式为 (regexp . function),其中 regexp 为正则表达式,function 为函数或 nil。打开文件后,若缓冲区开头文本匹配 regexp 且 function 非空,则 set-auto-mode 会调用该函数;若 function 为 nil,则交由 auto-mode-alist 决定模式。
用法与 magic-mode-alist 相同,但仅在 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))
该变量是一个关联列表,用于指定激活某个主模式时实际应调用的函数。适用于可被多种主模式支持的文件格式,通过该变量可以指定默认使用的替代模式。
例如,某个第三方包提供了大幅改进的 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 中的条目。
该函数根据 major-mode-remap-alist 和 major-mode-remap-defaults,返回替代 mode 使用的主模式。如果这些变量未对该模式进行重映射,则返回 mode 本身。
当某个程序包需要为特定文件格式激活主模式时,应当使用此函数,并将该文件格式的标准主模式作为 mode 参数传入,以确定实际要激活的具体模式,从而兼顾用户的偏好设置。