Linguist 语法高亮索引(Grammar Index)全解析:查询、排查与维护指南
【免费下载链接】linguistLanguage Savant. If your repository's language is being reported incorrectly, send us a pull request!项目地址: https://gitcode.com/GitHub_Trending/li/linguist
本文围绕 Linguist 仓库中的 vendor/README.md(Grammar index)展开,说明这份"语法索引"是什么、如何读懂它、遇到语法高亮错误时如何定位上报,以及它背后由 script/list-grammars、grammars.yml 与 vendor/grammars 子模块构成的自动生成与同步机制。读完你将掌握:快速定位某一语言语法来源的方法、🐌 标记的真实含义,以及向 Linguist 提交新语法高亮支持的完整流程。
Grammar Index 是什么
Linguist 是 GitHub 用来识别仓库语言并生成语言统计、语法高亮的工具。其中"语法高亮"这一能力并不由 Linguist 自己实现,而是从外部挑选一系列语法定义(Grammar),交给 GitHub 前端渲染时使用。
vendor/README.md 就是这份"挑选结果"的公开索引:它以- **语言名:** 语法来源的列表形式,逐条列出了 Linguist 当前为每一种受支持语言所选择的语法包,以及该语法包的维护仓库。文档开头的定位很明确:
This is a list of grammars that Linguist selects to provide syntax highlighting on GitHub.
也就是说,这份索引是 GitHub 语法高亮功能的"供货清单"——每一种能被正确高亮的语言,都能在这里找到其语法来源。
读懂索引格式:一行一条映射
索引的每一行结构固定:
- **语言名:** 语法仓库(维护方)例如:
- **Ruby:** tree-sitter/tree-sitter-ruby 🐌 - **Python:** tree-sitter/tree-sitter-python 🐌 - **Shell:** atom/language-shellscript - **XML:** textmate/xml.tmbundle每个条目回答两个问题:
- 语言名:GitHub 上显示的编程语言名称(与 lib/linguist/languages.yml 中的语言定义对应);
- 语法来源:提供该语言语法定义的上游仓库,通常是 TextMate Bundle、Sublime/Atom 语法包或 tree-sitter 语法库。
索引末尾覆盖了大量小众语言与数据格式(如1C Enterprise、B (Formal Method)、CoNLL-U、Omgrofl、TSPLIB data等),完整条目见 vendor/README.md 本体。
🐌 标记的含义:上游滞后提示
索引中有相当一部分条目带有 🐌 标记,例如C、C#、Go、HTML、Java、JavaScript、PHP、Python、Ruby、Rust、TypeScript、Swift、Nix、Elixir、Gleam、TLA、Regular Expression等。文档对此有明确说明:
grammars marked with 🐌 are not updated when Linguist is so upstream fixes may take longer to appear on GitHub.
翻译过来即:带 🐌 的语法不会跟随 Linguist 的发布节奏同步更新。Linguist 发布时可能没有重新拉取这些语法的最新版本,因此即使上游仓库修复了 bug,修复在 GitHub 上的生效时间也会更晚。
从条目内容可以观察到一个规律:几乎所有带 🐌 的语法都来自 tree-sitter 官方组织(如 vendor/grammars 中对应的tree-sitter-*子模块)。这可以推断,Linguist 对 tree-sitter 系语法采用了与 TextMate Bundle 系不同的更新策略——前者按独立节奏跟进,后者随 Linguist 发布同步更新。如果你发现某个 🐌 语法的高亮问题,需要明确:即使上游已修复,也要等待 Linguist 下一次同步这些语法子模块。
遇到高亮错误:如何排查与上报
文档给出了明确的上报路径:
If you've encountered an error with highlighting, please find the grammar in the list below and report it to the appropriate repository.
即遇到高亮错误时,不要直接找 Linguist,而是:
- 在 vendor/README.md 的索引中找到对应语言条目;
- 确认该语言使用的语法来源(是哪家仓库维护的语法);
- 去那个仓库提交 issue,并附上复现用的代码片段。
例如一个 Markdown 高亮问题,索引显示其语法来源为wooorm/markdown-tm-language,则问题应上报到该仓库;而如果问题涉及 Python 高亮,则应上报到tree-sitter/tree-sitter-python(同时注意它是 🐌 条目,修复生效存在延迟)。
判断"该找谁"还有一种辅助手段:索引条目中语法来源的名称,大多与 vendor/grammars 下的子模块目录名一一对应(如tree-sitter-c、xml.tmbundle、MagicPython等),可直接在本地查看对应语法定义文件。
索引背后的自动生成机制
这份索引不是手写的。文档在列表前有一行关键注释:
Everything below this line is auto-generated by script/list-grammars. Manual edits will be lost
即列表以下全部由 script/list-grammars 自动生成,手动修改会被覆盖。与之配套的数据源是根目录下的 grammars.yml,它的结构是把 vendor/grammars 下的子模块目录映射到 TextMate scope 名称:
vendor/grammars/AL: - source.al vendor/grammars/Alloy.tmbundle: - source.alloy vendor/grammars/MagicPython: - source.python - source.python.console - source.python.traceback这个机制在测试中有严格保障。test/test_grammars.rb 中test_readme_file_is_in_sync会对比vendor/README.md与script/list-grammars --print的输出:
def test_readme_file_is_in_sync current_data = File.read("#{ROOT}/vendor/README.md").to_s.sub(/\A.+?<!--.+?-->\n/mu, "") updated_data = `script/list-grammars --print` assert_equal current_data, updated_data, "Grammar list is out-of-date. Run `script/list-grammars`" end一旦新增语法后忘记重新生成索引,CI 会直接失败,并提示运行script/list-grammars。这保证了索引、grammars.yml 与 vendor/grammars 子模块三者永远保持一致。
同一测试文件还验证了其他一致性约束:
test_no_duplicate_scopes:grammars.yml 中不能出现重复的 scope;test_submodules_are_in_sync:grammars.yml 中列出的子模块必须真实存在于仓库,反之仓库中新增的子模块也必须登记到 grammars.yml;test_submodules_use_https_links:.gitmodules 中的子模块地址必须是 HTTPS 而非 SSH。
语法包的组织形式:vendor/grammars 子模块
所有被选中的语法包都作为git 子模块存放在 vendor/grammars(当前包含 555 个目录),每个子模块对应一个语法来源。之所以用子模块而非直接拷贝代码,是因为:
- 语法包通常由社区在独立仓库维护,子模块能保留其版本与提交历史;
- Linguist 可以通过更新子模块引用来升级语法,而无需改动自身代码;
- grammars.yml 以子模块路径为 key 登记 scope,形成"子模块 → scope"的完整索引。
初次克隆仓库后,需要执行 script/bootstrap 来初始化这些子模块,其核心步骤包括:
git submodule init git submodule sync --quiet script/fast-submodule-updatefast-submodule-update是 Linguist 对子模块拉取的加速封装(避免逐个 clone 造成超时)。
语法包实际加载路径由 lib/linguist/grammars.rb 提供:
module Linguist module Grammars # Get the path to the directory containing the language grammar JSON files. def self.path File.expand_path("../../../grammars", __FILE__) end end end它指向编译产物grammars/目录——运行时使用的是由 script/grammar-compiler 把各子模块的.tmLanguage/tree-sitter定义编译成的 JSON 文件,而不是直接解析原始语法包。
如何新增一种语言的语法高亮
如果你为 Linguist 支持的语言提供(或修复)了语法,需要通过官方脚本 script/add-grammar 把它登记为子模块。该脚本用法:
# 基本用法:添加新语法子模块 script/add-grammar https://example.com/owner/repo # 替换已有语法子模块 script/add-grammar --replace old-module-name https://example.com/owner/new-repo # 静默模式(失败时才输出) script/add-grammar -q https://example.com/owner/repo关键参数说明:
| 参数 | 作用 |
|---|---|
url(位置参数) | 语法仓库地址,必填 |
-q, --quiet | 不打印过程信息,仅在失败时输出 |
-r, --replace SUBMODULE | 替换已有的语法子模块(例如用新维护者仓库替换旧仓库) |
-h, --help | 打印完整帮助信息 |
添加完成后,还需保证索引同步,完整流程为:
- 运行
script/add-grammar <url>添加/替换子模块; - 更新 grammars.yml,登记新子模块路径及其 TextMate scope;
- 运行
script/list-grammars重新生成 vendor/README.md 中的索引列表; - 提交后由 CI 中的 test/test_grammars.rb 校验三处一致性(README 同步、子模块同步、scope 无重复)。
语言与语法来源对照(代表性样例)
下表从 vendor/README.md 摘录代表性条目,展示主流语言分别由哪类语法来源提供(完整清单以文档本体及 grammars.yml 为准):
| 语言 | 语法来源类型 | 是否 🐌 |
|---|---|---|
| C / C++ / Objective-C | TextMate C Bundle 系 | C 是 🐌,C++ 否 |
| C# / Uno / EQ | dotnet/csharp-tmLanguage | C# 是 🐌 |
| Go / Java / JavaScript / Python / Ruby / Rust / TypeScript / Swift / HTML / CSS / PHP / Nix / Elixir / Gleam | tree-sitter 官方语法库 | 全部 🐌 |
| Shell / Gentoo Ebuild / OpenRC runscript | atom/language-shellscript | 否 |
| XML / XSLT / XProc / Web Ontology Language | textmate/xml.tmbundle | 否 |
| Perl / R / Tcl / Pascal / Fortran / TeX | TextMate 官方 Bundle | 否 |
| JSON / Max / Jupyter Notebook | NovaGrammars | 否 |
| ABAP / COBOL / JCL | 社区语言服务器配套语法 | 否 |
可以看出:🐌 条目集中在 tree-sitter 官方语法,而 TextMate Bundle 系语法随 Linguist 发布同步更新,这正是"为什么有些语法修复快、有些慢"的根源。
小结:一条从查询到维护的完整链路
理解这份 Grammar Index 后,你可以按需走完以下链路:
- 查:在 vendor/README.md 中按语言名检索语法来源;
- 报:高亮出错时,按索引指向的上游仓库提交 issue,并留意 🐌 条目的延迟生效问题;
- 核:本地通过 vendor/grammars 子模块与 grammars.yml 核对 scope 映射;
- 增/改:用 script/add-grammar 登记新语法,运行 script/list-grammars 重新生成索引,并保证通过 test/test_grammars.rb 的一致性校验。
整条链路以"子模块存储、YAML 登记、脚本生成、测试锁定"的方式运转,使得数百种语言的语法高亮来源既高度可追溯,又能长期保持自动同步。
【免费下载链接】linguistLanguage Savant. If your repository's language is being reported incorrectly, send us a pull request!项目地址: https://gitcode.com/GitHub_Trending/li/linguist
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考