《elisp》 每日一练—— Font Lock 基础与语法高亮

《elisp》 每日一练—— Font Lock 基础与语法高亮

Masimaro
2026-09-26 / 0 评论 / 0 阅读 / 正在检测是否收录...

各位读者中秋快乐,昨天中秋节,我去过了一天节,断更了一天,今天我们继续更新

在前面的文章中,我们 将 Marjo Mode 中的六大元素都梳理了一遍。读者是否还记得哪六大元素呢?他们是 class-name、mode-name、keymap、abbrev-table、syntax-table、major-mode。有了这些元素我们就可以针对这些元素进行mode中的定制化开发。其中一项就是语法高亮,Emacs中的语法高亮依靠的是 Font Lock。

背景知识

Font Lock 本质是一个minor mode,负责根据文本的语法角色,自动为不同的语法角色加上 face属性,也就是文本的字体、字号、颜色、加粗或者斜体等样式。

Font Lock 本身并不决定什么该高亮,它依靠Major Mode 为它标记各种语法类型,例如关键字、语句块、字符串、变量、函数等等。而Font Lock 作为中间的桥梁,将这些属性映射到具体的face上面,最终Emacs根据face属性进行高亮显示。

这么说有点抽象,我们来看一个具体的示例, 它会将C/C++ 注释 /**/ 显示为黄色、// 注释显示为浅灰色。

我们先来定义具体的语法表 syntax-table。对于这类注释的处理,我们在介绍 syntax-table 的时候已经介绍过了,现在直接拿来用即可

(defvar my/c-like-mode-syntax-table
  (let ((table (make-syntax-table)))
    (modify-syntax-entry ?/ ". 124" table) ;; 注意 / 是两种注释都会使用的
    (modify-syntax-entry ?* ". 23" table)
    (modify-syntax-entry ?\n "> b" table) ;; 这里使用style B 类型的注释
    table))

然后我们定义显示文本的face

(defface my-c-block-comment-face
  '((t :foreground "yellow"))
  "Face for /*....*/ comments.")

(defface my-c-line-comment-face
  '((t :foreground "light gray"))
  "Face for // comments")

接着我们声明一个映射关系:

(defvar my/c-like-mode-font-lock-keywords
  `(;; 规则 A:匹配 /* ... */ 块注释,最后加上 t 表示 override 覆盖默认注释 face
    ("/\\*\\(?:.\\|\n\\)*?\\*/" 0 'my-c-block-comment-face t)
    
    ;; 规则 B:匹配 // 单行注释,同样加上 t
    ("//.*$" 0 'my-c-line-comment-face t))
  "测试模式的高亮规则列表。")

最后我们定义buffer local 的 font-lock-default 变量,以便建立二者的映射关系。

(define-derived-mode my/c-like-mode prog-mode "MySimpleC"
  (setq-local font-lock-defaults '(my/c-like-mode-font-lock-keywords)))

我们来分析一下上述代码,深刻体会一下。首先我们定义一个语法表,与前面不同,我们添加了对于换行的处理,在 // 类型的注释中, 换行符是结束,而对于 /**/ 类型的注释,换行符只是其中的一部分。所以在定义换行符的时候,它只是作为 // 类型注释的结尾,这里我们使用了 style B 类型的注释。关于这部分内容读者有兴趣可以查找相关资料,这里表示的含义就是 换行符只作为 // 类型注释的结尾

然后我们定义了 相关的face,来显示两种不同的注释。

接着我们通过正则表达式来匹配,对于 /**/ 注释,我们采用定义的 my-c-block-comment-face 样式显示,对于 // 类型的注释,我们使用定义的样式 my-c-line-comment-face 来使用。

总结

本篇我们简单介绍了一下font lock 的相关机制,它是一个中间的桥梁,由Major Mode 定义语法规则,由用户的习惯定义不同语法块的显示样式,而font lock 负责作为桥梁将二者连接起来。这种机制为各种theme 主题提供了发挥的空间,用户可以通过更换主题来对不同的语法单元进行不同的着色,mode的作者可以专心处理各种语法规则,用户则不需要关注语法,可以选择自己喜欢的配色。同时也可以做到对于不同的语言,相同的语法单元显示相同的效果。

对于本节我们展示的函数,我们将在接下来的文章中依依介绍。各位读者敬请期待!

最后中秋国庆假期我要回家休假了,因此更新可能会等到国庆假期之后了。提前祝各位读者国庆快乐!!!!

0

评论 (0)

取消