/** * @param ContextInterface $context * @param Cursor $cursor * * @return bool */ public function parse(ContextInterface $context, Cursor $cursor) { $tmpCursor = clone $cursor; $indent = $tmpCursor->advanceWhileMatches(' ', 3); $rest = $tmpCursor->getRemainder(); $data = new ListData(); if ($matches = RegexHelper::matchAll('/^[*+-]( +|$)/', $rest)) { $spacesAfterMarker = strlen($matches[1]); $data->type = ListBlock::TYPE_UNORDERED; $data->delimiter = null; $data->bulletChar = $matches[0][0]; } elseif ($matches = RegexHelper::matchAll('/^(\\d+)([.)])( +|$)/', $rest)) { $spacesAfterMarker = strlen($matches[3]); $data->type = ListBlock::TYPE_ORDERED; $data->start = intval($matches[1]); $data->delimiter = $matches[2]; $data->bulletChar = null; } else { return false; } $data->padding = $this->calculateListMarkerPadding($matches[0], $spacesAfterMarker, $rest); $cursor->advanceToFirstNonSpace(); $cursor->advanceBy($data->padding); // list item $data->markerOffset = $indent; // add the list if needed $container = $context->getContainer(); if (!$container || !$context->getContainer() instanceof ListBlock || !$data->equals($container->getListData())) { $context->addBlock(new ListBlock($data)); } // add the list item $context->addBlock(new ListItem($data)); return true; }
/** * @param ContextInterface $context * @param Cursor $cursor */ public function handleRemainingContents(ContextInterface $context, Cursor $cursor) { if ($cursor->isBlank()) { return; } $context->addBlock(new Paragraph()); $cursor->advanceToFirstNonSpace(); $context->getTip()->addLine($cursor->getRemainder()); }
public function matchesNextLine(Cursor $cursor) { if (!$cursor->isIndented() && $cursor->getFirstNonSpaceCharacter() === '>') { $cursor->advanceToFirstNonSpace(); $cursor->advance(); $cursor->advanceBySpaceOrTab(); return true; } return false; }
public function matchesNextLine(Cursor $cursor) { if ($cursor->isBlank() && $this->firstChild !== null) { $cursor->advanceToFirstNonSpace(); } elseif ($cursor->getIndent() >= $this->listData->markerOffset + $this->listData->padding) { $cursor->advanceBy($this->listData->markerOffset + $this->listData->padding, true); } else { return false; } return true; }
public function matchesNextLine(Cursor $cursor) { if ($cursor->getIndent() >= IndentedCodeParser::CODE_INDENT_LEVEL) { $cursor->advanceBy(IndentedCodeParser::CODE_INDENT_LEVEL); } elseif ($cursor->isBlank()) { $cursor->advanceToFirstNonSpace(); } else { return false; } return true; }
public function matchesNextLine(Cursor $cursor) { if ($cursor->isIndented()) { $cursor->advanceBy(Cursor::INDENT_LEVEL, true); } elseif ($cursor->isBlank()) { $cursor->advanceToFirstNonSpace(); } else { return false; } return true; }
/** * @param ContextInterface $context * @param Cursor $cursor * * @return bool */ public function parse(ContextInterface $context, Cursor $cursor) { if ($cursor->getFirstNonSpaceCharacter() !== '>') { return false; } $cursor->advanceToFirstNonSpace(); $cursor->advance(); if ($cursor->getCharacter() === ' ') { $cursor->advance(); } $context->addBlock(new BlockQuote()); return true; }
/** * @param ContextInterface $context * @param Cursor $cursor * * @return bool */ public function parse(ContextInterface $context, Cursor $cursor) { $previousState = $cursor->saveState(); $indent = $cursor->advanceToFirstNonSpace(); $fence = $cursor->match('/^`{3,}(?!.*`)|^~{3,}(?!.*~)/'); if (!$fence) { $cursor->restoreState($previousState); return false; } // fenced code block $fenceLength = strlen($fence); $context->addBlock(new FencedCode($fenceLength, $fence[0], $indent)); return true; }
public function matchesNextLine(Cursor $cursor) { if ($cursor->getIndent() <= 3 && in_array($cursor->getFirstNonSpaceCharacter(), static::getIconBlockTypes())) { $cursor->advanceToFirstNonSpace(); if ($cursor->peek() === '>') { $cursor->advanceBy(2); if ($cursor->getCharacter() === ' ') { $cursor->advance(); } return true; } } return false; }
public static function parse(Cursor $cursor) { if (null === self::$regexp) { $regex = RegexHelper::getInstance(); self::$regexp = sprintf('/^\\s*([.#][_a-z0-9-]+|%s%s)(?<!})\\s*/i', $regex->getPartialRegex(RegexHelper::ATTRIBUTENAME), $regex->getPartialRegex(RegexHelper::ATTRIBUTEVALUESPEC)); } $state = $cursor->saveState(); $cursor->advanceToFirstNonSpace(); if ('{' !== $cursor->getCharacter()) { $cursor->restoreState($state); return []; } $cursor->advanceBy(1); if (':' === $cursor->getCharacter()) { $cursor->advanceBy(1); } $attributes = []; while ($attribute = trim($cursor->match(self::$regexp))) { if ('#' === $attribute[0]) { $attributes['id'] = substr($attribute, 1); continue; } if ('.' === $attribute[0]) { $attributes['class'][] = substr($attribute, 1); continue; } list($name, $value) = explode('=', $attribute, 2); $first = $value[0]; $last = substr($value, -1); if (('"' === $first && '"' === $last || "'" === $first && "'" === $last) && strlen($value) > 1) { $value = substr($value, 1, -1); } if ('class' === strtolower(trim($name))) { foreach (array_filter(explode(' ', trim($value))) as $class) { $attributes['class'][] = $class; } } else { $attributes[trim($name)] = trim($value); } } if (0 === $cursor->advanceWhileMatches('}')) { $cursor->restoreState($state); return []; } if (isset($attributes['class'])) { $attributes['class'] = implode(' ', $attributes['class']); } return $attributes; }
/** * @param ContextInterface $context * @param Cursor $cursor * * @return bool */ public function parse(ContextInterface $context, Cursor $cursor) { if ($cursor->getFirstNonSpaceCharacter() !== 'A' || $cursor->getCharacter($cursor->getFirstNonSpacePosition() + 1) !== '>') { return false; } $cursor->advanceToFirstNonSpace(); if ($cursor->peek() === '>') { $cursor->advanceBy(2); if ($cursor->getCharacter() === ' ') { $cursor->advance(); } } $context->addBlock(new Aside()); return true; }
/** * @param ContextInterface $context * @param Cursor $cursor * * @return bool */ public function parse(ContextInterface $context, Cursor $cursor) { if ($cursor->isIndented()) { return false; } $previousState = $cursor->saveState(); $cursor->advanceToFirstNonSpace(); $fence = $cursor->match('/^\\[TOC\\]/'); if (is_null($fence)) { $cursor->restoreState($previousState); return false; } $context->addBlock(new TableOfContents()); return true; }
/** * @param ContextInterface $context * @param Cursor $cursor * * @return bool */ public function parse(ContextInterface $context, Cursor $cursor) { if (!in_array($cursor->getFirstNonSpaceCharacter(), IconBlock::getIconBlockTypes()) || $cursor->getCharacter($cursor->getFirstNonSpacePosition() + 1) !== '>') { return false; } $type = $cursor->getFirstNonSpaceCharacter(); $cursor->advanceToFirstNonSpace(); if ($cursor->peek() === '>') { $cursor->advanceBy(2); if ($cursor->getCharacter() === ' ') { $cursor->advance(); } } $context->addBlock(new IconBlock($type)); return true; }
/** * @param ContextInterface $context * @param Cursor $cursor * * @return bool */ public function parse(ContextInterface $context, Cursor $cursor) { $match = RegexHelper::matchAll('/^#{1,6}(?: +|$)/', $cursor->getLine(), $cursor->getFirstNonSpacePosition()); if (!$match) { return false; } $cursor->advanceToFirstNonSpace(); $cursor->advanceBy(strlen($match[0])); $level = strlen(trim($match[0])); $str = $cursor->getRemainder(); $str = preg_replace('/^ *#+ *$/', '', $str); $str = preg_replace('/ +#+ *$/', '', $str); $context->addBlock(new Header($level, $str)); $context->setBlocksParsed(true); return true; }
/** * @param ContextInterface $context * @param Cursor $cursor * * @return bool */ public function parse(ContextInterface $context, Cursor $cursor) { if ($cursor->isIndented() && !$context->getContainer() instanceof ListBlock) { return false; } $tmpCursor = clone $cursor; $tmpCursor->advanceToFirstNonSpace(); $rest = $tmpCursor->getRemainder(); $data = new ListData(); $data->markerOffset = $cursor->getIndent(); if ($matches = RegexHelper::matchAll('/^[*+-]/', $rest)) { $data->type = ListBlock::TYPE_UNORDERED; $data->delimiter = null; $data->bulletChar = $matches[0][0]; } elseif (($matches = RegexHelper::matchAll('/^(\\d{1,9})([.)])/', $rest)) && (!$context->getContainer() instanceof Paragraph || $matches[1] === '1')) { $data->type = ListBlock::TYPE_ORDERED; $data->start = intval($matches[1]); $data->delimiter = $matches[2]; $data->bulletChar = null; } else { return false; } $markerLength = strlen($matches[0]); // Make sure we have spaces after $nextChar = $tmpCursor->peek($markerLength); if (!($nextChar === null || $nextChar === "\t" || $nextChar === ' ')) { return false; } // If it interrupts paragraph, make sure first line isn't blank if ($context->getContainer() instanceof Paragraph && !RegexHelper::matchAt(RegexHelper::REGEX_NON_SPACE, $rest, $markerLength)) { return false; } // We've got a match! Advance offset and calculate padding $cursor->advanceToFirstNonSpace(); // to start of marker $cursor->advanceBy($markerLength, true); // to end of marker $data->padding = $this->calculateListMarkerPadding($cursor, $markerLength); // add the list if needed $container = $context->getContainer(); if (!$container || !$context->getContainer() instanceof ListBlock || !$data->equals($container->getListData())) { $context->addBlock(new ListBlock($data)); } // add the list item $context->addBlock(new ListItem($data)); return true; }
/** * @param ContextInterface $context * @param Cursor $cursor * * @return bool */ public function parse(ContextInterface $context, Cursor $cursor) { if ($cursor->isIndented()) { return false; } if ($cursor->getFirstNonSpaceCharacter() !== '<') { return false; } $savedState = $cursor->saveState(); $cursor->advanceToFirstNonSpace(); $line = $cursor->getRemainder(); for ($blockType = 1; $blockType <= 7; $blockType++) { $match = RegexHelper::matchAt(RegexHelper::getHtmlBlockOpenRegex($blockType), $line); if ($match !== null && ($blockType < 7 || !$context->getContainer() instanceof Paragraph)) { $cursor->restoreState($savedState); $context->addBlock(new HtmlBlock($blockType)); $context->setBlocksParsed(true); return true; } } $cursor->restoreState($savedState); return false; }
/** * @param ContextInterface $context * @param Cursor $cursor */ public function handleRemainingContents(ContextInterface $context, Cursor $cursor) { // create paragraph container for line $context->addBlock(new Paragraph()); $cursor->advanceToFirstNonSpace(); $context->getTip()->addLine($cursor->getRemainder()); }
/** * @param ContextInterface $context * @param Cursor $cursor */ public function handleRemainingContents(ContextInterface $context, Cursor $cursor) { $cursor->advanceToFirstNonSpace(); $context->getTip()->addLine($cursor->getRemainder()); }
/** * @param Cursor $cursor * * @return array|bool */ protected function tryParseInlineLinkAndTitle(Cursor $cursor) { $cursor->advance(); $cursor->advanceToFirstNonSpace(); if (($dest = LinkParserHelper::parseLinkDestination($cursor)) === null) { return false; } $cursor->advanceToFirstNonSpace(); $title = null; // make sure there's a space before the title: if (preg_match('/^\\s/', $cursor->peek(-1))) { $title = LinkParserHelper::parseLinkTitle($cursor) ?: ''; } $cursor->advanceToFirstNonSpace(); if ($cursor->match('/^\\)/') === null) { return false; } return ['url' => $dest, 'title' => $title]; }
/** * @param Cursor $cursor * @param ReferenceMap $referenceMap * @param Delimiter $opener * @param int $startPos * * @return Reference|null */ protected function tryParseReference(Cursor $cursor, ReferenceMap $referenceMap, Delimiter $opener, $startPos) { $savePos = $cursor->saveState(); $cursor->advanceToFirstNonSpace(); $beforeLabel = $cursor->getPosition(); $n = LinkParserHelper::parseLinkLabel($cursor); if ($n === 0 || $n === 2) { // Empty or missing second label $reflabel = mb_substr($cursor->getLine(), $opener->getIndex(), $startPos - $opener->getIndex(), 'utf-8'); } else { $reflabel = mb_substr($cursor->getLine(), $beforeLabel + 1, $n - 2, 'utf-8'); } if ($n === 0) { // If shortcut reference link, rewind before spaces we skipped $cursor->restoreState($savePos); } return $referenceMap->getReference($reflabel); }
/** * @param Cursor $cursor * * @return array|bool */ protected function tryParseInlineLinkAndTitle(Cursor $cursor) { if ($cursor->getCharacter() !== '(') { return false; } $previousState = $cursor->saveState(); $cursor->advance(); $cursor->advanceToFirstNonSpace(); if (($dest = LinkParserHelper::parseLinkDestination($cursor)) === null) { $cursor->restoreState($previousState); return false; } $cursor->advanceToFirstNonSpace(); $title = null; // make sure there's a space before the title: if (preg_match(RegexHelper::REGEX_WHITESPACE_CHAR, $cursor->peek(-1))) { $title = LinkParserHelper::parseLinkTitle($cursor) ?: ''; } $cursor->advanceToFirstNonSpace(); if ($cursor->match('/^\\)/') === null) { $cursor->restoreState($previousState); return false; } return ['url' => $dest, 'title' => $title]; }