diff --git a/phpcs.xml b/phpcs.xml
index 3cf4581..759198c 100644
--- a/phpcs.xml
+++ b/phpcs.xml
@@ -8,7 +8,10 @@
*/vendor/*
-
+
+
+
+
diff --git a/src/Parser/BlockParser.php b/src/Parser/BlockParser.php
index 3483f53..7c8af24 100644
--- a/src/Parser/BlockParser.php
+++ b/src/Parser/BlockParser.php
@@ -1500,6 +1500,14 @@ protected function tryParseList(Node $parent, array $lines, int $start): ?int
if ($itemInfo !== null && $itemInfo['type'] === $listInfo['type'] && $itemInfo['marker'] === $listInfo['marker'] && $sameStyle) {
break;
}
+ // After a blank line, content dropping back to base indent
+ // starts a new block outside the list - let parent handle it.
+ if ($sawBlankLine) {
+ $lastItemHadBlankAfter = true;
+ $brokeForParentContent = true;
+
+ break;
+ }
// Content at base indent that's not a matching list marker
// Check if it's a block element - if so, end list content collection
// Use isBlockElementStart() which detects blocks regardless of mode
diff --git a/tests/TestCase/Extension/HeadingReferenceExtensionTest.php b/tests/TestCase/Extension/HeadingReferenceExtensionTest.php
index 15cfcc6..ef5ec00 100644
--- a/tests/TestCase/Extension/HeadingReferenceExtensionTest.php
+++ b/tests/TestCase/Extension/HeadingReferenceExtensionTest.php
@@ -251,7 +251,7 @@ public function testHeadingWithNoTextIsIgnored(): void
public function testUserAuthoredLinkWithMatchingPlaceholderIsNotRewritten(): void
{
- $extension = new class ('heading-ref') extends HeadingReferenceExtension {
+ $extension = new class('heading-ref') extends HeadingReferenceExtension {
protected function generatePlaceholderPrefix(): string
{
return 'collision-placeholder-';
diff --git a/tests/TestCase/NestedBlocksInListsTest.php b/tests/TestCase/NestedBlocksInListsTest.php
index a54fe4a..b635fdc 100644
--- a/tests/TestCase/NestedBlocksInListsTest.php
+++ b/tests/TestCase/NestedBlocksInListsTest.php
@@ -633,4 +633,39 @@ public function testIssue83CodeBlockCase(): void
// Should NOT be inline code
$this->assertStringNotContainsString('
', $result);
}
+
+ /**
+ * After a nested block inside a list item and a blank line, an
+ * unindented paragraph must terminate the list rather than being
+ * absorbed as a sub-item of the previous list item.
+ *
+ * @see https://github.com/php-collective/djot-php/issues/176
+ */
+ public function testIssue176UnindentedParagraphAfterNestedCodeBlockEndsList(): void
+ {
+ $djot = <<<'DJOT'
+1. Item 1
+2. Item 2
+
+ ```
+ Example
+ ```
+
+New list:
+
+* New item 1
+* New item 2
+DJOT;
+
+ $result = $this->converter->convert($djot);
+
+ $this->assertStringContainsString('', $result);
+ // The "New list:" paragraph must appear after the ordered list closes.
+ $olClose = strpos($result, '');
+ $paragraph = strpos($result, 'New list:
');
+ $this->assertNotFalse($paragraph);
+ $this->assertGreaterThan($olClose, $paragraph);
+ // And the following bullet list must be a sibling, not nested in .
+ $this->assertMatchesRegularExpression('#\s*New list:
\s*