语法高亮
语法高亮是处理代码的应用程序中非常常见的功能。Tree-sitter 通过 tree-sitter-highlight 库内建支持语法高亮,这个库目前用于 GitHub.com 对多种语言代码进行高亮显示。你也可以使用命令行工具 tree-sitter highlight 执行语法高亮。(tree-sitter.github.io)
本文件说明 Tree-sitter 语法高亮系统如何工作,重点使用命令行界面。如果你使用 tree-sitter-highlight 库(无论是 C 还是 Rust),所有概念依然适用,但配置数据是以内存对象而不是文件的形式提供。(tree-sitter.github.io)
概览
用于高亮特定语言的所有文件通常包含在该语言的 Tree-sitter grammar 仓库中(例如 tree-sitter-javascript、tree-sitter-ruby)。要从命令行运行语法高亮,需要三类文件:
- 用户配置:位于
~/.config/tree-sitter/config.json的 per-user 配置文件(参见 init-config 文档)。 - 语言配置:位于 grammar 仓库的
tree-sitter.json文件中(参见 init 文档)。 - 查询文件:位于 grammar 仓库的
queries目录中。(tree-sitter.github.io)
语言配置(Language Configuration)
Tree-sitter CLI 使用 tree-sitter.json 文件。在这个文件中,CLI 会查找顶层 "grammars" 键,其值应包含一个对象数组,对象具有以下键:(tree-sitter.github.io)
基础字段(Basics)
这些字段指定解析器的基本信息:(tree-sitter.github.io)
scope(必需) — 字符串,如"source.js",用于标识语言。该值努力匹配常见的 TextMate grammar 和 Linguist 库中使用的 scope 名称。path(可选) — 从包含tree-sitter.json的目录到包含实际 parser 的src/文件夹的相对路径。默认值为"."。external-files(可选) — 一个相对路径数组,列出在 recompilation 时应检查修改的文件。(tree-sitter.github.io)
语言检测字段(Language Detection)
这些字段帮助决定某文件是否属于该语言:(tree-sitter.github.io)
file-types— 文件名后缀数组。grammar 用于以这些后缀结尾的文件。first-line-regex— 正则匹配第一行以检测语言。content-regex— 在多个 grammar 匹配时,内容正则可用于打破优先级。injection-regex— 用于检测是否应对嵌入语言启用 language injection(注入语言)。(tree-sitter.github.io)
查询路径(Query Paths)
以下键指定语法高亮相关的查询文件路径:(tree-sitter.github.io)
highlights— 高亮查询路径,默认queries/highlights.scmlocals— 局部变量查询路径,默认queries/locals.scminjections— 注入查询路径,默认queries/injections.scm(tree-sitter.github.io)
查询(Queries)
Tree-sitter 的语法高亮系统基于 tree queries,这是一种对语法树模式匹配的通用系统。语法高亮由三种查询文件控制,通常放在 queries 目录下:(tree-sitter.github.io)
Highlights(高亮查询)
最重要的查询是 highlights 查询。它使用 captures 为语法树中的不同节点赋予任意高亮名称,这些名称可映射为颜色。常用的高亮名称包括:
keywordfunctiontypepropertystring
名称也可以是点分隔形式,如 function.builtin。(tree-sitter.github.io)
例如,假设我们要将 Go 代码按如下规则着色:(tree-sitter.github.io)
- 关键字
func、return用紫色 - 函数名
increment用蓝色 - 类型
int用绿色 - 数字
5用棕色(tree-sitter.github.io)
可以写成 highlights 查询:
; highlights.scm
"func" @keyword
"return" @keyword
(type_identifier) @type
(int_literal) @number
(function_declaration name: (identifier) @function)
然后在配置文件中映射各高亮名称到颜色:(tree-sitter.github.io)
{
"theme": {
"keyword": "purple",
"function": "blue",
"type": "green",
"number": "brown"
}
}
Local Variables(局部变量查询)
良好的语法高亮有助于快速区分代码中的不同实体。Tree-sitter 的局部变量查询通过固定的 capture 名称来帮助追踪作用域与变量:(tree-sitter.github.io)
@local.scope— 表示语法节点引入新的本地作用域@local.definition— 表示节点包含当前作用域内的定义名称@local.reference— 表示节点包含可能引用先前定义的名称(tree-sitter.github.io)
此外可以使用 @ignore capture 忽略某些节点,这在模式前置时非常有用。(tree-sitter.github.io)
Language Injection(语言注入)
某些源文件包含多种语言,例如:(tree-sitter.github.io)
- HTML 中的
<script>(JavaScript)与<style>(CSS) - ERB 文件内嵌 Ruby
- JavaScript 中的正则字面量
- Ruby heredoc 内可能包含指定语言内容(tree-sitter.github.io)
通过 @injection.content 和 @injection.language capture,可以指定节点内容按其他语言重新解析,以及指定语言名称。额外属性如 injection.combined、injection.include-children、injection.self、injection.parent 用于控制注入行为。(tree-sitter.github.io)
单元测试(Unit Testing)
Tree-sitter 内建了验证语法高亮结果的方法,基于 Sublime Text 的测试系统。测试文件放在 test/highlight 目录下,并通过特殊注释断言高亮类别。例如:(tree-sitter.github.io)
var abc = function(d) {
// <- keyword
// ^ keyword
// ^ variable.parameter
// ^ function
此类测试使用两种断言方式:
- 插入符号
^:测试最接近的上一非测试注释行指定列的高亮作用域 - 箭头
←:测试注释字符所在列的高亮作用域(tree-sitter.github.io)
注意:感叹号 ! 可用于否定选择器(例如 !keyword 表示不匹配关键词类)。(tree-sitter.github.io)
(翻译完毕)(tree-sitter.github.io)
