Skip to content

fix: ignore marker delimiters that come from ordinary code - #244

Merged
brendt merged 3 commits into
tempestphp:mainfrom
Akiyo974:fix/emphasis-markers-in-code
Oct 27, 2026
Merged

brendt merged 3 commits into
tempestphp:mainfrom
Akiyo974:fix/emphasis-markers-in-code

Conversation

@Akiyo974

Copy link
Copy Markdown
Contributor

Fixes #240

{_, {* and {~ were read as highlight markers even when they came from ordinary code, for example const {_id} = a; const {name_} = b; in JavaScript or a = {_: 1} / b = {1: _} in Python. The delimiters were hidden and everything in between was wrapped in hl-em.

Cause

IsHighlightInjection matched any {_ … _} pair. In code like the examples above, the brace of {_ is closed by the code itself, so the "marker" content leaves one pair of braces and ends inside another: id} = a; const {name.

Fix

A match is now skipped when its content has a } that closes a brace opened before it, followed by a { that stays open. Real markers never do that. The search then continues right after the skipped {_, so a real marker later in the same snippet is still found (const {_id} = a; {_b_}; highlights b).

This applies to emphasis, strong and blur, since they share the same trait. Custom classes ({:class: :}) and additions/deletions aren't affected.

Markers around unbalanced braces keep working:

  • {_function foo() {_}: an opening brace only
  • {_ return 1;\n}_}: a closing brace only
  • {~}): Foo {}~}: the existing case from PhpLanguageTest

Tests

Added cases to HighlightMarkersTest:

  • delimiters in ordinary JavaScript, Python and PHP code, for _, * and ~
  • a real marker after a code delimiter in the same snippet
  • markers around unbalanced braces

Known limitation

A marker that wraps braces in the reverse order inside a string, like {_echo "}{";_}, is no longer treated as a marker. That seemed rare enough compared to destructuring or dict literals, but I'm happy to handle it differently if you'd prefer.

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

github-actions Bot commented Oct 26, 2026 •

Copy link
Copy Markdown

Benchmark Results

Comparison of fix/emphasis-markers-in-code against main (c0276f7ad33b6e64d0571645d7429e33b419c3af).

Open to see the benchmark results
benchmark subject set revs its mem_peak mode rstdev
HighlighterBench benchParse apache 100 5 2.207mb +0.76% 70.394521μs -2.23% ±1.10% -30.84%
HighlighterBench benchParse bash 100 5 2.240mb +0.75% 204.552661μs +0.80% ±0.67% -13.21%
HighlighterBench benchParse bbcode 100 5 2.195mb +0.77% 72.137554μs -1.22% ±0.74% -67.06%
HighlighterBench benchParse blade 100 5 2.884mb +0.58% 1,122.284775μs -1.97% ±0.80% -50.27%
HighlighterBench benchParse csharp 100 5 2.643mb +0.64% 376.762857μs +0.77% ±0.64% -9.97%
HighlighterBench benchParse c 100 5 2.233mb +0.75% 159.594247μs -1.08% ±0.67% +167.06%
HighlighterBench benchParse cpp 100 5 2.272mb +0.74% 242.745127μs -0.32% ±0.31% -8.23%
HighlighterBench benchParse css 100 5 2.227mb +0.75% 138.843268μs -0.89% ±0.87% +44.38%
HighlighterBench benchParse diff 100 5 2.228mb +0.75% 96.223933μs -2.99% ±0.51% -62.84%
HighlighterBench benchParse dockerfile 100 5 2.199mb +0.76% 86.281840μs -0.91% ±0.24% -82.72%
HighlighterBench benchParse dotenv 100 5 2.211mb +0.76% 74.869609μs -2.23% ±0.31% -7.98%
HighlighterBench benchParse gdscript 100 5 2.307mb +0.73% 329.850665μs -0.58% ±0.81% +16.00%
HighlighterBench benchParse go 100 5 2.186mb 0.00% 146.133894μs -0.21% ±0.72% +19.27%
HighlighterBench benchParse graphql 100 5 2.228mb +0.75% 151.462329μs -0.16% ±0.94% +20.44%
HighlighterBench benchParse html 100 5 2.234mb +0.75% 114.675166μs -0.76% ±0.46% -3.73%
HighlighterBench benchParse http 100 5 2.199mb +0.76% 22.839726μs -5.15% ±0.94% -17.98%
HighlighterBench benchParse ini 100 5 2.215mb +0.76% 83.824325μs -1.98% ±0.59% -6.05%
HighlighterBench benchParse java 100 5 2.632mb +0.64% 304.017241μs -1.96% ±0.57% -73.54%
HighlighterBench benchParse javascript 100 5 2.298mb +0.73% 267.841057μs -0.08% ±0.68% +253.72%
HighlighterBench benchParse json 100 5 2.272mb +0.74% 236.199178μs -0.58% ±0.71% -61.85%
HighlighterBench benchParse kotlin 100 5 2.523mb +0.67% 276.063170μs -3.89% ±0.77% -62.45%
HighlighterBench benchParse markdown 100 5 2.217mb +0.76% 73.375323μs -6.04% ±0.64% -66.67%
HighlighterBench benchParse nginx 100 5 2.281mb +0.74% 261.453973μs -0.32% ±0.49% +67.66%
HighlighterBench benchParse php 100 5 2.579mb +0.65% 763.152446μs -1.33% ±0.58% +82.55%
HighlighterBench benchParse python 100 5 2.474mb +0.68% 429.492055μs +1.83% ±0.53% +90.02%
HighlighterBench benchParse ruby 100 5 2.582mb +0.65% 239.806791μs +1.47% ±1.24% +193.60%
HighlighterBench benchParse rust 100 5 2.459mb +0.68% 188.857476μs -0.78% ±0.60% +7.35%
HighlighterBench benchParse scss 100 5 2.243mb +0.75% 179.999452μs -0.57% ±0.68% -33.97%
HighlighterBench benchParse sema 100 5 2.412mb +0.70% 230.186654μs +1.59% ±1.03% +351.52%
HighlighterBench benchParse sql 100 5 2.241mb +0.75% 157.765851μs +0.48% ±0.68% +72.25%
HighlighterBench benchParse svelte 100 5 2.523mb +0.67% 1,059.043425μs -4.93% ±0.73% +13.81%
HighlighterBench benchParse swift 100 5 2.289mb +0.73% 250.698356μs +0.77% ±0.78% +40.36%
HighlighterBench benchParse terminal 100 5 2.237mb +0.75% 182.705988μs -0.03% ±0.76% -8.08%
HighlighterBench benchParse terraform 100 5 2.241mb +0.75% 172.690744μs -1.32% ±0.22% -62.40%
HighlighterBench benchParse toml 100 5 2.213mb +0.76% 129.787397μs -0.85% ±0.37% -61.29%
HighlighterBench benchParse typescript 100 5 2.675mb +3.08% 252.108082μs -1.21% ±0.71% -21.94%
HighlighterBench benchParse txt 100 5 2.170mb +0.78% 7.243268μs -15.46% ±1.85% +51.54%
HighlighterBench benchParse twig 100 5 19.359mb +0.43% 1,537.154344μs -5.39% ±1.00% +34.31%
HighlighterBench benchParse vue 100 5 2.531mb +0.66% 414.861742μs -2.18% ±0.75% -21.52%
HighlighterBench benchParse xml 100 5 2.248mb +0.75% 175.315166μs -0.99% ±0.28% -58.27%
HighlighterBench benchParse yaml 100 5 2.303mb +0.73% 318.080333μs -0.62% ±0.62% +41.60%
HighlighterBench benchParse jsx 100 5 2.241mb +0.75% 50.451879μs -2.72% ±1.82% +46.42%
HighlighterBench benchParse tsx 100 5 2.398mb +0.70% 78.920294μs -0.86% ±0.72% -49.29%

Generated by phpbench against commit 8297742

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.

🟡 Changes recommended

The filter rejects valid block-transition markers, and repeated rejected candidates cause quadratic scanning.

2 open issues
What changed in this PR

This PR addresses #240 by filtering accidental emphasis, strong, and blur marker pairs in ordinary code through their shared injection trait.

Changes:

  • Adds brace-balance checks to reject accidental marker matches.
  • Continues searching after rejected candidates to find later real markers.
  • Adds tests for ordinary-code collisions, marker recovery, and unbalanced braces.
File Description
tests/​Languages/​Base/​HighlightMarkersTest.php Adds collision and marker-preservation regression cases.
src/​Languages/​Base/​IsHighlightInjection.php Filters marker candidates using brace balance and retries after rejected matches.

Review effort: Balanced

Comment thread src/Languages/Base/IsHighlightInjection.php Outdated
Comment thread src/Languages/Base/IsHighlightInjection.php Outdated
@brendt
brendt merged commit 5cb801a into tempestphp:main Oct 27, 2026
5 checks passed
@brendt

brendt commented Oct 27, 2026

Copy link
Copy Markdown
Member

Thanks!

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.

Emphasis markers {_ … _} match ordinary code

3 participants