diff --git a/Parsedown.php b/Parsedown.php index b3aeedbc4..b5fb584cc 100644 --- a/Parsedown.php +++ b/Parsedown.php @@ -524,13 +524,31 @@ protected function blockHeader($Line) protected function blockList($Line) { - list($name, $pattern) = $Line['text'][0] <= '-' ? array('ul', '[*+-]') : array('ol', '[0-9]+[.]'); + list($name, $pattern) = $Line['text'][0] <= '-' ? array('ul', '[*+-]') : array('ol', '[0-9]{1,9}[.\)]'); - if (preg_match('/^('.$pattern.'[ ]+)(.*)/', $Line['text'], $matches)) + if (preg_match('/^('.$pattern.'([ ]+|$))(.*)/', $Line['text'], $matches)) { + $contentIndent = strlen($matches[2]); + + if ($contentIndent >= 5) + { + $contentIndent -= 1; + $matches[1] = substr($matches[1], 0, -$contentIndent); + $matches[3] = str_repeat(' ', $contentIndent) . $matches[3]; + } + elseif ($contentIndent === 0) + { + $matches[1] .= ' '; + } + $Block = array( 'indent' => $Line['indent'], 'pattern' => $pattern, + 'data' => array( + 'type' => $name, + 'marker' => $matches[1], + 'markerType' => ($name === 'ul' ? strstr($matches[1], ' ', true) : substr(strstr($matches[1], ' ', true), -1)), + ), 'element' => array( 'name' => $name, 'handler' => 'elements', @@ -539,7 +557,7 @@ protected function blockList($Line) if($name === 'ol') { - $listStart = stristr($matches[0], '.', true); + $listStart = ltrim(strstr($matches[1], $Block['data']['markerType'], true), '0') ?: '0'; if($listStart !== '1') { @@ -550,9 +568,7 @@ protected function blockList($Line) $Block['li'] = array( 'name' => 'li', 'handler' => 'li', - 'text' => array( - $matches[2], - ), + 'text' => !empty($matches[3]) ? array($matches[3]) : array(), ); $Block['element']['text'] []= & $Block['li']; @@ -563,7 +579,28 @@ protected function blockList($Line) protected function blockListContinue($Line, array $Block) { - if ($Block['indent'] === $Line['indent'] and preg_match('/^'.$Block['pattern'].'(?:[ ]+(.*)|$)/', $Line['text'], $matches)) + if (isset($Block['interrupted']) and empty($Block['li']['text'])) + { + return null; + } + + $requiredIndent = ($Block['indent'] + strlen($Block['data']['marker'])); + + if ( + $Line['indent'] < $requiredIndent + and + ( + ( + $Block['data']['type'] === 'ol' + and preg_match('/^[0-9]+'.preg_quote($Block['data']['markerType']).'(?:[ ]+(.*)|$)/', $Line['text'], $matches) + ) + or + ( + $Block['data']['type'] === 'ul' + and preg_match('/^'.preg_quote($Block['data']['markerType']).'(?:[ ]+(.*)|$)/', $Line['text'], $matches) + ) + ) + ) { if (isset($Block['interrupted'])) { @@ -578,6 +615,8 @@ protected function blockListContinue($Line, array $Block) $text = isset($matches[1]) ? $matches[1] : ''; + $Block['indent'] = $Line['indent']; + $Block['li'] = array( 'name' => 'li', 'handler' => 'li', @@ -590,31 +629,38 @@ protected function blockListContinue($Line, array $Block) return $Block; } + elseif ($Line['indent'] < $requiredIndent and $this->blockList($Line)) + { + return null; + } if ($Line['text'][0] === '[' and $this->blockReference($Line)) { return $Block; } - if ( ! isset($Block['interrupted'])) + if ($Line['indent'] >= $requiredIndent) { - $text = preg_replace('/^[ ]{0,4}/', '', $Line['body']); + if (isset($Block['interrupted'])) + { + $Block['li']['text'] []= ''; + + unset($Block['interrupted']); + } + + $text = substr($Line['body'], $requiredIndent); $Block['li']['text'] []= $text; return $Block; } - if ($Line['indent'] > 0) + if ( ! isset($Block['interrupted'])) { - $Block['li']['text'] []= ''; - - $text = preg_replace('/^[ ]{0,4}/', '', $Line['body']); + $text = preg_replace('/^[ ]{0,'.$requiredIndent.'}/', '', $Line['body']); $Block['li']['text'] []= $text; - unset($Block['interrupted']); - return $Block; } } diff --git a/test/data/deeply_nested_list.html b/test/data/deeply_nested_list.html index d2c7e5acc..bd2eb7f38 100644 --- a/test/data/deeply_nested_list.html +++ b/test/data/deeply_nested_list.html @@ -9,4 +9,32 @@
  • li
  • li
  • + +
    + +
    + \ No newline at end of file diff --git a/test/data/deeply_nested_list.md b/test/data/deeply_nested_list.md index 76b7552d8..82f73b817 100644 --- a/test/data/deeply_nested_list.md +++ b/test/data/deeply_nested_list.md @@ -3,4 +3,24 @@ - li - li - li -- li \ No newline at end of file +- li + +--- + +- level 1 + - level 2 + - level 3 + - level 4 + - level 5 + +--- + +- a + - b + - c + - d + - e + - f + - g + - h +- i \ No newline at end of file diff --git a/test/data/unordered_list.html b/test/data/unordered_list.html index cd95567b7..6ed70a690 100644 --- a/test/data/unordered_list.html +++ b/test/data/unordered_list.html @@ -2,9 +2,21 @@
  • li
  • li
  • -

    mixed markers:

    +

    mixed unordered markers:

    + + \ No newline at end of file + +

    mixed ordered markers:

    +
      +
    1. starting at 1, list one
    2. +
    3. number 2, list one
    4. +
    +
      +
    1. starting at 3, list two
    2. +
    \ No newline at end of file diff --git a/test/data/unordered_list.md b/test/data/unordered_list.md index cf62c99f2..c1b8640cf 100644 --- a/test/data/unordered_list.md +++ b/test/data/unordered_list.md @@ -1,8 +1,14 @@ - li - li -mixed markers: +mixed unordered markers: * li + li -- li \ No newline at end of file +- li + +mixed ordered markers: + +1. starting at 1, list one +2. number 2, list one +3) starting at 3, list two \ No newline at end of file