Skip to content

Add line numbers and line highlighting for code blocks#82

Closed
dereuromark wants to merge 1 commit intomasterfrom
feature/code-block-line-numbers
Closed

Add line numbers and line highlighting for code blocks#82
dereuromark wants to merge 1 commit intomasterfrom
feature/code-block-line-numbers

Conversation

@dereuromark
Copy link
Contributor

Summary

  • Add VitePress-inspired syntax for code block line numbers and line highlighting
  • Shorthand # syntax for line numbers (cleaner than :line-numbers)
  • Support for line number offset with #=N
  • Support for line highlighting with {1,3-5,7} ranges
  • All features can be combined: ```php #=5 {2,4}

Syntax Examples

Syntax Result
```php Plain code block
```php # With line numbers
```php #=5 Line numbers starting at 5
```php {3,5-7} Highlight lines, no numbers
```php # {3,5-7} Line numbers + highlighting
```php #=5 {3,5-7} Numbers from 5 + highlighting

HTML Output

When line numbers or highlighting are enabled, the renderer:

  • Adds line-numbers class to <pre> when line numbers enabled
  • Adds data-start="N" attribute when start offset != 1
  • Adds has-highlighted-lines class when highlighting used
  • Wraps each line in <span class="line" data-line="N">
  • Adds highlighted class to highlighted line spans

Example output:

<pre class="line-numbers has-highlighted-lines" data-start="5"><code class="language-php"><span class="line" data-line="5">$foo = 1;</span>
<span class="line highlighted" data-line="6">$bar = 2;</span>
<span class="line" data-line="7">$baz = 3;</span>
</code></pre>

CSS can then style line numbers via counters and highlighted lines with background colors.

Adds VitePress-inspired syntax for code blocks:
- `php #` - show line numbers
- `php #=5` - line numbers starting at 5
- `php {2,4-6}` - highlight specific lines
- `php # {2,4}` - combine both features

HTML output includes:
- `line-numbers` class on pre element when enabled
- `data-start` attribute when start offset != 1
- `has-highlighted-lines` class when highlighting used
- Each line wrapped in span.line with data-line attribute
- `highlighted` class added to highlighted lines
@codecov
Copy link

codecov bot commented Feb 9, 2026

Codecov Report

❌ Patch coverage is 87.50000% with 13 lines in your changes missing coverage. Please review.
✅ Project coverage is 93.72%. Comparing base (9b26950) to head (0bdc767).

Files with missing lines Patch % Lines
src/Node/Block/CodeBlock.php 50.00% 6 Missing ⚠️
src/Renderer/HtmlRenderer.php 85.71% 6 Missing ⚠️
src/Parser/Block/FencedBlockParser.php 97.67% 1 Missing ⚠️
Additional details and impacted files
@@             Coverage Diff              @@
##             master      #82      +/-   ##
============================================
- Coverage     93.85%   93.72%   -0.13%     
- Complexity     2115     2149      +34     
============================================
  Files            77       77              
  Lines          5675     5773      +98     
============================================
+ Hits           5326     5411      +85     
- Misses          349      362      +13     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@dereuromark dereuromark added extra beyond standard/specs RFC labels Feb 9, 2026
@dereuromark dereuromark marked this pull request as draft February 10, 2026 16:00
dereuromark added a commit to php-collective/wp-djot that referenced this pull request Feb 24, 2026
With php-collective/djot-php#82, the core library handles:
- Line numbers syntax (# and #=N)
- Line highlighting syntax ({1,3-5})
- Wrapping lines in <span class="line"> elements
- Adding "highlighted" class to highlighted lines

This removes redundant processing from wp-djot:
- PHP: Remove pre/post processing for # and {lines} (keep filename only)
- JS: Remove addLineHighlighting() function

wp-djot now only handles its unique features:
- Filename headers [filename.php]
- Inline markers (// [!code ++], etc.)
- Copy button
- Line numbers gutter (visual element)
@dereuromark
Copy link
Contributor Author

Closing this PR as the functionality is better handled by a dedicated syntax highlighter.

After further consideration, line numbers and line highlighting should be handled by Phiki/Torchlight Engine rather than by djot-php:

  1. Separation of concerns - djot-php should focus on parsing Djot markup, not code rendering
  2. Feature richness - Torchlight provides much more: diff markers, focus mode, collapse, annotations via [tl! ...] comments
  3. Theme support - Torchlight uses VS Code themes for consistent styling
  4. Better architecture - Extensions can hook into djot-php's render.code_block event to use any highlighter

The wp-djot plugin now uses Torchlight Engine via a custom extension:

  • torchlight/engine added as composer dependency
  • TorchlightExtension hooks into render.code_block event
  • All highlighting/line numbers/annotations handled by Torchlight

See: https://github.com/torchlight-api/engine

@dereuromark dereuromark closed this Mar 2, 2026
@dereuromark dereuromark deleted the feature/code-block-line-numbers branch March 2, 2026 08:21
dereuromark added a commit to php-collective/wp-djot that referenced this pull request Mar 3, 2026
* Add VitePress-style code block features

- Diff highlighting with +/- symbols (// [!code ++], // [!code --])
- Focus mode to dim non-focused lines (// [!code focus])
- Error/warning highlights with ✗/⚠ symbols (// [!code error], // [!code warning])
- Inline highlight marker (// [!code highlight])
- Filename headers ([filename.php] syntax)
- Copy button on hover
- CSS custom properties for theme customization
- Fix line number sync when combining features

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* Simplify by relying on djot-php for line numbers/highlighting

With php-collective/djot-php#82, the core library handles:
- Line numbers syntax (# and #=N)
- Line highlighting syntax ({1,3-5})
- Wrapping lines in <span class="line"> elements
- Adding "highlighted" class to highlighted lines

This removes redundant processing from wp-djot:
- PHP: Remove pre/post processing for # and {lines} (keep filename only)
- JS: Remove addLineHighlighting() function

wp-djot now only handles its unique features:
- Filename headers [filename.php]
- Inline markers (// [!code ++], etc.)
- Copy button
- Line numbers gutter (visual element)

* Fix filename marker to preserve line numbers

The previous approach injected a marker at the START of code content,
which caused djot-php to count it as line 1 and shift all line numbers.

New approach:
- Inject marker at the END of code content
- Store filenames in a property array during pre-processing
- Remove marker line and add data-filename in post-processing
- Line numbers now correctly match user's #=N specification

* Fix line number alignment using CSS ::before with data-line

Problem: JS-generated gutter element could drift out of sync with code lines
due to theme typography differences.

Solution: Use CSS ::before pseudo-element on each .line span with
content: attr(data-line). This guarantees perfect alignment since
the line number is attached to its corresponding line element.

Changes:
- CSS: Use ::before with attr(data-line) instead of separate gutter
- CSS: Consistent font-size: inherit for all .line spans
- JS: Remove addLineNumbers(), syncLineNumberHeights() functions
- JS: Remove resize listener and gutter-related code
- JS: Add data-line attribute when processing inline markers

* Fix whitespace between code lines

The newlines between <span class='line'> elements were creating extra
vertical space. Fixed by setting font-size: 0 on the code element
(eliminating whitespace text nodes) and restoring proper font-size
on the .line spans.

Uses class-based selectors for browser compatibility instead of :has().

* Use flexbox instead of font-size hack for line structure

Flexbox with flex-direction: column naturally ignores whitespace
text nodes between flex items, eliminating the extra spacing without
breaking font-size inheritance for ::before pseudo-elements.

* Fix line numbers using inline flexbox

Use display: flex on each .line with ::before as the first flex item.
This keeps line numbers in the normal document flow, avoiding overflow
clipping issues with absolute positioning.

* Preserve indentation with white-space: pre

* Fix CSS line number alignment with grid layout

- Use CSS Grid for line numbers instead of flexbox for perfect alignment
- Add white-space: pre to all line spans to preserve code indentation
- Reduce grid column width to 2em and gap to 0.5em for tighter layout
- Use white-space: nowrap on line number pseudo-element

* Simplify line number CSS with absolute positioning

Remove grid/flexbox complexity that was breaking code display.
Use simple display:block for lines with absolute positioning for
line numbers in the left padding area. Much more robust.

* Remove broken font-size: 0 hack for markers

This old whitespace elimination trick was breaking the entire code display.

* Add explicit line-height to code block lines for consistency

* Replace custom code highlighting with Torchlight Engine

- Add torchlight/engine dependency for syntax highlighting
- Create TorchlightExtension that hooks into djot-php render events
- Remove custom CSS for line numbers, highlighting, diff, focus, etc.
- Simplify JS to only handle copy button (was 229 lines, now 73)
- Simplify CSS code block section (was 100+ lines, now 17)

Torchlight Engine (built on Phiki) handles:
- Syntax highlighting with TextMate grammars
- Line annotations: [tl! focus], [tl! ++], [tl! --], etc.
- Line numbers (withGutter option)
- All styling via inline styles from VS Code themes

* Add line numbers support via djot syntax

Parse '# or '#=N' from language string to enable line numbers:
- ``` php #   -> line numbers starting at 1
- ``` php #=5 -> line numbers starting at 5

Pass withGutter:true to Torchlight when line numbers requested.

* Add CSS for Torchlight line numbers spacing

* Simplify extension - use Torchlight inline annotations

Line highlighting and other features use Torchlight's inline annotation
syntax which works reliably:

- // [tl! highlight] - highlight line
- // [tl! focus] - focus line (dim others)
- // [tl! ++] - diff add (green)
- // [tl! --] - diff remove (red)

Fence syntax still supported for line numbers:
- ``` php #    - with line numbers
- ``` php #=5  - line numbers starting at 5

* Fix line number offset using inline torchlight options

The Torchlight Engine Options API resets options internally when
calling codeToHtml(). Use inline `// torchlight! {"lineNumbersStart": N}`
comment instead, which is processed from within the code block.

This fixes the #=42 syntax for custom line number starts.

* Add Code Annotations panel and update documentation

- Add editor-torchlight.js with block Inspector Controls for quick
  annotation insertion (highlight, focus, diff)
- Update DjotBlock to enqueue the new editor script
- Update docs/syntax.md with Torchlight annotation syntax
- Update CHANGELOG with Torchlight integration notes
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

extra beyond standard/specs RFC

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant