Repository navigation
Conversation
Benchmark ResultsComparison of Open to see the benchmark results
Generated by phpbench against commit 9c1e283 |
This was referenced Oct 20, 2026
There was a problem hiding this comment.
🟡 Changes recommended
Marker loss during injection processing and false keyword matches from whitespace masking remain unresolved.
3 open issues
What changed in this PR
This PR addresses #148 and #166 by improving highlight-marker handling around nested tokens and embedded languages.
Changes:
- Groups overlapping child tokens and allows markers inside built-in tokens.
- Tracks injection replacements to adjust existing token offsets.
- Masks markers during pattern matching and adds regression coverage.
| File | Description |
|---|---|
| tests/Tokens/GroupTokensTest.php | Tests child grouping, overflow, and embedded markers. |
| tests/Languages/Php/PhpLanguageTest.php | Updates keyword highlighting expectations. |
| tests/Languages/Base/HighlightMarkersTest.php | Adds cross-language marker and gutter tests. |
| src/Tokens/Token.php | Allows built-in tokens to contain markers. |
| src/Tokens/GroupTokens.php | Groups overlapping children and drops overflowing tokens. |
| src/ParsedInjection.php | Adds replacement-offset metadata. |
| src/IsInjection.php | Records injection replacements. |
| src/Highlighter.php | Adjusts token offsets and masks marker delimiters. |
Review effort: Balanced
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.

Fixes #148
Fixes #166
Highlight markers (
{_ _},{* *},{~ ~},{:class: :}) could duplicate text, corrupt the output (broken<span>nesting, invalid UTF-8), or throw a fatal error withwithGutter().Causes and fixes
There were three separate issues:
Overlapping children were never grouped (Fatal error when using emphasize tags around a string #148). A marker token became the direct parent of every token it covered, including tokens nested inside another child, for example a string and the SQL keywords inside it. Those children overlapped, so the text was rendered twice. This could also split the multibyte escape tokens (
❷,❸…), which is where the original "Malformed UTF-8" fatal error came from.→
GroupTokensnow groups a token's children the same way when they overlap. A token that runs past the end of its parent is dropped, like any other token that can't be contained.Offsets went stale after an injection rewrote the content (Custom classes tag breaks/errors when code contains function with a parameter (php) #166). Injections like PHP function parameters, CSS in a
styleattribute or Blade insert nested markup after the marker tokens have been created, so those tokens pointed to the wrong place (($te$test)).→
IsInjectionnow reports what it replaced throughParsedInjection::$replacements(a new optional argument, so it stays backwards compatible).Highlighteruses it to move the tokens found earlier.Markers affected pattern matching.
{_functiondidn't match thefunctionkeyword, because_is a word character, and markers inside strings or comments were ignored.→ Markers are replaced by spaces of the same length while patterns run, so offsets don't change. Pattern tokens never start or end on a marker, and any built-in token can contain a marker.
As a result, wrapping code in
{_ … _}now renders exactly like the same code without markers, wrapped in<span class="hl-em">.Tests
HighlightMarkersTest, covering both issues plus strong, blur, custom class, nested markers, markers inside strings, PHP signatures, HTML with CSS, Blade, andwithGutter(). It also checks that the "wrapped equals plain" property holds across languages.GroupTokensunit tests for children grouping, overflowing tokens and markers inside tokens.PhpLanguageTest: in{~class~} Foo {},classis now highlighted as a keyword. The old expectation reflected issue 3, and it contradictedGroupTokensTest::test_exact_overlaps, which expects a blur to contain a keyword.main.main, 521 runs produced broken output, including 16 exceptions. With this PR there are no exceptions, unbalanced spans or invalid UTF-8.Known limitation
Markers inside embedded languages are moved onto the rewritten code as long as the resulting markup stays properly nested. In the rare case where a marker would cut through a token highlighted by the embedded language (e.g. a custom class that starts in the middle of a CSS property and ends in its value), that marker is dropped rather than producing broken HTML.
Performance
No measurable difference with
mainin interleaved local runs (−0.4%, within noise). The extra work only happens when markers or custom classes are present.