# Highlighting parity: Shiki → the engine's own tree-sitter parse (CG-57) The viewer's code block used to be classified by a second highlighter — Shiki with 56 pruned TextMate grammars shipped in `dist/textmate/` — over source the engine had already parsed with a real grammar. CG-57 takes the classification off that tree instead. This file records what the swap changed, measured rather than asserted, so nobody has to re-derive it from a diff. Screenshots, one per language, before on the left and after on the right, same stylesheet: [`cg57-highlighting-parity/`](./cg57-highlighting-parity/) — `typescript.png`, `go.png`, `python.png`, `rust.png`, `swift.png`, `csharp.png`, `ruby.png`, `php.png`. ## What it costs 3 000 lines, cold, dev Mac (M-series), parse + classify + wire: | | TypeScript | Go | Python | Rust | Swift | C# | Ruby | PHP | |---|---|---|---|---|---|---|---|---| | Shiki + TextMate | ~700 ms | 43–57 ms | 35–47 ms | — | — | — | — | — | | Engine tree-sitter | 24–41 ms | ~30 ms | 25–29 ms | 18–19 ms | 25–27 ms | 20–25 ms | 14–16 ms | 20–22 ms | The task's budget was **< 100 ms per 3 000-line file warm**; every language clears it *cold*. TypeScript is the number that mattered: its TextMate grammar was 5–7× every other one and the cost was regex *execution*, not compilation, so nothing about the old module could have fixed it. The slice cache still exists — a re-render (resize, theme flip, stepping back through the trail) should cost nothing at all, and the whole-file view pages the same file repeatedly. ## What it changes on screen Per-character comparison over ~40 lines of realistic source per language, counting only non-whitespace characters, and treating `ident` / `other` / `type` as one bucket because all three paint at plain ink: | language | painted identically | what moved | |---|---|---| | TypeScript | 91.3% | 33 `def`, 40 interpolation chars now code, 2 punctuation | | Go | 91.5% | 37 built-in type words, 13 `def` | | Python | 93.2% | 26 `def`, 15 keyword (`is not`, `__future__`) | | Rust | 96.3% | 21 `def`, 3 keyword | | Swift | 93.3% | 18 `def`, 14 keyword (`throws`/`rethrows`) | | C# | 88.3% | 30 built-in type words, 23 `def`, 31 interpolation chars now code | | Ruby | 83.8% | 23 `def`, 35 interpolation chars now code, 14 symbol literals, 3 keyword | | PHP | 85.9% | 33 built-in type words, 29 `def`, 15 phpdoc tag chars, 12 keyword | Every remaining difference is one of five deliberate categories: 1. **`ident` → `def`.** The definition's own name now carries weight 600, everywhere rather than only on the line the Symbol view opened at. It comes from the extractors' own definition tables (`functionTypes`, `classTypes`, `methodTypes`, …) plus each language's `nameField`, so it cannot drift from what indexing considers a definition. 2. **`string` → code, inside an interpolation.** A template literal's `${…}`, an f-string's `{…}`, Ruby's `#{…}` and C#'s `$"{…}"` are classified as code. This is the one difference that is not cosmetic: the call-site overlay deliberately refuses to claim a token classed `string`, so **calls inside interpolated strings now link and did not before.** 3. **`keyword` → `type`, on built-in type words.** `string`, `int`, `u32`, `void`. The grammars disagree with each other about what a built-in type is — tree-sitter-go calls `string` a `type_identifier`, tree-sitter-typescript wraps it in a `predefined_type` whose child is an anonymous token spelled `string` — and TextMate scoped them inconsistently too (plain in TypeScript, `storage.type` in Go). They now all paint at plain ink, like a user-defined type name, in every language. 4. **Keyword-set corrections.** Python's `is not`, Rust's and Swift's modifiers, and Ruby's `new` (which is a method, not a keyword — TextMate's `keyword.operator.new` matched it anyway). 5. **`keyword` → `comment`, on phpdoc tags.** `@var` and friends recede with the comment they are in, which is what the near-monochrome ramp asks for. ## What is no longer highlighted Nine formats have extraction but no tree-sitter grammar. Three of them — `.svelte`, `.vue`, `.astro` — are classified through their `