From c4d4a6800dfee4026b9f62921c8c759bea73aff8 Mon Sep 17 00:00:00 2001 From: Aidan Woods Date: Tue, 11 Oct 2016 12:05:33 +0100 Subject: [PATCH 01/21] (beginning to) improve commonmark compliance:lists These changes aren't fit for merge, nor do they work correctly (yet) --- Parsedown.php | 24 +++++++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/Parsedown.php b/Parsedown.php index 4737eee2a..6c533c60a 100644 --- a/Parsedown.php +++ b/Parsedown.php @@ -509,6 +509,11 @@ protected function blockList($Line) $Block = array( 'indent' => $Line['indent'], 'pattern' => $pattern, + 'data' => array( + 'type' => $name, + 'matchText' => ($name === 'ul' ? stristr($matches[1], ' ', true) : stristr($matches[1], '.', true)), + 'rootItem' => $matches[2] + ), 'element' => array( 'name' => $name, 'handler' => 'elements', @@ -541,7 +546,19 @@ protected function blockList($Line) protected function blockListContinue($Line, array $Block) { - if ($Block['indent'] === $Line['indent'] and preg_match('/^'.$Block['pattern'].'(?:[ ]+(.*)|$)/', $Line['text'], $matches)) + if ( + ( + $Block['indent'] === $Line['indent'] + and $Block['data']['type'] === 'ol' + and preg_match('/^'.$Block['pattern'].'(?:[ ]+(.*)|$)/', $Line['text'], $matches) + ) + or + ( + $Block['indent'] === $Line['indent'] + and $Block['data']['type'] === 'ul' + and preg_match('/^'.preg_quote($Block['data']['matchText']).'(?:[ ]+(.*)|$)/', $Line['text'], $matches) + ) + ) { if (isset($Block['interrupted'])) { @@ -566,6 +583,11 @@ protected function blockListContinue($Line, array $Block) return $Block; } + elseif ($Block['indent'] === $Line['indent']) + { + echo $Block['data']['rootItem'] ."\t" . $Block['indent'] ."\t" . $Block['data']['type'] ."\t" . $Line['indent'] . "\t". $Block['data']['matchText'] ."\t" .$Line['text'] . "\n"; + return null; + } if ($Line['text'][0] === '[' and $this->blockReference($Line)) { From 06c4344a71b64b00c2fbfce4faa4befb94417ce8 Mon Sep 17 00:00:00 2001 From: Aidan Woods Date: Tue, 11 Oct 2016 13:38:47 +0100 Subject: [PATCH 02/21] Contextual limits on indentation stripping --- Parsedown.php | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/Parsedown.php b/Parsedown.php index 6c533c60a..29e5fc8cf 100644 --- a/Parsedown.php +++ b/Parsedown.php @@ -585,7 +585,6 @@ protected function blockListContinue($Line, array $Block) } elseif ($Block['indent'] === $Line['indent']) { - echo $Block['data']['rootItem'] ."\t" . $Block['indent'] ."\t" . $Block['data']['type'] ."\t" . $Line['indent'] . "\t". $Block['data']['matchText'] ."\t" .$Line['text'] . "\n"; return null; } @@ -596,7 +595,7 @@ protected function blockListContinue($Line, array $Block) if ( ! isset($Block['interrupted'])) { - $text = preg_replace('/^[ ]{0,4}/', '', $Line['body']); + $text = preg_replace('/^[ ]{0,'.($Block['indent'] + 1).'}/', '', $Line['body']); $Block['li']['text'] []= $text; @@ -607,7 +606,7 @@ protected function blockListContinue($Line, array $Block) { $Block['li']['text'] []= ''; - $text = preg_replace('/^[ ]{0,4}/', '', $Line['body']); + $text = preg_replace('/^[ ]{0,'.($Block['indent'] + 1).'}/', '', $Line['body']); $Block['li']['text'] []= $text; From 0bd61a73eda9697b7daadf9187bbda305c0916a5 Mon Sep 17 00:00:00 2001 From: Aidan Woods Date: Tue, 11 Oct 2016 13:48:38 +0100 Subject: [PATCH 03/21] Check that the current line is a list before starting a new one --- Parsedown.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Parsedown.php b/Parsedown.php index 29e5fc8cf..d9b4673d6 100644 --- a/Parsedown.php +++ b/Parsedown.php @@ -583,7 +583,7 @@ protected function blockListContinue($Line, array $Block) return $Block; } - elseif ($Block['indent'] === $Line['indent']) + elseif ($Block['indent'] === $Line['indent'] and $l = $this->blockList($Line)) { return null; } From d9679141fa938199c99c3866f0a8a28eec2e3957 Mon Sep 17 00:00:00 2001 From: Aidan Woods Date: Tue, 11 Oct 2016 13:50:47 +0100 Subject: [PATCH 04/21] Update test to comply with CommonMark --- test/data/unordered_list.html | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/test/data/unordered_list.html b/test/data/unordered_list.html index cd95567b7..a52e06b3a 100644 --- a/test/data/unordered_list.html +++ b/test/data/unordered_list.html @@ -5,6 +5,10 @@

mixed markers:

  • li
  • +
+
  • li
  • +
+
  • li
\ No newline at end of file From d26b33c20fb983d07162569b52da8b4510a78706 Mon Sep 17 00:00:00 2001 From: Aidan Woods Date: Tue, 11 Oct 2016 19:18:43 +0100 Subject: [PATCH 05/21] Add `)` as an ordered list marker Also added marker check to ordered list case when deciding to continue the current list --- Parsedown.php | 35 +++++++++++++++++++---------------- 1 file changed, 19 insertions(+), 16 deletions(-) diff --git a/Parsedown.php b/Parsedown.php index d9b4673d6..bb2bd11e6 100644 --- a/Parsedown.php +++ b/Parsedown.php @@ -502,7 +502,7 @@ 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]+[.\)]'); if (preg_match('/^('.$pattern.'[ ]+)(.*)/', $Line['text'], $matches)) { @@ -511,8 +511,7 @@ protected function blockList($Line) 'pattern' => $pattern, 'data' => array( 'type' => $name, - 'matchText' => ($name === 'ul' ? stristr($matches[1], ' ', true) : stristr($matches[1], '.', true)), - 'rootItem' => $matches[2] + 'marker' => ($name === 'ul' ? stristr($matches[1], ' ', true) : substr(stristr($matches[1], ' ', true), -1)), ), 'element' => array( 'name' => $name, @@ -522,7 +521,7 @@ protected function blockList($Line) if($name === 'ol') { - $listStart = stristr($matches[0], '.', true); + $listStart = stristr($matches[1], $Block['data']['marker'], true); if($listStart !== '1') { @@ -547,16 +546,18 @@ protected function blockList($Line) protected function blockListContinue($Line, array $Block) { if ( + $Block['indent'] === $Line['indent'] + and ( - $Block['indent'] === $Line['indent'] - and $Block['data']['type'] === 'ol' - and preg_match('/^'.$Block['pattern'].'(?:[ ]+(.*)|$)/', $Line['text'], $matches) - ) - or - ( - $Block['indent'] === $Line['indent'] - and $Block['data']['type'] === 'ul' - and preg_match('/^'.preg_quote($Block['data']['matchText']).'(?:[ ]+(.*)|$)/', $Line['text'], $matches) + ( + $Block['data']['type'] === 'ol' + and preg_match('/^[0-9]+'.preg_quote($Block['data']['marker']).'(?:[ ]+(.*)|$)/', $Line['text'], $matches) + ) + or + ( + $Block['data']['type'] === 'ul' + and preg_match('/^'.preg_quote($Block['data']['marker']).'(?:[ ]+(.*)|$)/', $Line['text'], $matches) + ) ) ) { @@ -583,11 +584,13 @@ protected function blockListContinue($Line, array $Block) return $Block; } - elseif ($Block['indent'] === $Line['indent'] and $l = $this->blockList($Line)) + elseif ($Block['indent'] === $Line['indent'] and $placeholder = $this->blockList($Line)) { return null; } + unset($placeholder); + if ($Line['text'][0] === '[' and $this->blockReference($Line)) { return $Block; @@ -595,7 +598,7 @@ protected function blockListContinue($Line, array $Block) if ( ! isset($Block['interrupted'])) { - $text = preg_replace('/^[ ]{0,'.($Block['indent'] + 1).'}/', '', $Line['body']); + $text = preg_replace('/^[ ]{0,'.min(4, $Block['indent'] + 1).'}/', '', $Line['body']); $Block['li']['text'] []= $text; @@ -606,7 +609,7 @@ protected function blockListContinue($Line, array $Block) { $Block['li']['text'] []= ''; - $text = preg_replace('/^[ ]{0,'.($Block['indent'] + 1).'}/', '', $Line['body']); + $text = preg_replace('/^[ ]{0,'.min(4, $Block['indent'] + 1).'}/', '', $Line['body']); $Block['li']['text'] []= $text; From 8965c7864fa62394d37e5e53576643a443c4b24e Mon Sep 17 00:00:00 2001 From: Aidan Woods Date: Tue, 11 Oct 2016 20:55:59 +0100 Subject: [PATCH 06/21] More appropriate tests for these changes --- test/data/unordered_list.html | 12 ++++++++++-- test/data/unordered_list.md | 10 ++++++++-- 2 files changed, 18 insertions(+), 4 deletions(-) diff --git a/test/data/unordered_list.html b/test/data/unordered_list.html index a52e06b3a..6ed70a690 100644 --- a/test/data/unordered_list.html +++ b/test/data/unordered_list.html @@ -2,7 +2,7 @@
  • li
  • li
  • -

    mixed markers:

    +

    mixed unordered markers:

    • li
    @@ -11,4 +11,12 @@
    • li
    • -
    \ 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 From 2db31995104f9ad31b9b1a10f8cf2be9d7a32441 Mon Sep 17 00:00:00 2001 From: Aidan Woods Date: Wed, 12 Oct 2016 18:10:44 +0100 Subject: [PATCH 07/21] Break less previously passed CommonMarkWeak tests --- Parsedown.php | 31 ++++++++++++++++++++++++++----- 1 file changed, 26 insertions(+), 5 deletions(-) diff --git a/Parsedown.php b/Parsedown.php index bb2bd11e6..2ee841746 100644 --- a/Parsedown.php +++ b/Parsedown.php @@ -188,16 +188,34 @@ protected function lines(array $lines) # ~ + $highPriority = array(); + $blockTypes = $this->unmarkedBlockTypes; if (isset($this->BlockTypes[$marker])) { foreach ($this->BlockTypes[$marker] as $blockType) { - $blockTypes []= $blockType; + if + ( + isset($CurrentBlock['type']) + and $CurrentBlock['type'] === $blockType + and ! isset($CurrentBlock['interrupted']) + and isset($CurrentBlock['continuable']) + and ! isset($CurrentBlock['complete']) + ) + { + $highPriority[] = $CurrentBlock['type']; + } + else + { + $blockTypes []= $blockType; + } } } + $blockTypes = array_merge($highPriority, $blockTypes); + # # ~ @@ -589,8 +607,6 @@ protected function blockListContinue($Line, array $Block) return null; } - unset($placeholder); - if ($Line['text'][0] === '[' and $this->blockReference($Line)) { return $Block; @@ -598,7 +614,7 @@ protected function blockListContinue($Line, array $Block) if ( ! isset($Block['interrupted'])) { - $text = preg_replace('/^[ ]{0,'.min(4, $Block['indent'] + 1).'}/', '', $Line['body']); + $text = preg_replace('/^[ ]{0,'.min(4, $Block['indent']).'}/', '', $Line['body']); $Block['li']['text'] []= $text; @@ -609,7 +625,12 @@ protected function blockListContinue($Line, array $Block) { $Block['li']['text'] []= ''; - $text = preg_replace('/^[ ]{0,'.min(4, $Block['indent'] + 1).'}/', '', $Line['body']); + $text = preg_replace('/^[ ]{0,4}/', '', $Line['body']); + + if ($placeholder = $this->blockList($Line)) + { + $text = preg_replace('/^[ ]{0,'.min(4, $Block['indent']).'}/', '', $Line['body']); + } $Block['li']['text'] []= $text; From 0a43799da4f6b10d9fc3bdbb6482e2e1713fb79f Mon Sep 17 00:00:00 2001 From: Aidan Woods Date: Thu, 13 Oct 2016 14:29:52 +0100 Subject: [PATCH 08/21] Prevent failure with data set 77 in CommonMarkWeak --- Parsedown.php | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/Parsedown.php b/Parsedown.php index 2ee841746..f774b886a 100644 --- a/Parsedown.php +++ b/Parsedown.php @@ -115,7 +115,7 @@ function setUrlsLinked($urlsLinked) # Blocks # - protected function lines(array $lines) + protected function lines(array $lines, $parentType = null) { $CurrentBlock = null; @@ -216,6 +216,12 @@ protected function lines(array $lines) $blockTypes = array_merge($highPriority, $blockTypes); + if ( $parentType === 'List' and ($a = array_search('List', $blockTypes)) !== false and ($b = array_search('Code', $blockTypes)) !== false and $a > $b and ($placeholder = $this->blockList($Line))) + { + unset($blockTypes[$b]); + array_splice($blockTypes, $a + 1, 0, 'Code'); + } + # # ~ @@ -1502,7 +1508,7 @@ protected function elements(array $Elements) protected function li($lines) { - $markup = $this->lines($lines); + $markup = $this->lines($lines, 'List'); $trimmedMarkup = trim($markup); From 6973302ca8f6f8613cd76488ad3f87067458e215 Mon Sep 17 00:00:00 2001 From: Aidan Woods Date: Thu, 13 Oct 2016 15:55:13 +0100 Subject: [PATCH 09/21] Prevent breaking remaining previously compliant CommonMarkWeak tests --- Parsedown.php | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/Parsedown.php b/Parsedown.php index f774b886a..e6a479917 100644 --- a/Parsedown.php +++ b/Parsedown.php @@ -165,7 +165,7 @@ protected function lines(array $lines, $parentType = null) if (isset($CurrentBlock['continuable'])) { - $Block = $this->{'block'.$CurrentBlock['type'].'Continue'}($Line, $CurrentBlock); + $Block = $this->{'block'.$CurrentBlock['type'].'Continue'}($Line, $CurrentBlock, $parentType); if (isset($Block)) { @@ -449,7 +449,7 @@ protected function blockFencedCode($Line) } } - protected function blockFencedCodeContinue($Line, $Block) + protected function blockFencedCodeContinue($Line, $Block, $parentType) { if (isset($Block['complete'])) { @@ -472,6 +472,11 @@ protected function blockFencedCodeContinue($Line, $Block) return $Block; } + if ($parentType === 'List') + { + $Line['body'] = preg_replace('/^[ ]{0,'.min(4, $Line['indent']).'}/', '', $Line['body']); + } + $Block['element']['text']['text'] .= "\n".$Line['body'];; return $Block; From eb853da92aef802deee84ea46476b14318ce3b12 Mon Sep 17 00:00:00 2001 From: Daniel Rudolf Date: Thu, 13 Oct 2016 19:25:30 +0200 Subject: [PATCH 10/21] Revert "Prevent breaking remaining previously compliant CommonMarkWeak tests" This reverts commit 6973302ca8f6f8613cd76488ad3f87067458e215. --- Parsedown.php | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/Parsedown.php b/Parsedown.php index e6a479917..f774b886a 100644 --- a/Parsedown.php +++ b/Parsedown.php @@ -165,7 +165,7 @@ protected function lines(array $lines, $parentType = null) if (isset($CurrentBlock['continuable'])) { - $Block = $this->{'block'.$CurrentBlock['type'].'Continue'}($Line, $CurrentBlock, $parentType); + $Block = $this->{'block'.$CurrentBlock['type'].'Continue'}($Line, $CurrentBlock); if (isset($Block)) { @@ -449,7 +449,7 @@ protected function blockFencedCode($Line) } } - protected function blockFencedCodeContinue($Line, $Block, $parentType) + protected function blockFencedCodeContinue($Line, $Block) { if (isset($Block['complete'])) { @@ -472,11 +472,6 @@ protected function blockFencedCodeContinue($Line, $Block, $parentType) return $Block; } - if ($parentType === 'List') - { - $Line['body'] = preg_replace('/^[ ]{0,'.min(4, $Line['indent']).'}/', '', $Line['body']); - } - $Block['element']['text']['text'] .= "\n".$Line['body'];; return $Block; From e691034861679341341d9cde4fcbf0a8cabb75d3 Mon Sep 17 00:00:00 2001 From: Daniel Rudolf Date: Thu, 13 Oct 2016 19:25:37 +0200 Subject: [PATCH 11/21] Revert "Prevent failure with data set 77 in CommonMarkWeak" This reverts commit 0a43799da4f6b10d9fc3bdbb6482e2e1713fb79f. --- Parsedown.php | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/Parsedown.php b/Parsedown.php index f774b886a..2ee841746 100644 --- a/Parsedown.php +++ b/Parsedown.php @@ -115,7 +115,7 @@ function setUrlsLinked($urlsLinked) # Blocks # - protected function lines(array $lines, $parentType = null) + protected function lines(array $lines) { $CurrentBlock = null; @@ -216,12 +216,6 @@ protected function lines(array $lines, $parentType = null) $blockTypes = array_merge($highPriority, $blockTypes); - if ( $parentType === 'List' and ($a = array_search('List', $blockTypes)) !== false and ($b = array_search('Code', $blockTypes)) !== false and $a > $b and ($placeholder = $this->blockList($Line))) - { - unset($blockTypes[$b]); - array_splice($blockTypes, $a + 1, 0, 'Code'); - } - # # ~ @@ -1508,7 +1502,7 @@ protected function elements(array $Elements) protected function li($lines) { - $markup = $this->lines($lines, 'List'); + $markup = $this->lines($lines); $trimmedMarkup = trim($markup); From 81025cd468f4f51eebedd2c159be893bfa414602 Mon Sep 17 00:00:00 2001 From: Daniel Rudolf Date: Thu, 13 Oct 2016 19:25:43 +0200 Subject: [PATCH 12/21] Revert "Break less previously passed CommonMarkWeak tests" This reverts commit 2db31995104f9ad31b9b1a10f8cf2be9d7a32441. --- Parsedown.php | 31 +++++-------------------------- 1 file changed, 5 insertions(+), 26 deletions(-) diff --git a/Parsedown.php b/Parsedown.php index 2ee841746..bb2bd11e6 100644 --- a/Parsedown.php +++ b/Parsedown.php @@ -188,34 +188,16 @@ protected function lines(array $lines) # ~ - $highPriority = array(); - $blockTypes = $this->unmarkedBlockTypes; if (isset($this->BlockTypes[$marker])) { foreach ($this->BlockTypes[$marker] as $blockType) { - if - ( - isset($CurrentBlock['type']) - and $CurrentBlock['type'] === $blockType - and ! isset($CurrentBlock['interrupted']) - and isset($CurrentBlock['continuable']) - and ! isset($CurrentBlock['complete']) - ) - { - $highPriority[] = $CurrentBlock['type']; - } - else - { - $blockTypes []= $blockType; - } + $blockTypes []= $blockType; } } - $blockTypes = array_merge($highPriority, $blockTypes); - # # ~ @@ -607,6 +589,8 @@ protected function blockListContinue($Line, array $Block) return null; } + unset($placeholder); + if ($Line['text'][0] === '[' and $this->blockReference($Line)) { return $Block; @@ -614,7 +598,7 @@ protected function blockListContinue($Line, array $Block) if ( ! isset($Block['interrupted'])) { - $text = preg_replace('/^[ ]{0,'.min(4, $Block['indent']).'}/', '', $Line['body']); + $text = preg_replace('/^[ ]{0,'.min(4, $Block['indent'] + 1).'}/', '', $Line['body']); $Block['li']['text'] []= $text; @@ -625,12 +609,7 @@ protected function blockListContinue($Line, array $Block) { $Block['li']['text'] []= ''; - $text = preg_replace('/^[ ]{0,4}/', '', $Line['body']); - - if ($placeholder = $this->blockList($Line)) - { - $text = preg_replace('/^[ ]{0,'.min(4, $Block['indent']).'}/', '', $Line['body']); - } + $text = preg_replace('/^[ ]{0,'.min(4, $Block['indent'] + 1).'}/', '', $Line['body']); $Block['li']['text'] []= $text; From bdf537e9d57035a12160ab4344e9a7361e327bbf Mon Sep 17 00:00:00 2001 From: Daniel Rudolf Date: Thu, 13 Oct 2016 19:30:50 +0200 Subject: [PATCH 13/21] Fix ordered list start argument See CommonMark spec examples [#226](http://spec.commonmark.org/0.26/#example-226) to #229 --- Parsedown.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Parsedown.php b/Parsedown.php index bb2bd11e6..ac83e50a6 100644 --- a/Parsedown.php +++ b/Parsedown.php @@ -502,7 +502,7 @@ 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)) { @@ -521,7 +521,7 @@ protected function blockList($Line) if($name === 'ol') { - $listStart = stristr($matches[1], $Block['data']['marker'], true); + $listStart = ltrim(strstr($matches[1], $Block['data']['marker'], true), '0') ?: '0'; if($listStart !== '1') { From 30ff5c6e7564aa3d0e30dd9476335c0a444f8dcd Mon Sep 17 00:00:00 2001 From: Daniel Rudolf Date: Thu, 13 Oct 2016 19:31:35 +0200 Subject: [PATCH 14/21] Remove unused $placeholder variable --- Parsedown.php | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/Parsedown.php b/Parsedown.php index ac83e50a6..5003775c1 100644 --- a/Parsedown.php +++ b/Parsedown.php @@ -584,13 +584,11 @@ protected function blockListContinue($Line, array $Block) return $Block; } - elseif ($Block['indent'] === $Line['indent'] and $placeholder = $this->blockList($Line)) + elseif ($Block['indent'] === $Line['indent'] and $this->blockList($Line)) { return null; } - unset($placeholder); - if ($Line['text'][0] === '[' and $this->blockReference($Line)) { return $Block; From 4b3b7df710e7a8ccd0a6fe66f84a03cddeb988e4 Mon Sep 17 00:00:00 2001 From: Daniel Rudolf Date: Thu, 13 Oct 2016 19:46:29 +0200 Subject: [PATCH 15/21] Support list items starting with a blank line According to the CommonMark specs ([list items](http://spec.commonmark.org/0.26/#list-items), rule 3), list items starting with a blank line basically behave like as if the \n doesn't exist. Also see example [#241](http://spec.commonmark.org/0.26/#example-241). --- Parsedown.php | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/Parsedown.php b/Parsedown.php index 5003775c1..df79c9999 100644 --- a/Parsedown.php +++ b/Parsedown.php @@ -504,8 +504,12 @@ protected function blockList($Line) { 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)) { + if ($matches[2] === '') { + $matches[1] .= ' '; + } + $Block = array( 'indent' => $Line['indent'], 'pattern' => $pattern, @@ -532,9 +536,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']; @@ -545,6 +547,10 @@ protected function blockList($Line) protected function blockListContinue($Line, array $Block) { + if (isset($Block['interrupted']) and empty($Block['li']['text'])) { + return null; + } + if ( $Block['indent'] === $Line['indent'] and From 1d61f90bf94a5a27736208275dae6d93c79107b8 Mon Sep 17 00:00:00 2001 From: Daniel Rudolf Date: Thu, 13 Oct 2016 19:47:06 +0200 Subject: [PATCH 16/21] Support list items starting with indented code --- Parsedown.php | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/Parsedown.php b/Parsedown.php index df79c9999..2f81b84cd 100644 --- a/Parsedown.php +++ b/Parsedown.php @@ -506,7 +506,12 @@ protected function blockList($Line) if (preg_match('/^('.$pattern.'([ ]+|$))(.*)/', $Line['text'], $matches)) { - if ($matches[2] === '') { + $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] .= ' '; } From 7b1529fff036b9c4c2c301bc4939a8c7f6e7d245 Mon Sep 17 00:00:00 2001 From: Daniel Rudolf Date: Thu, 13 Oct 2016 19:51:32 +0200 Subject: [PATCH 17/21] Use the list marker width to determine whether a list item is continued This basically represents [list item parsing](http://spec.commonmark.org/0.26/#list-items), rule 1 of the CommonMark specs. --- Parsedown.php | 31 +++++++++++++++++++------------ 1 file changed, 19 insertions(+), 12 deletions(-) diff --git a/Parsedown.php b/Parsedown.php index 2f81b84cd..f6e1bec4e 100644 --- a/Parsedown.php +++ b/Parsedown.php @@ -520,7 +520,8 @@ protected function blockList($Line) 'pattern' => $pattern, 'data' => array( 'type' => $name, - 'marker' => ($name === 'ul' ? stristr($matches[1], ' ', true) : substr(stristr($matches[1], ' ', true), -1)), + 'marker' => $matches[1], + 'markerType' => ($name === 'ul' ? strstr($matches[1], ' ', true) : substr(strstr($matches[1], ' ', true), -1)), ), 'element' => array( 'name' => $name, @@ -530,7 +531,7 @@ protected function blockList($Line) if($name === 'ol') { - $listStart = ltrim(strstr($matches[1], $Block['data']['marker'], true), '0') ?: '0'; + $listStart = ltrim(strstr($matches[1], $Block['data']['markerType'], true), '0') ?: '0'; if($listStart !== '1') { @@ -562,12 +563,12 @@ protected function blockListContinue($Line, array $Block) ( ( $Block['data']['type'] === 'ol' - and preg_match('/^[0-9]+'.preg_quote($Block['data']['marker']).'(?:[ ]+(.*)|$)/', $Line['text'], $matches) + 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']['marker']).'(?:[ ]+(.*)|$)/', $Line['text'], $matches) + and preg_match('/^'.preg_quote($Block['data']['markerType']).'(?:[ ]+(.*)|$)/', $Line['text'], $matches) ) ) ) @@ -605,25 +606,31 @@ protected function blockListContinue($Line, array $Block) return $Block; } - if ( ! isset($Block['interrupted'])) + $requiredIndent = ($Block['indent'] + strlen($Block['data']['marker'])); + + if ($Line['indent'] >= $requiredIndent) { - $text = preg_replace('/^[ ]{0,'.min(4, $Block['indent'] + 1).'}/', '', $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,'.min(4, $Block['indent'] + 1).'}/', '', $Line['body']); + // TODO: force multi-line paragraph, this must not parse any new block + $text = preg_replace('/^[ ]{0,'.$requiredIndent.'}/', '', $Line['body']); $Block['li']['text'] []= $text; - unset($Block['interrupted']); - return $Block; } } From a9e1163c85bb23564458af84e8852650e209fbe9 Mon Sep 17 00:00:00 2001 From: Daniel Rudolf Date: Thu, 13 Oct 2016 19:52:38 +0200 Subject: [PATCH 18/21] Fix code formatting --- Parsedown.php | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/Parsedown.php b/Parsedown.php index f6e1bec4e..ececf78a2 100644 --- a/Parsedown.php +++ b/Parsedown.php @@ -507,11 +507,15 @@ protected function blockList($Line) if (preg_match('/^('.$pattern.'([ ]+|$))(.*)/', $Line['text'], $matches)) { $contentIndent = strlen($matches[2]); - if ($contentIndent >= 5) { + + if ($contentIndent >= 5) + { $contentIndent -= 1; $matches[1] = substr($matches[1], 0, -$contentIndent); $matches[3] = str_repeat(' ', $contentIndent) . $matches[3]; - } elseif ($contentIndent === 0) { + } + elseif ($contentIndent === 0) + { $matches[1] .= ' '; } @@ -553,7 +557,8 @@ protected function blockList($Line) protected function blockListContinue($Line, array $Block) { - if (isset($Block['interrupted']) and empty($Block['li']['text'])) { + if (isset($Block['interrupted']) and empty($Block['li']['text'])) + { return null; } From a3836b185368b92dad899e7a9567731eeed8297d Mon Sep 17 00:00:00 2001 From: Daniel Rudolf Date: Thu, 13 Oct 2016 20:44:02 +0200 Subject: [PATCH 19/21] Handle subsequent list items which aren't indented sufficiently Subsequent list items which aren't indented sufficiently are treated as part of the original list, see CommonMark spec example [#256](http://spec.commonmark.org/0.26/#example-256). --- Parsedown.php | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/Parsedown.php b/Parsedown.php index ececf78a2..de80f3f2e 100644 --- a/Parsedown.php +++ b/Parsedown.php @@ -562,8 +562,10 @@ protected function blockListContinue($Line, array $Block) return null; } + $requiredIndent = ($Block['indent'] + strlen($Block['data']['marker'])); + if ( - $Block['indent'] === $Line['indent'] + $Line['indent'] < $requiredIndent and ( ( @@ -589,6 +591,8 @@ protected function blockListContinue($Line, array $Block) $text = isset($matches[1]) ? $matches[1] : ''; + $Block['indent'] = $Line['indent']; + $Block['li'] = array( 'name' => 'li', 'handler' => 'li', @@ -601,7 +605,7 @@ protected function blockListContinue($Line, array $Block) return $Block; } - elseif ($Block['indent'] === $Line['indent'] and $this->blockList($Line)) + elseif ($Line['indent'] < $requiredIndent and $this->blockList($Line)) { return null; } @@ -611,8 +615,6 @@ protected function blockListContinue($Line, array $Block) return $Block; } - $requiredIndent = ($Block['indent'] + strlen($Block['data']['marker'])); - if ($Line['indent'] >= $requiredIndent) { if (isset($Block['interrupted'])) @@ -631,7 +633,6 @@ protected function blockListContinue($Line, array $Block) if ( ! isset($Block['interrupted'])) { - // TODO: force multi-line paragraph, this must not parse any new block $text = preg_replace('/^[ ]{0,'.$requiredIndent.'}/', '', $Line['body']); $Block['li']['text'] []= $text; From f594d4c18b686294ccc3e162ba0eb84c4b45fb3b Mon Sep 17 00:00:00 2001 From: Aidan Woods Date: Tue, 27 Mar 2018 11:20:04 +0100 Subject: [PATCH 20/21] Add more tests for CommonMark compliance --- test/data/deeply_nested_list.html | 28 ++++++++++++++++++++++++++++ test/data/deeply_nested_list.md | 22 +++++++++++++++++++++- 2 files changed, 49 insertions(+), 1 deletion(-) 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
  • + +
    +
      +
    • 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/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 From d2a73f917938e816fde895f417d5a1539d6b310e Mon Sep 17 00:00:00 2001 From: Aidan Woods Date: Tue, 27 Mar 2018 11:23:04 +0100 Subject: [PATCH 21/21] Trim whitespace --- Parsedown.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Parsedown.php b/Parsedown.php index 0d4466928..b5fb584cc 100644 --- a/Parsedown.php +++ b/Parsedown.php @@ -558,7 +558,7 @@ protected function blockList($Line) if($name === 'ol') { $listStart = ltrim(strstr($matches[1], $Block['data']['markerType'], true), '0') ?: '0'; - + if($listStart !== '1') { $Block['element']['attributes'] = array('start' => $listStart);