Built mostly by Gemini 3 Pro using opencode.
A CLI tool to make debugging VSCode syntax highlighting easier by simulating the full TextMate + Semantic Token pipeline, generating visual previews, and providing snapshot-based regression testing with diffing capabilities.
- Hybrid Engine: Simulates VS Code's highlighting pipeline by merging TextMate scopes (using
vscode-textmate+vscode-oniguruma) with LSP Semantic Tokens. - Theme Support: Resolves colors using VS Code compatible JSON themes.
- Visualization: Generates HTML previews with tooltips to inspect the full scope stack and token provenance (TextMate vs Semantic).
- Regression Testing: Snapshot-based testing to verify that changes to the semantic tokens, grammar, or theme do not introduce unexpected differences.
- Diffing: When verifying snapshots, generates a diff of any mismatches to quickly identify issues.
bun installRun the tool with a configuration file:
bun run src/index.ts config.jsonThe configuration file controls which grammar, LSP, and files are tested. Paths in the config are generally relative to the location of the config.json file itself.
{
"grammar": "./path/to/grammar.tmLanguage.json",
"scopeName": "source.swift",
"lsp": {
"command": ["/path/to/language-server", "--arg1", "--arg2"],
"rootUri": "file:///path/to/project"
},
"theme": "Dark Modern",
"files": ["./path/to/source1", "./path/to/source2"],
"outDir": "./results",
"snapshotDir": "./snapshots"
}| Property | Type | Required | Description | Default |
|---|---|---|---|---|
grammar |
string |
Yes | Path to the main TextMate grammar file (JSON format). | - |
scopeName |
string |
Yes | The root scope name of the grammar (e.g., source.ts, source.swift). |
- |
theme |
string |
Yes | Path to a VS Code compatible JSON theme file OR a known theme name (e.g. "Dark Modern", "Dark+", "Light Modern"). | - |
files |
string[] |
Yes | List of source files to process and highlight. | - |
lsp.command |
string[] |
Yes | The command to launch the Language Server (e.g., ["node", "server.js"] or ["/path/to/binary"]). |
- |
lsp.rootUri |
string |
No | The root URI sent to the LSP initialize request. |
file:// + directory of config.json |
extraGrammars |
object |
No | A map of scope names to grammar paths. Used for including other languages (e.g., embedding SQL in Strings). | {} |
outDir |
string |
No | Directory where HTML and JSON results are written. | ./out (relative to config.json) |
snapshotDir |
string |
No | Directory where expected token snapshots are stored for verification. | ./snapshots (relative to config.json) |
To verify that the current output matches previously saved snapshots:
bun run src/index.ts config.json --verifyTo update snapshots (accept current output as correct):
bun run src/index.ts config.json --updateWhen running in --verify mode, if there are any mismatches between the generated tokens and the snapshot, a visual diff report will be generated for each file, showing side-by-side comparisons of the expected vs actual tokens.
You can create multiple versions of snapshots for the same file (e.g., to test different configurations or scenarios) using the --snapshot-name option.
To create a named snapshot:
bun run src/index.ts config.json --update --snapshot-name v2
# Creates: snapshots/filename.v2.tokens.jsonTo verify against a specific named snapshot:
bun run src/index.ts config.json --verify --snapshot-name v2You can also customize the label for the "generated" side of the diff using --generated-name:
bun run src/index.ts config.json --verify --generated-name "Proposed Changes"You can manually generate a visual diff HTML report between any two token JSON files (e.g., a snapshot and a newly generated output) using the diff command.
bun run src/index.ts diff <snapshot.json> <generated.json> [output.html]snapshot.json: The "expected" token file (left side of diff).generated.json: The "actual" token file (right side of diff).output.html: (Optional) The output path for the HTML report. Defaults todiff.html.
This generates an interactive side-by-side view where you can verify discrepancies in color, style, or scopes.
- Set up a config pointing to your grammar, LSP, and test files.
- Run the tool with
--updateto generate a baseline snapshot. - Make changes to your grammar or language server.
- Run the tool with
--verifyto get a report of any differences from the baseline.
For each input file, the tool generates:
filename.html: An interactive preview of the highlighting. Hover over tokens to see scope details.filename.tokens.json: A raw JSON dump of the resolved tokens (used for snapshots).
MIT License. See LICENSE for details.

