Skip to content

Add LineBlockDivExtension (::: | fenced line blocks)#243

Merged
dereuromark merged 3 commits into
masterfrom
feature/line-block-div-extension
Jun 12, 2026
Merged

Add LineBlockDivExtension (::: | fenced line blocks)#243
dereuromark merged 3 commits into
masterfrom
feature/line-block-div-extension

Conversation

@dereuromark

@dereuromark dereuromark commented Jun 12, 2026

Copy link
Copy Markdown
Contributor

Summary

Adds LineBlockDivExtension: a fenced line block written as a ::: div whose only class token is a pipe - ::: |. Produces the same line-block div as the existing |-prefixed form, without prefixing every line.

::: |
The limerick packs laughs anatomical
  Into space that is quite economical.

But the good ones I've seen
  So seldom are clean
:::

Inside the fence: soft line breaks become hard breaks (<br>), leading whitespace is preserved, a blank line separates stanzas (each becomes its own paragraph), and inline djot still parses normally.

Indentation preserved in every format

Leading whitespace is kept as a non-breaking space, so the indent survives without any CSS - and it composes with nesting. An indented poem inside a list item:

- A poem in a list:

  ::: |
  Roses are red,
    Violets are blue,
    Sugar is sweet,
  And so are you.
  :::

renders (HTML):

<ul>
<li>
<p>A poem in a list:</p>
<div class="line-block">
<p>Roses are red,<br>
&nbsp;&nbsp;Violets are blue,<br>
&nbsp;&nbsp;Sugar is sweet,<br>
And so are you.</p>
</div>
</li>
</ul>

Per format: &nbsp; in HTML, a real non-breaking space (U+00A0) in Markdown - which keeps the indent through a round-trip re-render and never trips the indented-code-block rule - and an ordinary space in plain-text / ANSI. Tabs expand to four-column stops.

Why

Per djot#29: a leading | on every line (Pandoc-style) can be confused with pipe tables and is awkward to edit; an English-keyword div class (::: verse) was undesirable. A language-neutral | marker on the div opener sidesteps both. The pipe is consumed as the marker, so the output is a line-block div, never a literal class="|" - and because | is not a meaningful class, intercepting it cannot collide with real usage.

Design

  • Parsing is a pure extension. Registered via addBlockPattern, which runs before the core div parser, so ::: | is intercepted before it could become a class="|" div. Reuses the core LineBlock node and the core FencedBlockParser detectors so code-fence/closer recognition matches the built-in div parser. Composes with blockquotes and list items.
  • Indentation uses the existing internal non-breaking-space placeholder (U+E000) - a private-use sentinel, so it never collides with a literal U+00A0 in the author's text. The HTML escaper already turns it into &nbsp;; the non-HTML renderers convert it as their final output step (Markdown -> U+00A0, plain/ANSI -> space). This also fixes a pre-existing case where the escaped-space placeholder leaked into non-HTML output.
  • Opt-in: $converter->addExtension(new LineBlockDivExtension());

Docs

  • docs/extensions/index.md: new LineBlockDivExtension section + table entry.
  • docs/guide/syntax.md: cross-reference from the Line Blocks section.

Notes

Draft - proposal-stage feature tracking djot#29. Class name settled as line-block; stanza handling (blank line = separate paragraph) open to review.

A `:::` div whose only class token is a pipe is treated as a line block:
soft breaks become hard breaks, leading whitespace is preserved, and a
blank line separates stanzas. It produces the same `line-block` div as the
`|`-prefixed form, without prefixing every line - convenient for verse,
addresses, lyrics, and signature blocks.

Pure extension, no core changes: the block pattern runs before the core div
parser, so `::: |` is intercepted before it could become a `class="|"` div.
Reuses the core LineBlock node and its renderers, and the core
FencedBlockParser detectors so code-fence and closer recognition match the
built-in div parser. Composes with nesting (blockquotes, list items).

Tracks djot#29.
@codecov

codecov Bot commented Jun 12, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 98.95833% with 1 line in your changes missing coverage. Please review.
✅ Project coverage is 92.04%. Comparing base (9a51f5a) to head (7f69890).

Files with missing lines Patch % Lines
src/Extension/LineBlockDivExtension.php 98.88% 1 Missing ⚠️
Additional details and impacted files
@@             Coverage Diff              @@
##             master     #243      +/-   ##
============================================
+ Coverage     91.89%   92.04%   +0.14%     
- Complexity     3532     3559      +27     
============================================
  Files           106      107       +1     
  Lines          9985    10078      +93     
============================================
+ Hits           9176     9276     +100     
+ Misses          809      802       -7     

☔ View full report in Codecov by Harness.
📢 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.

Leading whitespace in a `::: |` block now survives the browser's whitespace
collapsing without any CSS: it is emitted via the internal non-breaking-space
placeholder (U+E000, a private-use sentinel that never collides with a literal
U+00A0 in the author's text). The HTML escaper already renders it as `&nbsp;`;
the Markdown / plain-text / ANSI renderers now collapse it to an ordinary space
as their final output step - which also fixes a pre-existing case where the
escaped-space placeholder leaked into non-HTML output.

Tabs expand to four-column stops. A `cssIndent` option keeps raw spaces instead
for an HTML + CSS (`white-space: pre-wrap`) workflow.
@dereuromark dereuromark marked this pull request as ready for review June 12, 2026 13:51
Drop the `cssIndent` option: the default placeholder now preserves indentation
faithfully in every format, so the raw-spaces-for-CSS mode only added a caveat
(and a non-HTML-only variant would need a fragile render hook). A custom
extension can cover that niche if anyone needs it.

Markdown now keeps the indent as a real non-breaking space (U+00A0) rather than
an ordinary space. Markdown is a re-parseable round-trip format, so the nbsp
survives a re-render as `&nbsp;` and is never mistaken for an indented code
block. Plain-text and ANSI stay on an ordinary space.
@dereuromark

Copy link
Copy Markdown
Contributor Author

Merging without release for demo in sandbox for us for now.

Net-side effect of fixing the NBSP transformation affects all renderers => positive

@dereuromark dereuromark merged commit 6818161 into master Jun 12, 2026
6 checks passed
@dereuromark dereuromark deleted the feature/line-block-div-extension branch June 12, 2026 14:12
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.

1 participant