Skip to content

fix: don't wrap addition and deletion delimiters twice in embedded languages - #245

Merged
brendt merged 2 commits into
tempestphp:mainfrom
Akiyo974:fix/nested-addition-deletion-delimiters
Oct 27, 2026
Merged

brendt merged 2 commits into
tempestphp:mainfrom
Akiyo974:fix/nested-addition-deletion-delimiters

Conversation

@Akiyo974

Copy link
Copy Markdown
Contributor

Related to #125

{-<script>-} in HTML rendered an empty <span class="ignore"></span> in the output, and the -} disappeared. The same happens with {+ +}, and in Blade, Vue and Svelte.

Cause

The code inside <script> is highlighted by a nested highlighter, which wraps -} in an ignore token. The outer HTML patterns then run on content that already contains that rendered code, so DeletionEndTokenPattern finds the same -} and wraps it a second time. DeletionInjection only unwraps one level, and its regex then consumes the -} that's left inside the span.

Fix

The four delimiter patterns don't match a delimiter that is already wrapped in an ignore token.

Tests

  • PatternTest cases for an already wrapped delimiter on the four patterns
  • Rendered HTML tests for an addition and a deletion that end inside <script>

I also wrapped each line of the bench fixtures in {- -} and {+ +} (3,946 runs): broken outputs go from 608 to 488 on main. Most of the remaining ones are lines that already contain braces, the same kind of collision as #240.

Copilot AI balanced review requested due to automatic review settings October 26, 2026 16:27
@github-actions

github-actions Bot commented Oct 26, 2026 •

Copy link
Copy Markdown

Benchmark Results

Comparison of fix/nested-addition-deletion-delimiters against main (5cb801ab97f5fc06cee265e21a2aec39094bd31c).

Open to see the benchmark results
benchmark subject set revs its mem_peak mode rstdev
HighlighterBench benchParse apache 100 5 2.224mb +0.04% 35.461820μs -2.02% ±1.45% +8.16%
HighlighterBench benchParse bash 100 5 2.257mb +0.04% 99.990000μs -2.32% ±1.07% +79.89%
HighlighterBench benchParse bbcode 100 5 2.212mb +0.04% 35.625695μs +0.55% ±1.37% +68.90%
HighlighterBench benchParse blade 100 5 2.901mb +0.03% 543.902681μs +1.47% ±1.75% +44.76%
HighlighterBench benchParse csharp 100 5 2.659mb +0.04% 181.821644μs -3.01% ±1.23% +42.27%
HighlighterBench benchParse c 100 5 2.250mb +0.04% 80.710000μs +0.06% ±2.15% +123.65%
HighlighterBench benchParse cpp 100 5 2.289mb +0.04% 125.187730μs -0.95% ±1.67% +6.21%
HighlighterBench benchParse css 100 5 2.244mb +0.04% 68.261018μs -4.10% ±1.94% +62.52%
HighlighterBench benchParse diff 100 5 2.244mb +0.04% 47.641683μs -2.50% ±1.85% +4.31%
HighlighterBench benchParse dockerfile 100 5 2.216mb 0.00% 45.109589μs -1.16% ±0.66% -65.58%
HighlighterBench benchParse dotenv 100 5 2.228mb +0.04% 38.574658μs -0.37% ±2.20% +269.73%
HighlighterBench benchParse gdscript 100 5 2.324mb +0.04% 170.537965μs -1.69% ±0.59% -49.19%
HighlighterBench benchParse go 100 5 2.186mb +0.04% 74.824168μs -1.15% ±2.00% +117.16%
HighlighterBench benchParse graphql 100 5 2.245mb +0.04% 77.055910μs +0.17% ±1.08% +2.16%
HighlighterBench benchParse html 100 5 2.251mb +0.04% 59.013933μs +0.67% ±1.16% -19.83%
HighlighterBench benchParse http 100 5 2.216mb +0.04% 12.105088μs -1.36% ±1.67% +71.12%
HighlighterBench benchParse ini 100 5 2.232mb +0.04% 43.148689μs -0.83% ±0.35% -40.52%
HighlighterBench benchParse java 100 5 2.649mb +0.04% 156.380822μs -1.17% ±0.97% -18.31%
HighlighterBench benchParse javascript 100 5 2.315mb +0.04% 136.215538μs -1.32% ±0.60% +1.55%
HighlighterBench benchParse json 100 5 2.288mb +0.04% 120.610352μs +0.46% ±1.35% -6.19%
HighlighterBench benchParse kotlin 100 5 2.540mb +0.04% 140.650137μs +0.00% ±0.27% -85.56%
HighlighterBench benchParse markdown 100 5 2.234mb +0.04% 38.580978μs +0.61% ±0.93% +53.27%
HighlighterBench benchParse nginx 100 5 2.298mb +0.04% 137.881722μs +2.16% ±0.87% -18.59%
HighlighterBench benchParse php 100 5 2.596mb +0.04% 365.051487μs +0.17% ±0.94% +39.02%
HighlighterBench benchParse python 100 5 2.491mb +0.04% 215.278669μs +1.24% ±0.87% +30.52%
HighlighterBench benchParse ruby 100 5 2.599mb +0.04% 118.659765μs -1.84% ±1.83% +853.93%
HighlighterBench benchParse rust 100 5 2.476mb +0.04% 95.069041μs +0.42% ±0.92% +26.18%
HighlighterBench benchParse scss 100 5 2.260mb +0.04% 96.312505μs +2.90% ±1.23% -51.03%
HighlighterBench benchParse sema 100 5 2.428mb +0.04% 109.663757μs +0.67% ±1.31% -0.07%
HighlighterBench benchParse sql 100 5 2.258mb +0.04% 80.341566μs +1.39% ±1.25% -33.33%
HighlighterBench benchParse svelte 100 5 2.540mb +0.04% 521.010509μs -1.07% ±0.76% -46.38%
HighlighterBench benchParse swift 100 5 2.306mb +0.04% 127.150920μs +0.36% ±0.70% -39.19%
HighlighterBench benchParse terminal 100 5 2.254mb +0.04% 93.494834μs +1.26% ±0.88% -40.94%
HighlighterBench benchParse terraform 100 5 2.258mb +0.04% 88.435773μs -0.79% ±0.74% +100.12%
HighlighterBench benchParse toml 100 5 2.230mb +0.04% 67.417926μs +0.89% ±0.65% -24.48%
HighlighterBench benchParse typescript 100 5 2.757mb +0.03% 126.054990μs +2.94% ±0.73% -47.56%
HighlighterBench benchParse txt 100 5 2.186mb +0.04% 3.999159μs -2.82% ±2.33% -7.37%
HighlighterBench benchParse twig 100 5 19.441mb +0.00% 793.586106μs +0.25% ±0.69% +23.76%
HighlighterBench benchParse vue 100 5 2.548mb +0.04% 199.570020μs +0.49% ±0.63% -2.43%
HighlighterBench benchParse xml 100 5 2.265mb +0.04% 91.884834μs +0.00% ±1.10% -14.68%
HighlighterBench benchParse yaml 100 5 2.320mb +0.04% 163.908043μs +0.77% ±1.16% +23.34%
HighlighterBench benchParse jsx 100 5 2.258mb +0.04% 26.405949μs -1.47% ±2.00% +103.36%
HighlighterBench benchParse tsx 100 5 2.415mb +0.04% 39.173523μs +0.60% ±1.95% +100.33%

Generated by phpbench against commit fce86f7

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟢 Approval recommended

The narrowly scoped guards match the existing ignore-token format, with focused regression coverage and no identified blocking issues.

No open issues 🎉

What changed in this PR

Fixes duplicate wrapping of addition and deletion delimiters when embedded code is highlighted, preventing malformed spans and lost delimiters.

Changes:

  • Adds guards to all four delimiter patterns to skip delimiters already wrapped in ignore tokens.
  • Adds pattern-level checks for wrapped delimiters and rendered HTML regression tests for markers ending inside <script>.
File Description
tests/​Languages/​Base/​Injections/​DeletionInjectionTest.php Tests deletion markers ending inside embedded JavaScript.
tests/​Languages/​Base/​Injections/​AdditionInjectionTest.php Tests addition markers ending inside embedded JavaScript.
src/​Languages/​Base/​Patterns/​DeletionStartTokenPattern.php Skips already-wrapped deletion opening delimiters.
src/​Languages/​Base/​Patterns/​DeletionEndTokenPattern.php Skips already-wrapped deletion closing delimiters.
src/​Languages/​Base/​Patterns/​AdditionStartTokenPattern.php Skips already-wrapped addition opening delimiters.
src/​Languages/​Base/​Patterns/​AdditionEndTokenPattern.php Skips already-wrapped addition closing delimiters.

Review effort: Balanced

@brendt
brendt merged commit 1005b5c into tempestphp:main Oct 27, 2026
5 checks passed
@brendt

brendt commented Oct 27, 2026

Copy link
Copy Markdown
Member

Thank you :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants