diff --git a/docs/reference/enhancements.md b/docs/reference/enhancements.md index 70b1ab8..5143024 100644 --- a/docs/reference/enhancements.md +++ b/docs/reference/enhancements.md @@ -1008,7 +1008,7 @@ The `^ caption text` syntax adds captions to images, tables, and block quotes: - `^ ` marker at start of line triggers caption parsing - Can interrupt paragraphs (no blank line required before caption) - Blank line between element and caption is allowed for readability -- Multi-line captions supported (continues until blank line or new block) +- Multi-line captions supported (continues until blank line or new block; an adjacent `^ ` line is caption text with its caret preserved) - Full roundtrip support in HtmlToDjot converter **Multi-line caption example:** diff --git a/src/Parser/BlockParser.php b/src/Parser/BlockParser.php index 35cb232..ab8bfc5 100644 --- a/src/Parser/BlockParser.php +++ b/src/Parser/BlockParser.php @@ -3728,7 +3728,7 @@ protected function tryParseCaption(Node $parent, array $lines, int $start): ?int break; } // Stop at block-level elements - if ($this->startsNewBlock($nextLine)) { + if ($this->startsNewBlock($nextLine) && !preg_match('/^\^ /', $nextLine)) { break; } // Stop at new table diff --git a/tests/TestCase/DjotConverterTest.php b/tests/TestCase/DjotConverterTest.php index 96be866..aa42b4d 100644 --- a/tests/TestCase/DjotConverterTest.php +++ b/tests/TestCase/DjotConverterTest.php @@ -380,6 +380,15 @@ public function testTableCaptionWithBlankLine(): void $this->assertStringContainsString('Caption after blank line', $result); } + public function testBlankSeparatedSecondCaptionReplacesTheFirst(): void + { + $djot = "| A | B |\n|---|---|\n| 1 | 2 |\n^ First\n\n^ Second"; + $expected = "\n\n\n\n\n\n" + . "\n\n\n\n
Second
AB
12
\n"; + + $this->assertSame($expected, $this->converter->convert($djot)); + } + public function testTableCaptionMultiline(): void { $djot = "| A | B |\n|---|---|\n| 1 | 2 |\n^ This is a long caption\nthat continues on the next line"; @@ -390,6 +399,41 @@ public function testTableCaptionMultiline(): void $this->assertStringContainsString("This is a long caption\nthat continues on the next line", $result); } + public function testAdjacentCaptionMarkerIsLiteralTableCaptionText(): void + { + $djot = "| A | B |\n|---|---|\n| 1 | 2 |\n^ First\n^ Second"; + $expected = "\n\n\n\n\n\n" + . "\n\n\n\n
First\n^ Second
AB
12
\n"; + + $this->assertSame($expected, $this->converter->convert($djot)); + } + + public function testAdjacentCaptionMarkerIsLiteralImageCaptionText(): void + { + $djot = "![alt](image.png)\n^ First\n^ Second"; + $expected = "
\n\"alt\"
First\n^ Second
\n
\n"; + + $this->assertSame($expected, $this->converter->convert($djot)); + } + + public function testAdjacentCaptionMarkerIsLiteralBlockquoteCaptionText(): void + { + $djot = "> q\n^ First\n^ Second"; + $expected = "
\n
\n

q

\n
\n
First\n^ Second
\n" + . "
\n"; + + $this->assertSame($expected, $this->converter->convert($djot)); + } + + public function testTwoCaptionedTablesKeepTheirOwnCaptions(): void + { + $djot = "| A |\n|---|\n| 1 |\n^ First\n\n| B |\n|---|\n| 2 |\n^ Second"; + $expected = "\n\n\n\n\n\n\n\n
First
A
1
\n" + . "\n\n\n\n\n\n\n\n
Second
B
2
\n"; + + $this->assertSame($expected, $this->converter->convert($djot)); + } + public function testReferenceLink(): void { $djot = "[Example][ex]\n\n[ex]: https://example.com";