adding-grammar
Use when adding a new TextMate grammar to the KotlinTextMate project, including corpus files, golden snapshot generation, and conformance test registration
安装与使用
请根据来源仓库和你的 AI 工具说明安装此技能。先阅读技能文件和依赖要求,再添加到工作流。
查看来源 ↗使用指南技能说明
Adding a Grammar to KotlinTextMate
Overview
Adding a new grammar requires: grammar file, corpus files, golden snapshot generation, and test registration. Missing any step causes silent gaps in conformance coverage.
Placeholders used below: <lang> = corpus directory name (always lowercase, e.g., javascript), <Grammar> = grammar filename without .tmLanguage.json (preserve original casing, e.g., JavaScript), <Label> = human-readable name for test display (e.g., JavaScript).
Prerequisites
- Node.js >= 21.2 (for the snapshot generator)
Steps
0. Obtain the grammar file
Source the .tmLanguage.json from VS Code's built-in extensions: microsoft/vscode repo under extensions/<lang>-basics/syntaxes/. Copy to shared-assets/grammars/. Use the exact original filename — casing varies per grammar (e.g., JavaScript.tmLanguage.json uppercase, kotlin.tmLanguage.json lowercase). If the file is JSONC (has trailing commas or comments), strip them to make valid JSON.
Also check if vscode-textmate/test-cases/themes/syntaxes/ or vscode-textmate/benchmark/ already has the grammar.
1. Create corpus files
Create tools/generate-golden/corpus/<lang>/ with hand-crafted source files exercising the language's syntax.
Check vscode-textmate/test-cases/themes/tests/ first — it has small, focused test files (e.g., test.js, test.jsx) that make excellent corpus files. Also check vscode-textmate/benchmark/ for larger corpus files.
Prefer 1-3 small focused files over one large dump. Existing corpora use 1-2 files each (JSON: 1 file, Kotlin: 2, Markdown: 2, JavaScript: 1).
2. Register in generator
Add entry to GRAMMARS in tools/generate-golden/generate.mjs:
<lang>: { file: "<Grammar>.tmLanguage.json", scope: "<scope.name>" },
Find the scope name in the grammar file's top-level scopeName field.
3. Run generator
cd tools/generate-golden && npm install && npm run generate
Produces core/src/test/resources/conformance/golden/<lang>.snapshot.json.
4. Add to GoldenSnapshotTest
Add parameter row in core/src/test/kotlin/dev/textmate/conformance/GoldenSnapshotTest.kt:
arrayOf("<Label>", "grammars/<Grammar>.tmLanguage.json", "conformance/golden/<lang>.snapshot.json"),
5. Add sentinel test
Add test in core/src/test/kotlin/dev/textmate/conformance/SentinelPatternTest.kt:
@Test
fun `<Label> grammar has 0 sentinel patterns`() {
val onigLib = JoniOnigLib()
loadAndCompileGrammar("grammars/<Grammar>.tmLanguage.json", onigLib)
assertEquals("<Label> should have no sentinel patterns", 0, onigLib.sentinelPatternCount)
}
If the grammar uses backreferences inside lookbehinds (like Markdown's strikethrough), expect >0 sentinels. Run the test first with 0 — if it fails, the actual count tells you the correct value.
Important: loadAndCompileGrammar() tokenizes fixed representative lines. Lazy compilation means only exercised rules get compiled. You MUST add at least one representative line for the new language to the lines list inside loadAndCompileGrammar() in SentinelPatternTest.kt, otherwise 0 sentinels passes vacuously.
6. Run tests
./gradlew :core:test --tests "dev.textmate.conformance.*"
7. Commit
Commit all new/changed files: grammar file, corpus, snapshot, generator config, test code.
Key File Locations
| Purpose | Path |
|---|---|
| Grammar files | shared-assets/grammars/ |
| Corpus files | tools/generate-golden/corpus/<lang>/ |
| Generator script | tools/generate-golden/generate.mjs |
| Generated snapshots | core/src/test/resources/conformance/golden/ |
| Golden snapshot test | core/.../conformance/GoldenSnapshotTest.kt |
| Sentinel test | core/.../conformance/SentinelPatternTest.kt |
| Reusable test files | vscode-textmate/test-cases/themes/tests/ |
Common Mistakes
- Forgetting sentinel test — sentinels silently degrade tokenization; always verify count
-
Not checking vscode-textmate clone — reusable corpus files often exist in
test-cases/themes/tests/ -
Wrong grammar file casing — use exact filename (e.g.,
JavaScript.tmLanguage.jsonnotjavascript.tmLanguage.json) -
Generator without
npm install—node_modulesnot committed; always install first -
Cross-grammar includes won't resolve — generator uses
loadGrammar: () => null; sub-grammars (likesource.js.regexp) won't load, and that's expected — the snapshot captures this behavior
使用示例
查看来源仓库中的使用示例与配置说明。
查看来源 ↗来源历史
- 收录时间
- 2026-03-11
- 索引更新时间
- 2026-03-11
- Branch
- main
收录与同步日期属于本站记录。源码修改历史请查看来源仓库。
GitHub ↗chat Comments (0)
Sign in to join the discussion and leave a comment.
No comments yet. Be the first to share your thoughts!