Fix gsub! and offset! directive results being stored per-pattern.
Review Request #15250 — Created Aug. 25, 2026 and updated
Injection patterns that capture
@injection.languageand transform it
with#gsub!(astro/vue<script type="text/javascript">) never
highlighted the injected content. Two bugs combined to cause this:
The reader in highlight.py only consulted the stored language when
the raw capture was empty. A truthy but unsupported value like
"text/javascript" skipped the lookup and then failed the supported-
language check.The
gsub!and offset! directive handlers stored results in
query.pattern_settings(pattern_index), but py-tree-sitter passes a
predicate's position within its pattern aspattern_index, not the
actual pattern index. Results usually landed in the wrong pattern's
settings, where consumers (which have the real pattern index from
the match) never found them. The existing directive tests passed
only because their query shapes happened to align the two numbers,
and the offset! markdown frontmatter test passed because the---
fences are valid YAML with or without the offset.Directive results are now stored on the predicate handler itself, keyed
by captured node ID. This sidesteps the unusable index and also fixes a
related problem where multiple matches of one pattern (two
<script type="...">blocks with different languages) clobbered each
other's settings, since the per-pattern settings dictionary is shared
by all matches. set! values are unaffected; they are handled natively
by py-tree-sitter with the correct pattern index.
- Added highlight tests covering a gsub!-transformed injection language
and repeated matches of the same injection pattern with different
languages. - Updated the directive unit tests for the node-keyed storage.
- Ran all tests.
| Summary | ID |
|---|---|
| pzkytzxvnrwrxutwqqoysuxvwntpvysr |