From b2bc6f1dc77b744cb22fe486efac5159cf8b7e13 Mon Sep 17 00:00:00 2001 From: trendschau Date: Mon, 2 Nov 2020 11:13:34 +0100 Subject: [PATCH 1/2] Version 1.4.1: Fix Markdown Blocks --- system/Extensions/ParsedownExtension.php | 233 ++++++++++++++++++++++- 1 file changed, 232 insertions(+), 1 deletion(-) diff --git a/system/Extensions/ParsedownExtension.php b/system/Extensions/ParsedownExtension.php index fcecb31..53fd55a 100644 --- a/system/Extensions/ParsedownExtension.php +++ b/system/Extensions/ParsedownExtension.php @@ -715,8 +715,239 @@ class ParsedownExtension extends \ParsedownExtra - # manipulated method linesElements, returns array of markdown blocks public function markdownToArrayBlocks($markdown) + { + # make sure no definitions are set + $this->DefinitionData = array(); + + # standardize line breaks + $text = str_replace(array("\r\n", "\r"), "\n", $markdown); + + # remove surrounding line breaks + $text = trim($text, "\n"); + + # split text into lines + $lines = explode("\n", $text); + + # manipulated method linesElements + + # $Elements = array(); + + # the block that's being built + # when a block is complete we add it to $Elements + $CurrentBlock = null; + + # ++ + $strings = array(); + $currentString = null; + + foreach ($lines as $line) { + + # is it a blank line + if (chop($line) === '') { + # mark current block as interrupted + if (isset($CurrentBlock)) { + # set or increment interrupted + $CurrentBlock['interrupted'] = (isset($CurrentBlock['interrupted']) + ? $CurrentBlock['interrupted'] + 1 : 1 + ); + } + + continue; + } + + # ~ + + # figure out line indent and text + + while (($beforeTab = strstr($line, "\t", true)) !== false) { + $shortage = 4 - mb_strlen($beforeTab, 'utf-8') % 4; + + $line = $beforeTab + . str_repeat(' ', $shortage) + . substr($line, strlen($beforeTab) + 1); + } + + $indent = strspn($line, ' '); + + $text = $indent > 0 ? substr($line, $indent) : $line; + + # ~ + + $Line = array('body' => $line, 'indent' => $indent, 'text' => $text); + + # ~ + + if (isset($CurrentBlock['continuable'])) { + # current block is continuable + # let's attempt to continue it + $methodName = 'block' . $CurrentBlock['type'] . 'Continue'; + $Block = $this->$methodName($Line, $CurrentBlock); + + if (isset($Block)) { + # attempt to continue it was successful + # let's update it + $CurrentBlock = $Block; + + # ++ + $currentString .= "\n$line"; + + continue; + } else { + # current block is continuable but we were unable to continue it + # this means that it's complete + # let's call it's "complete" method if it has one + if ($this->isBlockCompletable($CurrentBlock['type'])) { + $methodName = 'block' . $CurrentBlock['type'] . 'Complete'; + $CurrentBlock = $this->$methodName($CurrentBlock); + } + } + } + + # ~ + + $marker = $text[0]; + + # ~ + + # make a list of the block types that current line can start + $blockTypes = $this->unmarkedBlockTypes; + if (isset($this->BlockTypes[$marker])) { + foreach ($this->BlockTypes[$marker] as $blockType) { + $blockTypes [] = $blockType; + } + } + + # + # ~ + + foreach ($blockTypes as $blockType) { + # let's see if current line can start a block of type $blockType + $Block = $this->{"block$blockType"}($Line, $CurrentBlock); + + if (isset($Block)) { + # echo "[$blockType]"; + # current line managed to start a block of type $blockType + # let's set its type + $Block['type'] = $blockType; + + # on start block, we "ship" current block and flag started block as identified + # except when the started block has already flagged itself as identified + # this is the case of table + # blocks flag themselves as identified to "absorb" current block + # setext function doesn't set "identified" but it inherits it from the $Block param + if (!isset($Block['identified'])) { + # if (isset($CurrentBlock)) { + # $Elements[] = $this->extractElement($CurrentBlock); + # } + + # ++ + # currentString would be null if this is the first block + if ($currentString !== null) { + $strings[] = $currentString; + } + + # ++ + # line doesn't belong to currentString + # we've shipped + $currentString = $line; + + $Block['identified'] = true; + } else { + # ++ + $currentString .= "\n$line"; + } + + # does block have a "continue" method + if ($this->isBlockContinuable($blockType)) { + $Block['continuable'] = true; + } + + $CurrentBlock = $Block; + + # we're done with this line + # move on to next line + continue 2; + } + } + + # ~ + + if (isset($CurrentBlock) and $CurrentBlock['type'] === 'Paragraph') { + # we continue paragraphs here because they are "lazy" + # they "eat" the line only if no other block type has "eaten" it + $Block = $this->paragraphContinue($Line, $CurrentBlock); + } + + if (isset($Block)) { + $CurrentBlock = $Block; + + # ++ + $currentString .= "\n$line"; + } else { + # is this "isset" might be here to handle $lines[0] (first line) + # version 1.7.x doesn't have it but it does unset($Blocks[0]) + if (isset($CurrentBlock)) { + # $Elements[] = $this->extractElement($CurrentBlock); + + # ++ + $strings[] = $currentString; + } + + $CurrentBlock = $this->paragraph($Line); + + # ++ + $currentString = $line; + + $CurrentBlock['identified'] = true; + } + if($blockType == "DefinitionList") + { + die('def'); + echo 'currentLine'; + echo $currentString; + } + + } + die(); + # ~ + + # at this point, we're out of the $lines loop + + # handles the case where the last block is continuable + # since there are no more lines, it won't get completed in the loop + # we need to complete it here + if (isset($CurrentBlock['continuable']) and $this->isBlockCompletable($CurrentBlock['type'])) { + $methodName = 'block' . $CurrentBlock['type'] . 'Complete'; + $CurrentBlock = $this->$methodName($CurrentBlock); + } + + # ~ + + if (isset($CurrentBlock)) { + # $Elements[] = $this->extractElement($CurrentBlock); + + # ++ + $strings[] = $currentString; + } + + # ~ + + # return $Elements; + + ## ++ + echo '
';
+        print_r($strings);
+        return $strings;
+    }
+
+
+
+
+
+
+    # manipulated method linesElements, returns array of markdown blocks
+    public function markdownToArrayBlocksNew($markdown)
     {
 
         # make sure no definitions are set

From b0f1e0eac38bebfc1d4ed07720504410b633967a Mon Sep 17 00:00:00 2001
From: trendschau 
Date: Mon, 2 Nov 2020 22:13:09 +0100
Subject: [PATCH 2/2] Version 141: Final fix for markdown blocks

---
 system/Extensions/ParsedownExtension.php | 290 +++++------------------
 1 file changed, 55 insertions(+), 235 deletions(-)

diff --git a/system/Extensions/ParsedownExtension.php b/system/Extensions/ParsedownExtension.php
index 53fd55a..d78ccd3 100644
--- a/system/Extensions/ParsedownExtension.php
+++ b/system/Extensions/ParsedownExtension.php
@@ -715,6 +715,10 @@ class ParsedownExtension extends \ParsedownExtra
 
 
 
+    # ++
+    # blocks that belong to a "magneticType" would "merge" if they are next to each other
+    protected $magneticTypes = array('DefinitionList', 'Footnote');
+
     public function markdownToArrayBlocks($markdown)
     {
         # make sure no definitions are set
@@ -738,8 +742,8 @@ class ParsedownExtension extends \ParsedownExtra
         $CurrentBlock = null;
 
         # ++
-        $strings = array();
-        $currentString = null;
+        $done = array();
+        $current = null;
 
         foreach ($lines as $line) {
 
@@ -785,18 +789,19 @@ class ParsedownExtension extends \ParsedownExtra
                 $Block = $this->$methodName($Line, $CurrentBlock);
 
                 if (isset($Block)) {
-                    # attempt to continue it was successful
+                    # attempt to continue was successful
                     # let's update it
                     $CurrentBlock = $Block;
 
                     # ++
-                    $currentString .= "\n$line";
+                    $current['text'] .= "\n$line";
 
+                    # move to next line
                     continue;
                 } else {
-                    # current block is continuable but we were unable to continue it
-                    # this means that it's complete
-                    # let's call it's "complete" method if it has one
+                    # attempt to continue failed
+                    # this means current block is complete
+                    # let's call its "complete" method if it has one
                     if ($this->isBlockCompletable($CurrentBlock['type'])) {
                         $methodName = 'block' . $CurrentBlock['type'] . 'Complete';
                         $CurrentBlock = $this->$methodName($CurrentBlock);
@@ -806,6 +811,9 @@ class ParsedownExtension extends \ParsedownExtra
 
             # ~
 
+            # current block failed to "eat" current line
+            # let's see if we can start a new block
+
             $marker = $text[0];
 
             # ~
@@ -842,20 +850,20 @@ class ParsedownExtension extends \ParsedownExtra
                         # }
 
                         # ++
-                        # currentString would be null if this is the first block
-                        if ($currentString !== null) {
-                            $strings[] = $currentString;
+                        # $current would be null if this is the first block
+                        if ($current !== null) {
+                            $done[] = $current;
                         }
 
                         # ++
-                        # line doesn't belong to currentString
-                        # we've shipped
-                        $currentString = $line;
+                        # line doesn't belong to $current
+                        $current = ['text' => $line, 'type' => $blockType];
 
                         $Block['identified'] = true;
                     } else {
                         # ++
-                        $currentString .= "\n$line";
+                        $current['text'] .= "\n$line";
+                        $current['type'] = $blockType;
                     }
 
                     # does block have a "continue" method
@@ -883,7 +891,7 @@ class ParsedownExtension extends \ParsedownExtra
                 $CurrentBlock = $Block;
 
                 # ++
-                $currentString .= "\n$line";
+                $current['text'] .= "\n$line";
             } else {
                 # is this "isset" might be here to handle $lines[0] (first line)
                 # version 1.7.x doesn't have it but it does unset($Blocks[0])
@@ -891,25 +899,18 @@ class ParsedownExtension extends \ParsedownExtra
                     # $Elements[] = $this->extractElement($CurrentBlock);
 
                     # ++
-                    $strings[] = $currentString;
+                    $done[] = $current;
                 }
 
                 $CurrentBlock = $this->paragraph($Line);
 
                 # ++
-                $currentString = $line;
+                $current = ['text' => $line, 'type' => 'Paragraph'];
 
                 $CurrentBlock['identified'] = true;
             }
-            if($blockType == "DefinitionList")
-            {
-                die('def');
-                echo 'currentLine';
-                echo $currentString;  
-            }
-
         }
-        die();
+
         # ~
 
         # at this point, we're out of the $lines loop
@@ -928,223 +929,42 @@ class ParsedownExtension extends \ParsedownExtra
             # $Elements[] = $this->extractElement($CurrentBlock);
 
             # ++
-            $strings[] = $currentString;
+            $done[] = $current;
         }
 
         # ~
 
+        # ++
+        # merge blocks that have magnetic types
+        $done = array_reduce($done, function (array $accumulator, array $current) {
+            if ($accumulator) {
+                $last = array_pop($accumulator);
+
+                if ($current['type'] === $last['type'] and in_array($current['type'], $this->magneticTypes)) {
+                    $last['text'] .= "\n\n" . $current['text'];
+                    $accumulator[] = $last;
+                } else {
+                    $accumulator[] = $last;
+                    $accumulator[] = $current;
+                }
+            } else {
+                # first iteration
+                $accumulator[] = $current;
+            }
+
+            return $accumulator;
+        }, []);
+
+        # ~
+
         # return $Elements;
 
-        ## ++
-        echo '
';
-        print_r($strings);
-        return $strings;
+        # ++
+        # return just the text of each item
+        return array_map(function (array $item) {
+            return $item['text'];
+        }, $done);
     }
-
-
-
-
-
-
-    # manipulated method linesElements, returns array of markdown blocks
-    public function markdownToArrayBlocksNew($markdown)
-    {
-
-        # make sure no definitions are set
-        $this->DefinitionData = array();
-
-        # standardize line breaks
-        $text = str_replace(array("\r\n", "\r"), "\n", $markdown);
-
-        # remove surrounding line breaks
-        $text = trim($text, "\n");
-
-        # split text into lines
-        $lines = explode("\n", $text);
-
-        # manipulated method linesElements
-
-        $Elements = array();
-        $CurrentBlock = null;
-/*new*/ $mdElements = array();
-
-        foreach ($lines as $line)
-        {
-            if (chop($line) === '')
-            {
-                if (isset($CurrentBlock))
-                {
-                    $CurrentBlock['interrupted'] = (isset($CurrentBlock['interrupted'])
-                        ? $CurrentBlock['interrupted'] + 1 : 1
-                    );
-                }
-
-                continue;
-            }
-
-            while (($beforeTab = strstr($line, "\t", true)) !== false)
-            {
-                $shortage = 4 - mb_strlen($beforeTab, 'utf-8') % 4;
-
-                $line = $beforeTab
-                    . str_repeat(' ', $shortage)
-                    . substr($line, strlen($beforeTab) + 1)
-                ;
-            }
-
-            $indent = strspn($line, ' ');
-
-            $text = $indent > 0 ? substr($line, $indent) : $line;
-
-            # ~
-
-            $Line = array('body' => $line, 'indent' => $indent, 'text' => $text);
-
-            # ~
-
-            # if we are in a multiline block element
-            if (isset($CurrentBlock['continuable']))
-            {
-                $methodName = 'block' . $CurrentBlock['type'] . 'Continue';
-
-/* fix definition list */
-                if($CurrentBlock['type'] == 'DefinitionList' && isset($CurrentBlock['interrupted']))
-                {
-                    $mdCurrentBlock = $mdCurrentBlock . "\n\n";
-                }
-
-                $Block = $this->$methodName($Line, $CurrentBlock);
-
-                # if this line still belongs to the current multiline block
-                if (isset($Block))
-                {
-                    $CurrentBlock = $Block;
-/*new*/             $mdCurrentBlock = $mdCurrentBlock . "\n" . $line;
-                    continue;
-                }
-                # if this line does not belong to the current multiline block
-                else
-                {
-                    # if multiline block element is finished
-                    if ($this->isBlockCompletable($CurrentBlock['type']))
-                    {
-                        $methodName = 'block' . $CurrentBlock['type'] . 'Complete';
-                        $CurrentBlock = $this->$methodName($CurrentBlock);
-/*new*/                 $mdCurrentBlock = $mdCurrentBlock;
-                    }
-                }
-            }                
-
-            # ~
-
-            $marker = $text[0];
-
-            # ~
-
-            $blockTypes = $this->unmarkedBlockTypes;
-
-            if (isset($this->BlockTypes[$marker]))
-            {
-                foreach ($this->BlockTypes[$marker] as $blockType)
-                {
-                    $blockTypes []= $blockType;
-                }
-            }
-
-            #
-            # ~
-            foreach ($blockTypes as $blockType)
-            {
-                $Block = $this->{"block$blockType"}($Line, $CurrentBlock);
-
-/* new */       $mdBlock = $line;
-
-/* dirty fix for tables and definition lists, not sure why this happens */     
-                if ( ($blockType == "Table" OR $blockType == "DefinitionList") && isset($mdCurrentBlock) ) 
-                {
-                   $mdBlock = $mdCurrentBlock . "\n" . $line;
-                }
-/* fix end */
-
-                if (isset($Block))
-                {
-                    $Block['type'] = $blockType;
-                    if ( ! isset($Block['identified']))
-                    {
-                        if (isset($CurrentBlock))
-                        {
-                            $Elements[] = $this->extractElement($CurrentBlock);
-/*new*/                     $mdElements[] = $mdCurrentBlock;
-                        }
-
-                        $Block['identified'] = true;
-                    }
-
-                    if ($this->isBlockContinuable($blockType))
-                    {
-                        $Block['continuable'] = true;
-                    }
-
-                    $CurrentBlock = $Block;
-/*new*/             $mdCurrentBlock = $mdBlock;
- 
-                    continue 2;
-                }
-            }
-
-            # ~
-
-            if (isset($CurrentBlock) and $CurrentBlock['type'] === 'Paragraph')
-            {
-                $Block = $this->paragraphContinue($Line, $CurrentBlock);
-/*new*/         $mdBlock = $mdCurrentBlock . "\n" . $line;
-            }
-
-            if (isset($Block))
-            {
-                $CurrentBlock = $Block;
-/*new*/         $mdCurrentBlock = $mdBlock;
-            }
-            else
-            {
-                if (isset($CurrentBlock))
-                {
-                    $Elements[] = $this->extractElement($CurrentBlock);
-/*new*/             $mdElements[] = $mdCurrentBlock;
-                }
-
-                $CurrentBlock = $this->paragraph($Line);
-/*new*/         $mdCurrentBlock = $line;
-                $CurrentBlock['identified'] = true;
-            }
-
-        }
-
-        # ~
-
-        if (isset($CurrentBlock['continuable']) and $this->isBlockCompletable($CurrentBlock['type']))
-        {
-            $methodName = 'block' . $CurrentBlock['type'] . 'Complete';
-            $CurrentBlock = $this->$methodName($CurrentBlock);
-/*new*/     $mdCurrentBlock = $mdCurrentBlock;
-        }
-
-        # ~
-
-        if (isset($CurrentBlock))
-        {            
-            $Elements[] = $this->extractElement($CurrentBlock);
-/*new*/     $mdElements[] = $mdCurrentBlock;
-        }
-
-        # ~
-/*        echo '
';
-        print_r($mdElements);
-        die();
-/*new*/ return $mdElements;
-#       return $Elements;
-    }
-
     
     public function arrayBlocksToMarkdown(array $arrayBlocks)
     {