Compact list blocks: a sub-block no longer loosens a tight list#227
Draft
dereuromark wants to merge 2 commits into
Draft
Compact list blocks: a sub-block no longer loosens a tight list#227dereuromark wants to merge 2 commits into
dereuromark wants to merge 2 commits into
Conversation
A blank line is still required to START a block inside a list item (block recognition and the uniformity principle are unchanged), but that blank line no longer forces the list LOOSE when the indented content opens a block (sub-list, block quote, fenced code, fenced div, heading, table). Only a genuine second prose paragraph, or a blank line between items, makes the list loose. Result: an item can carry a sub-block while staying tight (lead text inline, no <p> ceremony) -- the common case for checklists with notes, steps with code, etc. This changes only the tight/loose RENDERING, never the block structure, so it does not touch uniformity. It is a deliberate divergence from canonical djot (which renders these lists loose); the official test suite stays green because it does not pin these particular loose cases. - BlockParser: the "blank + indented content" loose guard is broadened from "is a list marker" to "opens any structured block" (reuses startsNewBlockSignificant). Between-items loosening is unchanged. - Renderer already strips the lead <p> for tight items, so no renderer change.
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## master #227 +/- ##
=========================================
Coverage 91.87% 91.87%
- Complexity 3512 3513 +1
=========================================
Files 105 105
Lines 9944 9946 +2
=========================================
+ Hits 9136 9138 +2
Misses 808 808 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
This was referenced Jun 6, 2026
Add a 'Compact List Blocks' section explaining that a sub-block after a blank line keeps the list tight (vs loose in canonical djot), with a before/after example and the still-loose cases (second prose paragraph, blank between items). Flagged as a djot-php divergence.
Contributor
Author
|
This would be the ideal solution to tight lists. |
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.
The problem: you can't have a tight list item that contains a block
djot has two rules that collide:
<p>wrappers + vertical spacing).So any list whose items carry a sub-block is forced loose. There is no way to write a compact checklist-with-notes or steps-with-code. That's the itch this scratches.
The change
A blank line is still required to start the block (block recognition and the uniformity principle are unchanged). It just no longer loosens the list when the indented content opens a block. Loose is still triggered by a genuine second prose paragraph, or a blank line between items.
Net effect, on one example:
- One > QuoteOnly the lead
<p>placement changes — the block structure is identical.Showcase — where it comes in handy
Checklist with a note per task (deploy runbook, review checklist):
→ a tight task list; the note sits with its item instead of the whole list blowing out to loose/spaced.
Steps with a code block (install / build instructions):
The code attaches to its step, list stays tight. Same for a
:::noteadmonition, a sub-table, or a quote under each item.What is deliberately not changed (still loose, correctly)
A real second paragraph in an item:
→ stays loose (
<p>First point.</p>+<p>…explanation.</p>). And a blank line between items still loosens. Only blank-then-block is affected.Why this respects uniformity (the djot principle)
Uniformity is about block structure — "a single paragraph stays a single paragraph when embedded." This change touches only tight-vs-loose rendering (whether the lead paragraph prints its
<p>tag), which djot already varies by tight/loose. No block is recognized differently; embedding is unchanged. So it does not violate the principle that motivated djot.Divergence (honest)
Canonical djot renders the showcase lists loose; this renders them tight. The official test suite passes because it does not pin these specific loose-list-with-sub-block cases, but this is a behavioral difference from djot.js on those inputs. Hence: draft, for discussion on whether this belongs in djot-php (always-on), behind a flag, or proposed upstream.
Implementation
One guard broadened in
BlockParser: the "blank line + indented content" loosening check goes from "is a list marker" to "opens any structured block" (reusingstartsNewBlockSignificant). Between-items loosening untouched; the renderer already strips the lead<p>for tight items, so no renderer change. NewCompactListBlocksTest; one round-trip test updated to the tight output.