Skip to content

Commit 9b26950

Browse files
authored
Allow fenced comments to interrupt paragraphs (#79)
Fenced comment blocks (%%%) can now interrupt paragraphs without requiring a preceding blank line. This makes comments truly "invisible" from a formatting perspective. Before this change: ``` Lorem ipsum %%% comment %%% dolor sit amet ``` Would be treated as a single paragraph with %%% as literal text. After this change: The above produces two separate paragraphs with the comment stripped. This is a special case for comments since they should not affect document formatting. Other block elements still follow the djot spec and require blank lines to interrupt paragraphs.
1 parent f5f043b commit 9b26950

File tree

3 files changed

+77
-0
lines changed

3 files changed

+77
-0
lines changed

docs/syntax.md

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -475,6 +475,29 @@ Still inside the comment
475475
> **Note:** This is a djot-php extension, not part of the official Djot specification.
476476
> See [discussion](https://github.com/jgm/djot/issues/67) for background.
477477
478+
Fenced comment blocks are block-level elements that break paragraph continuity.
479+
Unlike other block elements, fenced comments can interrupt paragraphs without
480+
requiring a preceding blank line - making them truly "invisible" from a formatting
481+
perspective:
482+
483+
**Input:**
484+
```djot
485+
Lorem ipsum
486+
%%%
487+
comment
488+
%%%
489+
dolor sit amet
490+
```
491+
492+
**Output:**
493+
```html
494+
<p>Lorem ipsum</p>
495+
<p>dolor sit amet</p>
496+
```
497+
498+
This produces two separate paragraphs. For comments that should not interrupt
499+
paragraph flow (keeping text in the same paragraph), use inline comments (`{% ... %}`).
500+
478501
### Line Blocks
479502

480503
Preserve line breaks using `|` at the start of each line. Useful for poetry or addresses.

src/Parser/BlockParser.php

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2922,6 +2922,12 @@ protected function startsNewBlock(string $line): bool
29222922
return true;
29232923
}
29242924

2925+
// Fenced comments `%%%` can always interrupt paragraphs
2926+
// Comments should be invisible and not require extra formatting
2927+
if ($line[0] === '%' && isset($line[1], $line[2]) && $line[1] === '%' && $line[2] === '%') {
2928+
return true;
2929+
}
2930+
29252931
// In significantNewlines mode, block elements can interrupt paragraphs
29262932
if ($this->significantNewlines) {
29272933
return $this->startsNewBlockSignificant($line);
@@ -2973,6 +2979,9 @@ protected function startsNewBlockSignificant(string $line): bool
29732979
case ':':
29742980
// Fenced divs: :{3,}
29752981
return isset($line[1], $line[2]) && $line[1] === ':' && $line[2] === ':';
2982+
case '%':
2983+
// Fenced comments: %{3,}
2984+
return isset($line[1], $line[2]) && $line[1] === '%' && $line[2] === '%';
29762985
default:
29772986
// Only 1. or 1) can interrupt paragraphs (CommonMark rule)
29782987
// Prevents "1985. That year..." from becoming a list

tests/TestCase/DjotConverterTest.php

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -683,6 +683,51 @@ public function testFencedCommentClosingNeedsMatchingLength(): void
683683
$this->assertStringNotContainsString('still', $result);
684684
}
685685

686+
public function testFencedCommentBreaksParagraphContinuity(): void
687+
{
688+
// Fenced comments are block-level elements that break paragraph continuity
689+
// Text before and after becomes two separate paragraphs
690+
$djot = "Lorem ipsum\n\n%%%\ncomment\n%%%\n\ndolor sit amet";
691+
692+
$result = $this->converter->convert($djot);
693+
694+
// Should produce two separate paragraphs
695+
$this->assertStringContainsString('<p>Lorem ipsum</p>', $result);
696+
$this->assertStringContainsString('<p>dolor sit amet</p>', $result);
697+
$this->assertStringNotContainsString('comment', $result);
698+
699+
// Should NOT be a single paragraph
700+
$this->assertStringNotContainsString('Lorem ipsum dolor', $result);
701+
}
702+
703+
public function testFencedCommentInterruptsParagraph(): void
704+
{
705+
// Fenced comments can interrupt paragraphs without requiring blank lines
706+
// This makes comments truly "invisible" from a formatting perspective
707+
$djot = "Lorem ipsum\n%%%\ncomment\n%%%\ndolor sit amet";
708+
709+
$result = $this->converter->convert($djot);
710+
711+
// Should produce two separate paragraphs with comment stripped
712+
$this->assertStringContainsString('<p>Lorem ipsum</p>', $result);
713+
$this->assertStringContainsString('<p>dolor sit amet</p>', $result);
714+
$this->assertStringNotContainsString('comment', $result);
715+
$this->assertStringNotContainsString('%%%', $result);
716+
}
717+
718+
public function testFencedCommentWithBlankLinesAlsoWorks(): void
719+
{
720+
// Also works with blank lines (traditional block element style)
721+
$djot = "Lorem ipsum\n\n%%%\ncomment\n%%%\n\ndolor sit amet";
722+
723+
$result = $this->converter->convert($djot);
724+
725+
// Comment should be recognized and stripped
726+
$this->assertStringContainsString('<p>Lorem ipsum</p>', $result);
727+
$this->assertStringContainsString('<p>dolor sit amet</p>', $result);
728+
$this->assertStringNotContainsString('comment', $result);
729+
}
730+
686731
// Edge cases from official Djot test suite
687732

688733
public function testEmphasisIntraword(): void

0 commit comments

Comments
 (0)