GitHub Linguist 如何添加一种新语言:languages.yml、语法与样本的完整流程
【免费下载链接】linguistLanguage Savant. If your repository's language is being reported incorrectly, send us a pull request!项目地址: https://gitcode.com/GitHub_Trending/li/linguist
如果你的语言目前不被 GitHub 识别,仓库语言统计栏里没有它,或者你的扩展名被归到了别的语言下,Linguist 官方给出的解决方式就是向 linguist 仓库提交一个 pull request,走「languages.yml登记语言 + 添加高亮语法 + 补充样本代码」的完整流程。本文按 CONTRIBUTING.md 中 “Adding a language” 一节的实际操作路径展开:先搭好开发环境,再依次修改 lib/linguist/languages.yml、运行script/add-grammar引入 TextMate 兼容语法、在 samples/ 目录下放好真实代码样本、生成语言 ID,最后通过测试并开 PR。
开始之前有两个前提需要确认:
- 使用量门槛:Linguist 只接受在公开 GitHub 仓库中有足够使用量的新语言,非常新或纯兴趣型(hobby)语言会被直接关闭。CONTRIBUTING.md 给出的量化标准是:
- 每仓库会多次出现的扩展名(如
.rb),要求近一年内被 GitHub Search 索引的文件数至少2000(不含 fork); - 每仓库只出现一次的文件名(如
Makefile),要求近一年内至少200个文件(不含 fork); - 结果需要在不同的
:user/:repo组合间分布合理,如果某个用户(比如语言作者本人)占比过高,评估时会用-user:<username>将其过滤后再看。 - 这些证据要通过 PR 模板中要求的 GitHub 搜索链接提供,且要留意 GitHub Search 本身对可索引内容的限制。
- 每仓库会多次出现的扩展名(如
- 语法许可证:
script/add-grammar只接受带有 CONTRIBUTING.md 所链接许可证列表 之一的高亮语法;许可证不符的语法无法添加。
准备开发环境
Linguist 是 Ruby 库,本地贡献需要较新版本的 Ruby。macOS/XCode 自带的 Ruby 安装依赖时已知有问题,文档建议改用 Homebrew、rbenv、rvm、ruby-build、asdf等包管理方式安装。
依赖方面(见 CONTRIBUTING.md):
- 字符编码检测库
charlock_holmes(依赖 ICU,即icu4c); rugged提供的 libgit2 绑定(依赖cmake和pkg-config);- 安装 gem 依赖需要 Bundler v1.10.0 或更新版本;
- 添加或更新语法时还需要 Docker。
在 Ubuntu 上,文档给出的系统依赖安装命令(需要 root 权限,会修改系统软件包)是:
apt-get install cmake pkg-config libicu-dev docker.io ruby ruby-dev zlib1g-dev build-essential libssl-devmacOS 上则依赖 Getting started 步骤里的script/bootstrap自动处理。环境搭建有三种方式:GitHub Codespaces(文档推荐,开箱即用)、本地 VS Code dev container(打开仓库后 VS Code 会提示在容器内运行,无需额外配置)、或直接在本地系统安装。本文按本地系统方式写。
克隆仓库并运行script/bootstrap安装依赖。script/bootstrap的作用(见 script/bootstrap):在 macOS 上自动执行brew bundle安装 Homebrew 依赖,然后bundle install安装 gem 依赖(安装到vendor/gems),接着git submodule init/git submodule sync并调用 script/fast-submodule-update 初始化语法子模块,最后bundle exec rake samples生成样本数据。
git clone https://github.com/github/linguist.git cd linguist/ script/bootstrap验证环境可用:从克隆的仓库直接运行 Linguist:
bundle exec bin/github-linguist --breakdown能输出当前仓库的语言占比和文件明细,说明环境搭建完成。
在 languages.yml 中添加语言条目
在 lib/linguist/languages.yml 中为新语言添加一条目。该文件头部注释定义了各字段的含义和必填项,其中:
type必填,取值为data、programming、markup或prose(data/prose类型的语言不计入仓库语言统计,见 docs/how-linguist-works.md);extensions:关联的文件扩展名列表,按升序 ASCII 排序,主扩展名必须放在第一位;filenames:关联的文件名列表,与extensions二者至少其一;tm_scope:该语言对应的 TextMate scope,需要与grammars.yml中列出的 scope 之一匹配;没有 TextMate 语法时填none;language_id:GitHub 内部使用的唯一标识,由script/update-ids生成,文档明确要求不要手工填写——所以这一步先留空。
如果新语言定义的扩展名已经存在于languages.yml并被别的语言使用,还有两个额外要求(与“给已有语言加扩展名”一节相同):
samples目录中,每个使用该扩展名的语言至少要有两个示例文件;- 如果两种语言外观相似,或其中一种有可唯一识别的特征,考虑写一个启发式(heuristic)帮助分类。目标是尽量减少误判(false positives)。
用 script/add-grammar 添加高亮语法
语法高亮由 TextMate 兼容语法驱动。为新语言添加语法的命令:
script/add-grammar https://github.com/某作者/MyGrammar这条命令会分析语法仓库,没有问题时把它以子模块形式加入 Linguist 仓库;如果分析发现问题,你需要向该语法的维护者报告,否则无法添加(见 CONTRIBUTING.md)。命令的参数就是语法仓库的 URL,示例中https://github.com/某作者/MyGrammar需替换为你要添加的语言语法仓库地址。
script/add-grammar 本身还定义了-q/--quiet(失败时不输出额外信息)和-r/--replace <submodule>(替换已有语法子模块)两个选项;--replace用于切换已有语言的语法来源,属于另一个维护场景,添加新语言时用不到。该脚本启动时会检查docker git sed ruby bundle是否可用,缺失时会直接报错退出——这对应上面“添加语法需要 Docker”的前提。
语法的正则表达式兼容性会在编译阶段检查:Linguist 使用 PCRE,而 TextMate 语法基于 Oniguruma,两者大多兼容但偶有差异,CONTRIBUTING.md 说明语法更新时 Linguist 的 grammar compiler 会标出这些问题。
向 samples 目录添加样本代码
在 samples/ 目录下对应语言的子目录中添加样本文件,文件名使用该语言的扩展名。文档对样本的要求:
- 优先选择展示常用写法的真实世界代码,越能代表该语言的结构越好;
- “Hello world” 和教程里的示例不会被接受;
- 开 PR 时须明确说明样本代码的许可证:能直接链接到原始来源最好;如果样本是专为这个 PR 编写且同意按 Linguist 的 MIT 许可证收录,也可以这样声明。
样本的作用之一是喂给分类器:docs/how-linguist-works.md 描述了检测策略链(modeline、常见文件名、shebang、扩展名、XML header、man page section、启发式、朴素贝叶斯分类)按序生效,样本是分类器学习材料的来源;docs/troubleshooting.md 也提到“增加样本可以让分类器更聪明”。
生成 language_id
语言条目和样本都就位后,运行:
script/update-idsscript/update-ids 会读取lib/linguist/languages.yml,为所有缺少language_id字段的语言生成 ID 并写回文件。脚本输出的 “Updated N language(s)” 列表就是它更新的条目;没有缺失 ID 时会输出 “No languages were found with missing IDs.”。它还提供--check参数只做检查不改文件,用于查看哪些语言缺 ID。注意它更新的是所有缺 ID 的语言——因此不要在自己的分支上遗留他人未合并的改动,避免把无关语言一并带进你的 PR。
运行测试验证
CONTRIBUTING.md 给出两条本地验证命令:
# 运行完整测试套件 bundle exec rake test # 单独测试分类器 bundle exec script/cross-validation --test如果本地跑测试困难(比如没有太多 Ruby 经验),文档明确表示可以让 GitHub Actions 代劳:直接开 pull request,CI 会自动开始跑测试。
开 PR 与后续
PR 必须使用并填写 PR 模板,未填模板的 PR 不会被 review。模板要求的关键内容:
- 链接到展示该语言实际使用量的 GitHub 搜索结果(对应上面的使用量门槛);
- 样本代码的许可证说明,能直接链接原始来源最好。
PR 合并后不会立刻出现在 GitHub 上:变更要等新的 Linguist 版本发布并部署到 GitHub.com 才生效,发布节奏没有固定时间,目标是每三到四个月至少一次(见 docs/troubleshooting.md)。另外注意:新语言在合并且新版本部署后,还会在 GitHub 的搜索结果中延迟数周到数月才出现,因为 GitHub 搜索使用一个独立于 Linguist 的内部语言检测库,会滞后于 Linguist。
限制与边界
- 使用量不足的语言(非常新、纯兴趣型)PR 会被关闭,这是硬性门槛,样本和语法再完整也无法绕过;
- 语法分析失败时
script/add-grammar无法继续,只能向语法上游维护者报告问题,没有旁路; - 语法许可证不在允许列表内时同样无法添加;
- 共享扩展名冲突(新语言复用了已被别的语言使用的扩展名)必须用“每个语言至少两个样本 + 必要时写启发式”来处理,这是为避免误判而设的要求。
按以上路径走完——languages.yml条目(留空language_id)、script/add-grammar引入语法、samples/样本、script/update-ids生成 ID、bundle exec rake test通过、按模板开 PR——就是为 Linguist 添加一种新语言的全部流程。
【免费下载链接】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),仅供参考