• 
      

    Fix gsub! and offset! directive results being stored per-pattern.

    Review Request #15250 — Created Aug. 25, 2026 and updated

    Information

    Review Board
    release-9.x

    Reviewers

    Injection patterns that capture @injection.language and transform it
    with #gsub! (astro/vue <script type="text/javascript">) never
    highlighted the injected content. Two bugs combined to cause this:

    1. 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.

    2. 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 as pattern_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
    Fix gsub! and offset! directive results being stored per-pattern.
    Injection patterns that capture @injection.language and transform it with #gsub! (astro/vue <script type="text/javascript">) never highlighted the injected content. Two bugs combined to cause this: 1. 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. 2. 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 as pattern_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. Testing: 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 reviewboard/treesitter and diffviewer interesting- lines/chunk-generator tests.
    pzkytzxvnrwrxutwqqoysuxvwntpvysr
    Checks run (2 succeeded)
    flake8 passed.
    JSHint passed.