首页
/ Helix 新语言支持实战指南:languages.toml 配置、Tree-sitter 语法编译与查询开发

Helix 新语言支持实战指南:languages.toml 配置、Tree-sitter 语法编译与查询开发

2026-09-05 16:45:44作者:裘旻烁

本文为 Helix 编辑器贡献新语言支持的完整操作手册,覆盖 languages.toml 中语言项与语言服务器项的写法、Tree-sitter 语法的接入方式、runtime/queries/ 目录下各类 .scm 查询文件的职责与校验流程。读完之后,你可以独立把一个尚未支持的语言接入 Helix,并用 cargo xtask 工具链验证高亮、缩进与查询的有效性。

一、整体流程概览

向 Helix 添加一种语言的工作由三部分构成,对应仓库中的三个位置:

步骤 涉及文件 作用
语言配置 languages.toml(仓库根目录) 声明语言识别、缩进、格式化器、语言服务器
语法配置 languages.toml 中的 [[grammar]] 声明 Tree-sitter 语法来源并编译
查询编写 runtime/queries/ 下的 <语言名>/ 目录 高亮、注入、缩进、文本对象等能力

整个仓库内置了数百种语言的配置。以 Rust 为例,仓库根目录的 languages.toml 中同时存在一个 [[language]] 段(负责语言行为)和一个紧随其后的 [[grammar]] 段(负责语法来源),新语言也应遵循这一配对结构。

二、语言配置(Language configuration)

2.1 添加 [[language]] 条目

第一步是在 languages.toml 中新增一个 [[language]] 条目,并为新语言提供必要的配置。以仓库中已有的 Rust 配置为参照(languages.toml):

[[language]]
name = "rust"
scope = "source.rust"
injection-regex = "rs|rust"
file-types = ["rs"]
roots = ["Cargo.toml", "Cargo.lock"]
shebangs = ["rust-script", "cargo"]
auto-format = true
comment-tokens = ["//", "///", "//!"]
block-comment-tokens = [
  { start = "/*", end = "*/" },
  { start = "/**", end = "*/" },
  { start = "/*!", end = "*/" },
]
language-servers = [ "rust-analyzer" ]
indent = { tab-width = 4, unit = "    " }
persistent-diagnostic-sources = ["rustc", "clippy"]

各字段的完整说明(namescopeinjection-regexfile-typesshebangsrootsauto-formatcomment-tokensblock-comment-tokensindentlanguage-serversgrammarformattersoft-wrap 等)以及文件类型检测(glob 与扩展名两种匹配优先级)的规则,详见 语言配置文档。几个容易忽略的实践要点:

  • scope 建议与主流 TextMate 语法保持一致,一般为 source.<name>,标记类语言用 text.<name>
  • file-types 既可以是扩展名字符串,也可以是 { glob = "..." } 表,后者对文件完整路径做 Unix 风格 glob 匹配(例如 { glob = "Makefile" });
  • roots 是 LSP 工作目录的向上查找标记文件,Helix 从当前文件出发向上走,取最顶层含标记文件的目录;
  • 当语言名与语法名不一致时,用 grammar 键显式指定。例如 languages.tomlname = "protobuf" 的语言显式声明 grammar = "proto",因为语法仓库名是 tree-sitter-proto

2.2 添加语言服务器

如需为新语言接入 LSP,在同一文件的 [language-server] 表中扩展一项,再通过语言条目的 language-servers 数组引用。仓库中的语言服务器项分两种写法:

内联简写(languages.toml 中大量使用):

[language-server]
clangd = { command = "clangd" }
bash-language-server = { command = "bash-language-server", args = ["start"] }
deno = { command = "deno", args = ["lsp"], config.deno.enable = true }
julia = { command = "julia", timeout = 60, args = ["--startup-file=no", "-e", "using LanguageServer; runserver()"] }

带嵌套 config 的多行写法(见 languages.toml):

[language-server.rust-analyzer]
command = "rust-analyzer"

[language-server.rust-analyzer.config]
inlayHints.bindingModeHints.enable = false
inlayHints.closingBraceHints.minLines = 10

[language-server.rust-analyzer.config.files]
watcher = "server"

语言服务器可用的键包括 command(需在 $PATH 中)、argsconfig(LSP 初始化选项)、environment(启动环境变量)、timeout(默认 20 秒)等,完整表格见 语言服务器配置文档。一个语言可以挂多个语言服务器,并用 only-features / except-features 精确限定每个服务器承担的能力(例如只用某个 LSP 做格式化)。

2.3 重新生成语言支持文档

添加新语言或修改语言服务器配置后,运行文档生成任务:

cargo xtask docgen

该任务由 xtask/src/main.rs 实现,会生成三类 Markdown 产物,其中 LANG_SUPPORT_MD_OUTPUT 对应的即 Language Support 文档,它从 languages.toml 自动汇总每种语言可用的能力(格式化、LSP 等),因此配置一改就必须重新生成。

三、语法配置(Grammar configuration)

3.1 添加 [[grammar]] 条目

若新语言有可用的 Tree-sitter 语法,就在 languages.toml 中新增一个 [[grammar]] 条目。仓库中的标准写法(languages.toml):

[[grammar]]
name = "rust"
source = { git = "https://github.com/tree-sitter/tree-sitter-rust", rev = "77a3747266f4d621d0757825e6b11edcbf991ca5" }

source 表的键及含义(完整说明见 语法配置文档):

说明
git 语法仓库的 git 远程 URL
rev 需要拉取的修订(commit hash 或 tag),用于锁定版本
subpath 多语法仓库时指向具体语法子目录,省略则用仓库根

source.path 则接受一个绝对路径,供本地测试语法时使用。注意:提交 pull request 之前,务必把 source.path 换回 source.git,否则其他人和 CI 无法构建该语法。

仓库顶层还有一个总开关 use-grammars

use-grammars = { except = [ "wren", "gemini" ] }

它控制 hx --grammar fetch / hx --grammar build 抓取和构建哪些语法,支持 onlyexcept 两种模式;省略时全部抓取构建。

3.2 抓取与构建语法

语法的实际下载与编译由命令行子命令完成:

hx --grammar fetch   # 按 [[grammar]] 的 git/rev 拉取语法源码
hx --grammar build   # 编译过期(out-of-date)的语法

编译产物是 runtime/grammars/<name>.so 动态库,运行时由 helix-core/src/syntax.rs 加载。query-check 等开发工具内部也会调用同一套加载逻辑(default_lang_loader),因此本地先 build 好语法是运行校验工具的前提。

四、查询(Queries):高亮、缩进与更多能力

4.1 查询目录结构

为提供语法高亮与缩进,需要编写 Tree-sitter 查询文件,放在 runtime/queries/<name>/ 目录下。以 Rust 为例,runtime/queries/rust/ 目录恰好包含全部七种查询文件:highlights.scminjections.scmindents.scmtextobjects.scmlocals.scmtags.scmrainbows.scm

4.2 各类查询文件的职责

Helix 会从该目录加载多个查询文件,其中只有 highlights.scm 是必需的,其余按需提供:

文件 用途 编写指南
highlights.scm 语法高亮 highlights 指南
injections.scm 在特定区域(字符串、代码围栏等)内嵌其他语言 injection 指南
indents.scm 缩进计算 indent 指南
textobjects.scm 文本对象与导航(mif]f 等) textobject 指南
locals.scm 作用域跟踪,让局部变量高亮区分开来 locals 指南
tags.scm 文档/工作区符号选择器 tags 指南
rainbows.scm 彩虹括号 rainbow bracket 指南

编写高亮查询时需要掌握的核心规则(详见 themes 文档 中关于 highlight capture 的说明):

  • 选择最具体的语义作用域(@function@type 等);
  • 捕获你真正想染色的叶子节点
  • 记住最后匹配的 pattern 且最内层的节点胜出——这意味着后写的、范围更窄的 pattern 会覆盖先写的宽泛 pattern。

查询语法本身的编写方法可参考 Tree-sitter 官方文档中的 syntax highlighting 章节(仓库文档中给出的原始链接指向 tree-sitter.github.io,此处按仓库规范不贴出)。

4.3 复用其他语言的查询

一个查询文件可以在首行写 ; inherits: <lang>,直接继承另一个语言的对应查询文件(仓库中多个语言的 highlights.scm 就是这样复用 _javascript_typescript 等私有查询集的)。适合新语言先以继承方式快速获得基础高亮,再逐步补充自己的 pattern。

4.4 运行时目录与环境变量

如果你在本地开发中修改了查询文件而 Helix 找不到它们,需要确保环境变量 HELIX_RUNTIME 指向你正在开发的那个 runtime 目录。从源码结构看,运行时目录的解析优先级在 helix-loader/src/lib.rs 中有明确注释:内置 runtime 目录优先被检查,之后是 HELIX_RUNTIME(若设置),最后才是配置目录下的 runtime。开发阶段把它指到仓库内的 runtime/ 即可让 Helix 实时加载你未提交的查询。

4.5 查询在源码中的编译入口

每种查询对应 helix-core/src/syntax.rs 中的一个编译方法,可据此确认各文件的加载行为:

  • LanguageData::compile_highlight_query:读取 highlights.scm,并连同 injections.scmlocals.scm 一起加载(syntax.rs 注释明确说明 "Loads the grammar and compiles the highlights, injections and locals for the language");
  • compile_indent_query 读取 indents.scmsyntax.rs);
  • compile_textobject_query 读取 textobjects.scmsyntax.rs);
  • compile_tag_query 读取 tags.scmsyntax.rs);
  • compile_rainbow_query 读取 rainbows.scmsyntax.rs)。

这些 compile_* 方法都会以 "Failed to compile X for ''" 为上下文报错,所以查询写错时错误信息能直接定位到文件与语言。

五、验证工具:cargo xtask

所有校验工具都在 xtask/src/main.rs 中注册,帮助文本完整列出了五个任务:

cargo xtask docgen                 # 生成文档(lang-support 等)
cargo xtask query-check [language]    # 校验查询语法对语法的合法性
cargo xtask indent-check [language]   # 用 tests/indent/ 语料校验缩进
cargo xtask highlight-check [language] # 用真实高亮器校验捕获
cargo xtask theme-check [theme]       # 校验主题文件

其中 query-check 的实现(xtask/src/main.rs)值得注意:它遍历加载器中的语言,逐个调用 compile_indent_querycompile_textobject_querycompile_tag_querycompile_rainbow_query——每个查询文件都必须能对该语法成功编译,任何一个失败都会使检查失败。

indent-check 则把 tests/indent/ 目录下的语料文件(命名为 <language-id>.<ext>,仓库中已有 76 种语言的语料)逐行与真实 Tree-sitter 缩进算法比对,包括模拟在行尾按回车时的“打字方向”缩进;highlight-check 走的是 nvim-treesitter 风格的 caret 断言(// ^^^ @capture),用真实高亮器逐列断言获胜捕获(xtask/src/main.rs),能抓出 query-check 发现不了的优先级错误。提交新语言或修改查询时,建议三个检查都跑一遍。

六、常见问题(Common issues)

官方指南列出的排障清单,逐条结合仓库说明:

  1. 切换分支后运行 Helix 报错:Tree-sitter 语法可能过期,运行 hx --grammar fetch 拉取语法、hx --grammar build 重新编译过期的语法。
  2. 某个 parser 导致 segfault 或你想移除它:务必删除编译产物 runtime/grammars/<name>.so,否则旧的二进制仍会被加载。
  3. Helix 找不到你新加的查询:确认 HELIX_RUNTIME 环境变量指向你正在开发的 runtime 目录(解析逻辑见 helix-loader/src/lib.rs)。
  4. 查询校验:用 cargo xtask query-check [language] 验证(每个查询文件都必须能通过语法编译);highlight-checkindent-check 更进一步——它们分别驱动真实的高亮器与缩进器跑测试语料,能捕获编译通过但语义错误的查询。

七、收尾检查清单

把一个语言完整接入 Helix 的提交前清单可以归纳为:

  • [ ] languages.toml 中有配对的 [[language]][[grammar]] 条目,source 使用 git + rev 而非本地 path
  • [ ] 若引入了 LSP,[language-server] 表中已定义对应项且语言的 language-servers 引用了它;
  • [ ] runtime/queries/<name>/ 下至少有 highlights.scm,其余查询按需补齐;
  • [ ] cargo xtask query-check <name>cargo xtask indent-check <name>cargo xtask highlight-check <name> 全部通过;
  • [ ] cargo xtask docgen 已重新运行,Language Support 文档已更新;
  • [ ] 新语言服务器的安装说明已同步到社区维护的 Language Server Configurations Wiki(官方指南给出的提醒)。

完成以上步骤后,新语言即可获得高亮、缩进、文本对象与 LSP 能力,并且文档与校验语料都与其保持一致。

登录后查看全文
热门项目推荐
相关项目推荐

项目优选

收起
kernelkernel
deepin linux kernel
C
33
18
ops-transformerops-transformer
本项目是CANN提供的transformer类大模型算子库,实现网络在NPU上加速计算。
C++
1.12 K
2.72 K
kernelkernel
openEuler内核是openEuler操作系统的核心,既是系统性能与稳定性的基石,也是连接处理器、设备与服务的桥梁。
C
528
588
ops-nnops-nn
本项目是CANN提供的神经网络类计算算子库,实现网络在NPU上加速计算。
C++
906
1.83 K
pytorchpytorch
作为 Ascend for PyTorch 社区的核心组件,TorchNPU 是昇腾专为 PyTorch 打造的深度学习适配插件,使 PyTorch 框架能够直接调用昇腾 NPU,为开发者提供昇腾 AI 处理器的超强算力。
Python
854
1.34 K
docsdocs
暂无描述
Markdown
891
5.79 K
jiuwenswarmjiuwenswarm
JiuwenSwarm 是一款基于openJiuwen开发的智能AI Agent,它能够将大语言模型的强大能力,通过你日常使用的各类通讯应用,直接延伸至你的指尖。
Python
3.53 K
1.01 K
ops-mathops-math
本项目是CANN提供的数学类基础计算算子库,实现网络在NPU上加速计算。
C++
1.34 K
1.45 K
cann-learning-hubcann-learning-hub
CANN 学习中心仓,支持在线互动运行、边学边练,提供教程、示例与优化方案,一站式助力昇腾开发者快速上手。
Jupyter Notebook
988
506
AscendNPU-IRAscendNPU-IR
AscendNPU-IR是基于MLIR(Multi-Level Intermediate Representation)构建的,面向昇腾亲和算子编译时使用的中间表示,提供昇腾完备表达能力,通过编译优化提升昇腾AI处理器计算效率,支持通过生态框架使能昇腾AI处理器与深度调优
C++
540
384