/** * Parse the given content. * * Any newly created nodes should be pushed to the stack. Any remaining content should be passed to the next parser * in the chain. * * @param Text $content * @param Container $target * @return void */ public function parseBlock(Text $content, Container $target) { $content->handle('/ ( (?: # We are either at the beginning of the match ^|\\n # or at a newline (for multi-line quotes) ) (?: [ ]{0,3}\\>[ ]* # either a blank line | [ ]{0,3}\\>[ ]?[`~]{3,}.* # or a code fence | [ ]{0,3}\\> # or non-blank lines... [ ]*[^\\n\\ ][^\\n]*[ ]* ( # ...with lazy continuation \\n [ ]{0,3} [^>\\-+*=\\ \\n][^\\n]* )* ) )+ $ /mx', function (Text $content) use($target) { // Remove block quote marker plus surrounding whitespace on each line $content->replace('/^[ ]{0,3}\\>[ ]?/m', ''); $blockquote = new Blockquote(); $target->addChild($blockquote); $this->first->parseBlock($content, $blockquote); }, function (Text $part) use($target) { $this->next->parseBlock($part, $target); }); }
/** * Parse the given content. * * Any newly created nodes should be pushed to the stack. Any remaining content should be passed to the next parser * in the chain. * * @param Text $content * @param Container $target * @return void */ public function parseBlock(Text $content, Container $target) { $content->handle('{ ^(?: ([ ]{0,3}) #1 Initial indentation ( #2 Fence ([`~]) #3 The fence character (` or ~) \\3{2,} # At least two remaining fence characters ) ([^`\\n]*?)? #4 Code language [optional] (?: \\n(.*?) #5 Code block )? (?:(?<=\\n)([ ]{0,3}\\2\\3*[ ]*)|\\z) # Closing fence or end of document )$ }msx', function (Text $whole, Text $whitespace, Text $fence, Text $fenceChar, Text $lang, Text $code = null) use($target) { $leading = $whitespace->getLength(); $code = $code ?: new Text(); $language = new Text(explode(' ', $lang->trim())[0]); $language->decodeEntities(); // Remove all leading whitespace from content lines if ($leading > 0) { $code->replace("/^[ ]{0,{$leading}}/m", ''); } $target->addChild(new CodeBlock($code, $language)); }, function (Text $part) use($target) { $this->next->parseBlock($part, $target); }); }
/** * Parse the given content. * * Any newly created nodes should be pushed to the stack. Any remaining content should be passed to the next parser * in the chain. * * @param Text $content * @param Container $target * @return void */ public function parseBlock(Text $content, Container $target) { $content->handle('{ (?: # Ensure blank line before (or beginning of subject) \\A\\s*\\n?| \\n\\s*\\n ) [ ]{4} # four leading spaces .+ (?: # optionally more spaces (?: # blank lines in between are okay \\n[ ]* )* \\n [ ]{4} .+ )* $ }mx', function (Text $code) use($target) { // Remove leading blank lines $code->replace('/^(\\s*\\n)*/', ''); // Remove indent $code->replace('/^[ ]{1,4}/m', ''); $code->append("\n"); $target->addChild(new CodeBlock($code)); }, function (Text $part) use($target) { $this->next->parseBlock($part, $target); }); }
/** * Parse the given content. * * Any newly created nodes should be pushed to the stack. Any remaining content should be passed to the next parser * in the chain. * * @param Text $content * @param Container $target * @return void */ public function parseBlock(Text $content, Container $target) { $content->handle('/^\\s*$/m', function (Text $line) use($target) { $target->addChild(new BlankLine($line)); }, function (Text $part) use($target) { $paragraph = new Paragraph($part); $target->addChild($paragraph); $this->inlineParser->queue($paragraph->getText(), $paragraph); }); }
/** * Parse the given content. * * Any newly created nodes should be pushed to the stack. Any remaining content should be passed to the next parser * in the chain. * * @param Text $content * @param Container $target * @return void */ public function parseBlock(Text $content, Container $target) { $content->handle('{ ^[ ]{0,3} # Optional leading spaces (\\#{1,6}) # $1 = string of #\'s (([ ].+?)??) # $2 = Header text ([ ]\\#*[ ]*)? # optional closing #\'s (not counted) $ }mx', function (Text $whole, Text $marks, Text $content) use($target) { $level = $marks->getLength(); $heading = new Heading($content->trim(), $level); $target->addChild($heading); $this->inlineParser->queue($heading->getText(), $heading); }, function (Text $part) use($target) { $this->next->parseBlock($part, $target); }); }
/** * Parse the given content. * * Any newly created nodes should be pushed to the stack. Any remaining content should be passed to the next parser * in the chain. * * @param Text $content * @param Container $target * @return void */ public function parseBlock(Text $content, Container $target) { $content->handle('{ ^ [ ]{0,3} ([^>\\-*=\\ \\n].*) [ ]* \\n [ ]{0,3} (=+|-+) [ ]* \\n* $ }mx', function (Text $whole, Text $content, Text $mark) use($target) { $level = substr($mark, 0, 1) == '=' ? 1 : 2; $heading = new Heading($content->trim(), $level); $target->addChild($heading); $this->inlineParser->queue($heading->getText(), $heading); }, function (Text $part) use($target) { $this->next->parseBlock($part, $target); }); }
/** * Parse the given content. * * Any newly created nodes should be pushed to the stack. Any remaining content should be passed to the next parser * in the chain. * * @param Text $content * @param Container $target * @return void */ public function parseBlock(Text $content, Container $target) { $tags = implode('|', $this->getValidTags()); $content->handle('{ ^ # starts at the beginning or with a newline [ ]{0,3} # up to 3 leading spaces allowed (?: # start with one of the following... \\<(?:' . $tags . ')\\s*/?\\>?| # an opening HTML tag, or \\</(?:' . $tags . ')\\s*\\>| # a closing HTML tag, or \\<!--(-(?!-)|[^\\-])*?--\\>| # a HTML comment, or \\<\\?.*?\\?\\>| # a processing instruction, or \\<![A-Z]+\\s+[^>]+\\>| # an element type declaration, or \\<!\\[CDATA\\[.*?\\]\\]\\> # a CDATA section ) .*? # match everything until... ((?=\\n[ ]*\\n)|\\Z) # we encounter an empty line or the end }imsx', function (Text $content) use($target) { $block = new HTMLBlock($content); $target->addChild($block); }, function (Text $part) use($target) { $this->next->parseBlock($part, $target); }); }
public function render(Container $root) { $this->buffer = new Text(); $root->visit($this); return $this->buffer; }
protected function parseOrderedLists(Text $content, Container $target) { $content->handle('{ ^ ([ ]{0,3}) # $1 - initial indent ([0-9]+)([.)]) # $2 - list marker; $3 - punctuation (?| ([ ]{1,4}) # $4 - list indent [^ ].* | () # ... which can also be empty ) ( \\n\\n? \\1[ ]{2}\\4 .* )* ( (?: \\n \\1[0-9]+\\3\\4 [^ ].* | # empty items \\n \\1\\2 | # Lazy continuation lines \\n [ ]* (?: [^0-9>\\-+*=\\ \\n] | [0-9]+[^.)] ) [^\\n]* ) ( \\n\\n? \\1[ ]{2}\\4 .* )* )* $ }mx', function (Text $content, Text $i, Text $start, Text $punctuation, Text $indent) use($target) { $isTerse = !$content->match('/^[ ]*$/m'); $lines = explode("\n", $content->getString()); $start = $start->getString(); $indentLength = $i->getLength() + $indent->getLength() + 2; $list = new ListBlock('ol', $isTerse, $start); // Go through all the lines to assemble the list items $curItem = substr(array_shift($lines), $indentLength) . "\n"; foreach ($lines as $line) { if (preg_match('/^[0-9]+' . preg_quote($punctuation) . '/', $line)) { $this->addItemToList($curItem, $list); $curItem = substr($line, $indentLength) . "\n"; } else { $curItem .= $this->unindentLine($line, $indentLength) . "\n"; } } $this->addItemToList($curItem, $list); $target->addChild($list); }, function (Text $part) use($target) { $this->next->parseBlock($part, $target); }); }
protected function handle(Text $content, $mark, Container $target, callable $next) { $content->handle($this->getPattern($mark), function () use($target) { $target->addChild(new HorizontalRule()); }, $next); }
public function visit(NodeVisitorInterface $visitor) { $visitor->enterBlockquote($this); parent::visit($visitor); $visitor->leaveBlockquote($this); }
public function visit(NodeVisitorInterface $visitor) { $visitor->enterListBlock($this); parent::visit($visitor); $visitor->leaveListBlock($this); }