/vendor/s9e/text-formatter/src/Plugins/Litedown/Parser.php
PHP | 735 lines | 729 code | 1 blank | 5 comment | 116 complexity | 3f02313082e483dca6e86b29df9831f3 MD5 | raw file
Possible License(s): BSD-3-Clause
- <?php
- /*
- * @package s9e\TextFormatter
- * @copyright Copyright (c) 2010-2017 The s9e Authors
- * @license http://www.opensource.org/licenses/mit-license.php The MIT License
- */
- namespace s9e\TextFormatter\Plugins\Litedown;
- use s9e\TextFormatter\Parser as Rules;
- use s9e\TextFormatter\Parser\Tag;
- use s9e\TextFormatter\Plugins\ParserBase;
- class Parser extends ParserBase
- {
- protected $hasEscapedChars;
- protected $hasRefs;
- protected $refs;
- protected $text;
- public function parse($text, array $matches)
- {
- $this->init($text);
- $this->matchBlockLevelMarkup();
- $this->matchLinkReferences();
- $this->matchInlineCode();
- $this->matchImages();
- $this->matchLinks();
- $this->matchStrikethrough();
- $this->matchSuperscript();
- $this->matchEmphasis();
- $this->matchForcedLineBreaks();
- unset($this->text);
- }
- protected function addImageTag($startTagPos, $endTagPos, $endTagLen, $linkInfo, $alt)
- {
- $tag = $this->parser->addTagPair('IMG', $startTagPos, 2, $endTagPos, $endTagLen);
- $this->setLinkAttributes($tag, $linkInfo, 'src');
- $tag->setAttribute('alt', $this->decode($alt));
- $this->overwrite($startTagPos, $endTagPos + $endTagLen - $startTagPos);
- }
- protected function addInlineCodeTags($left, $right)
- {
- $startTagPos = $left['pos'];
- $startTagLen = $left['len'] + $left['trimAfter'];
- $endTagPos = $right['pos'] - $right['trimBefore'];
- $endTagLen = $right['len'] + $right['trimBefore'];
- $this->parser->addTagPair('C', $startTagPos, $startTagLen, $endTagPos, $endTagLen);
- $this->overwrite($startTagPos, $endTagPos + $endTagLen - $startTagPos);
- }
- protected function addLinkTag($startTagPos, $endTagPos, $endTagLen, $linkInfo)
- {
- $priority = ($endTagLen === 1) ? 1 : -1;
- $tag = $this->parser->addTagPair('URL', $startTagPos, 1, $endTagPos, $endTagLen, $priority);
- $this->setLinkAttributes($tag, $linkInfo, 'url');
- $this->overwrite($startTagPos, 1);
- $this->overwrite($endTagPos, $endTagLen);
- }
- protected function closeList(array $list, $textBoundary)
- {
- $this->parser->addEndTag('LIST', $textBoundary, 0)->pairWith($list['listTag']);
- $this->parser->addEndTag('LI', $textBoundary, 0)->pairWith($list['itemTag']);
- if ($list['tight'])
- foreach ($list['itemTags'] as $itemTag)
- $itemTag->removeFlags(Rules::RULE_CREATE_PARAGRAPHS);
- }
- protected function computeQuoteIgnoreLen($str, $maxQuoteDepth)
- {
- $remaining = $str;
- while (--$maxQuoteDepth >= 0)
- $remaining = \preg_replace('/^ *> ?/', '', $remaining);
- return \strlen($str) - \strlen($remaining);
- }
- protected function decode($str)
- {
- if ($this->config['decodeHtmlEntities'] && \strpos($str, '&') !== \false)
- $str = \html_entity_decode($str, \ENT_QUOTES, 'UTF-8');
- $str = \str_replace("\x1A", '', $str);
- if ($this->hasEscapedChars)
- $str = \strtr(
- $str,
- array(
- "\x1B0" => '!', "\x1B1" => '"', "\x1B2" => "'", "\x1B3" => '(',
- "\x1B4" => ')', "\x1B5" => '*', "\x1B6" => '[', "\x1B7" => '\\',
- "\x1B8" => ']', "\x1B9" => '^', "\x1BA" => '_', "\x1BB" => '`',
- "\x1BC" => '~'
- )
- );
- return $str;
- }
- protected function encode($str)
- {
- return \strtr(
- $str,
- array(
- '\\!' => "\x1B0", '\\"' => "\x1B1", "\\'" => "\x1B2", '\\(' => "\x1B3",
- '\\)' => "\x1B4", '\\*' => "\x1B5", '\\[' => "\x1B6", '\\\\' => "\x1B7",
- '\\]' => "\x1B8", '\\^' => "\x1B9", '\\_' => "\x1BA", '\\`' => "\x1BB",
- '\\~' => "\x1BC"
- )
- );
- }
- protected function getAtxHeaderEndTagLen($startPos, $endPos)
- {
- $content = \substr($this->text, $startPos, $endPos - $startPos);
- \preg_match('/[ \\t]*#*[ \\t]*$/', $content, $m);
- return \strlen($m[0]);
- }
- protected function getSetextLines()
- {
- $setextLines = array();
- if (\strpos($this->text, '-') === \false && \strpos($this->text, '=') === \false)
- return $setextLines;
- $regexp = '/^(?=[-=>])(?:> ?)*(?=[-=])(?:-+|=+) *$/m';
- if (\preg_match_all($regexp, $this->text, $matches, \PREG_OFFSET_CAPTURE))
- foreach ($matches[0] as $_f570d26d)
- {
- list($match, $matchPos) = $_f570d26d;
- $endTagPos = $matchPos - 1;
- while ($endTagPos > 0 && $this->text[$endTagPos - 1] === ' ')
- --$endTagPos;
- $setextLines[$matchPos - 1] = array(
- 'endTagLen' => $matchPos + \strlen($match) - $endTagPos,
- 'endTagPos' => $endTagPos,
- 'quoteDepth' => \substr_count($match, '>'),
- 'tagName' => ($match[0] === '=') ? 'H1' : 'H2'
- );
- }
- return $setextLines;
- }
- protected function getEmphasisByBlock($regexp, $pos)
- {
- $block = array();
- $blocks = array();
- $breakPos = \strpos($this->text, "\x17", $pos);
- \preg_match_all($regexp, $this->text, $matches, \PREG_OFFSET_CAPTURE, $pos);
- foreach ($matches[0] as $m)
- {
- $matchPos = $m[1];
- $matchLen = \strlen($m[0]);
- if ($matchPos > $breakPos)
- {
- $blocks[] = $block;
- $block = array();
- $breakPos = \strpos($this->text, "\x17", $matchPos);
- }
- if (!$this->ignoreEmphasis($matchPos, $matchLen))
- $block[] = array($matchPos, $matchLen);
- }
- $blocks[] = $block;
- return $blocks;
- }
- protected function getInlineCodeMarkers()
- {
- $pos = \strpos($this->text, '`');
- if ($pos === \false)
- return array();
- \preg_match_all(
- '/(`+)(\\s*)[^\\x17`]*/',
- \str_replace("\x1BB", '\\`', $this->text),
- $matches,
- \PREG_OFFSET_CAPTURE | \PREG_SET_ORDER,
- $pos
- );
- $trimNext = 0;
- $markers = array();
- foreach ($matches as $m)
- {
- $markers[] = array(
- 'pos' => $m[0][1],
- 'len' => \strlen($m[1][0]),
- 'trimBefore' => $trimNext,
- 'trimAfter' => \strlen($m[2][0]),
- 'next' => $m[0][1] + \strlen($m[0][0])
- );
- $trimNext = \strlen($m[0][0]) - \strlen(\rtrim($m[0][0]));
- }
- return $markers;
- }
- protected function getLabels()
- {
- \preg_match_all(
- '/\\[((?:[^\\x17[\\]]|\\[[^\\x17[\\]]*\\])*)\\]/',
- $this->text,
- $matches,
- \PREG_OFFSET_CAPTURE
- );
- $labels = array();
- foreach ($matches[1] as $m)
- $labels[$m[1] - 1] = \strtolower($m[0]);
- return $labels;
- }
- protected function ignoreEmphasis($matchPos, $matchLen)
- {
- return ($this->text[$matchPos] === '_' && $matchLen === 1 && $this->isSurroundedByAlnum($matchPos, $matchLen));
- }
- protected function init($text)
- {
- if (\strpos($text, '\\') === \false || !\preg_match('/\\\\[!"\'()*[\\\\\\]^_`~]/', $text))
- $this->hasEscapedChars = \false;
- else
- {
- $this->hasEscapedChars = \true;
- $text = $this->encode($text);
- }
- $text .= "\n\n\x17";
- $this->text = $text;
- }
- protected function isAlnum($chr)
- {
- return (\strpos(' abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789', $chr) > 0);
- }
- protected function isSurroundedByAlnum($matchPos, $matchLen)
- {
- return ($matchPos > 0 && $this->isAlnum($this->text[$matchPos - 1]) && $this->isAlnum($this->text[$matchPos + $matchLen]));
- }
- protected function markBoundary($pos)
- {
- $this->text[$pos] = "\x17";
- }
- protected function matchBlockLevelMarkup()
- {
- $codeFence = \null;
- $codeIndent = 4;
- $codeTag = \null;
- $lineIsEmpty = \true;
- $lists = array();
- $listsCnt = 0;
- $newContext = \false;
- $quotes = array();
- $quotesCnt = 0;
- $setextLines = $this->getSetextLines();
- $textBoundary = 0;
- $regexp = '/^(?:(?=[-*+\\d \\t>`~#_])((?: {0,3}> ?)+)?([ \\t]+)?(\\* *\\* *\\*[* ]*$|- *- *-[- ]*$|_ *_ *_[_ ]*$|=+$)?((?:[-*+]|\\d+\\.)[ \\t]+(?=\\S))?[ \\t]*(#{1,6}[ \\t]+|```+[^`\\n]*$|~~~+[^~\\n]*$)?)?/m';
- \preg_match_all($regexp, $this->text, $matches, \PREG_OFFSET_CAPTURE | \PREG_SET_ORDER);
- foreach ($matches as $m)
- {
- $matchPos = $m[0][1];
- $matchLen = \strlen($m[0][0]);
- $ignoreLen = 0;
- $quoteDepth = 0;
- $continuation = !$lineIsEmpty;
- $lfPos = \strpos($this->text, "\n", $matchPos);
- $lineIsEmpty = ($lfPos === $matchPos + $matchLen && empty($m[3][0]) && empty($m[4][0]) && empty($m[5][0]));
- $breakParagraph = ($lineIsEmpty && $continuation);
- if (!empty($m[1][0]))
- {
- $quoteDepth = \substr_count($m[1][0], '>');
- $ignoreLen = \strlen($m[1][0]);
- if (isset($codeTag) && $codeTag->hasAttribute('quoteDepth'))
- {
- $quoteDepth = \min($quoteDepth, $codeTag->getAttribute('quoteDepth'));
- $ignoreLen = $this->computeQuoteIgnoreLen($m[1][0], $quoteDepth);
- }
- $this->overwrite($matchPos, $ignoreLen);
- }
- if ($quoteDepth < $quotesCnt && !$continuation)
- {
- $newContext = \true;
- do
- {
- $this->parser->addEndTag('QUOTE', $textBoundary, 0)
- ->pairWith(\array_pop($quotes));
- }
- while ($quoteDepth < --$quotesCnt);
- }
- if ($quoteDepth > $quotesCnt && !$lineIsEmpty)
- {
- $newContext = \true;
- do
- {
- $tag = $this->parser->addStartTag('QUOTE', $matchPos, 0, $quotesCnt - 999);
- $quotes[] = $tag;
- }
- while ($quoteDepth > ++$quotesCnt);
- }
- $indentWidth = 0;
- $indentPos = 0;
- if (!empty($m[2][0]) && !$codeFence)
- {
- $indentStr = $m[2][0];
- $indentLen = \strlen($indentStr);
- do
- {
- if ($indentStr[$indentPos] === ' ')
- ++$indentWidth;
- else
- $indentWidth = ($indentWidth + 4) & ~3;
- }
- while (++$indentPos < $indentLen && $indentWidth < $codeIndent);
- }
- if (isset($codeTag) && !$codeFence && $indentWidth < $codeIndent && !$lineIsEmpty)
- $newContext = \true;
- if ($newContext)
- {
- $newContext = \false;
- if (isset($codeTag))
- {
- $this->overwrite($codeTag->getPos(), $textBoundary - $codeTag->getPos());
- $endTag = $this->parser->addEndTag('CODE', $textBoundary, 0, -1);
- $endTag->pairWith($codeTag);
- $codeTag = \null;
- $codeFence = \null;
- }
- foreach ($lists as $list)
- $this->closeList($list, $textBoundary);
- $lists = array();
- $listsCnt = 0;
- if ($matchPos)
- $this->markBoundary($matchPos - 1);
- }
- if ($indentWidth >= $codeIndent)
- {
- if (isset($codeTag) || !$continuation)
- {
- $ignoreLen += $indentPos;
- if (!isset($codeTag))
- $codeTag = $this->parser->addStartTag('CODE', $matchPos + $ignoreLen, 0, -999);
- $m = array();
- }
- }
- else
- {
- $hasListItem = !empty($m[4][0]);
- if (!$indentWidth && !$continuation && !$hasListItem)
- $listIndex = -1;
- elseif ($continuation && !$hasListItem)
- $listIndex = $listsCnt - 1;
- elseif (!$listsCnt)
- if ($hasListItem && (!$continuation || $this->text[$matchPos - 1] === "\x17"))
- $listIndex = 0;
- else
- $listIndex = -1;
- else
- {
- $listIndex = 0;
- while ($listIndex < $listsCnt && $indentWidth > $lists[$listIndex]['maxIndent'])
- ++$listIndex;
- }
- while ($listIndex < $listsCnt - 1)
- {
- $this->closeList(\array_pop($lists), $textBoundary);
- --$listsCnt;
- }
- if ($listIndex === $listsCnt && !$hasListItem)
- --$listIndex;
- if ($hasListItem && $listIndex >= 0)
- {
- $breakParagraph = \true;
- $tagPos = $matchPos + $ignoreLen + $indentPos;
- $tagLen = \strlen($m[4][0]);
- $itemTag = $this->parser->addStartTag('LI', $tagPos, $tagLen);
- $this->overwrite($tagPos, $tagLen);
- if ($listIndex < $listsCnt)
- {
- $this->parser->addEndTag('LI', $textBoundary, 0)
- ->pairWith($lists[$listIndex]['itemTag']);
- $lists[$listIndex]['itemTag'] = $itemTag;
- $lists[$listIndex]['itemTags'][] = $itemTag;
- }
- else
- {
- ++$listsCnt;
- if ($listIndex)
- {
- $minIndent = $lists[$listIndex - 1]['maxIndent'] + 1;
- $maxIndent = \max($minIndent, $listIndex * 4);
- }
- else
- {
- $minIndent = 0;
- $maxIndent = $indentWidth;
- }
- $listTag = $this->parser->addStartTag('LIST', $tagPos, 0);
- if (\strpos($m[4][0], '.') !== \false)
- {
- $listTag->setAttribute('type', 'decimal');
- $start = (int) $m[4][0];
- if ($start !== 1)
- $listTag->setAttribute('start', $start);
- }
- $lists[] = array(
- 'listTag' => $listTag,
- 'itemTag' => $itemTag,
- 'itemTags' => array($itemTag),
- 'minIndent' => $minIndent,
- 'maxIndent' => $maxIndent,
- 'tight' => \true
- );
- }
- }
- if ($listsCnt && !$continuation && !$lineIsEmpty)
- if (\count($lists[0]['itemTags']) > 1 || !$hasListItem)
- {
- foreach ($lists as &$list)
- $list['tight'] = \false;
- unset($list);
- }
- $codeIndent = ($listsCnt + 1) * 4;
- }
- if (isset($m[5]))
- {
- if ($m[5][0][0] === '#')
- {
- $startTagLen = \strlen($m[5][0]);
- $startTagPos = $matchPos + $matchLen - $startTagLen;
- $endTagLen = $this->getAtxHeaderEndTagLen($matchPos + $matchLen, $lfPos);
- $endTagPos = $lfPos - $endTagLen;
- $this->parser->addTagPair('H' . \strspn($m[5][0], '#', 0, 6), $startTagPos, $startTagLen, $endTagPos, $endTagLen);
- $this->markBoundary($startTagPos);
- $this->markBoundary($lfPos);
- if ($continuation)
- $breakParagraph = \true;
- }
- elseif ($m[5][0][0] === '`' || $m[5][0][0] === '~')
- {
- $tagPos = $matchPos + $ignoreLen;
- $tagLen = $lfPos - $tagPos;
- if (isset($codeTag) && $m[5][0] === $codeFence)
- {
- $endTag = $this->parser->addEndTag('CODE', $tagPos, $tagLen, -1);
- $endTag->pairWith($codeTag);
- $this->parser->addIgnoreTag($textBoundary, $tagPos - $textBoundary);
- $this->overwrite($codeTag->getPos(), $tagPos + $tagLen - $codeTag->getPos());
- $codeTag = \null;
- $codeFence = \null;
- }
- elseif (!isset($codeTag))
- {
- $codeTag = $this->parser->addStartTag('CODE', $tagPos, $tagLen);
- $codeFence = \substr($m[5][0], 0, \strspn($m[5][0], '`~'));
- $codeTag->setAttribute('quoteDepth', $quoteDepth);
- $this->parser->addIgnoreTag($tagPos + $tagLen, 1);
- $lang = \trim(\trim($m[5][0], '`~'));
- if ($lang !== '')
- $codeTag->setAttribute('lang', $lang);
- }
- }
- }
- elseif (!empty($m[3][0]) && !$listsCnt && $this->text[$matchPos + $matchLen] !== "\x17")
- {
- $this->parser->addSelfClosingTag('HR', $matchPos + $ignoreLen, $matchLen - $ignoreLen);
- $breakParagraph = \true;
- $this->markBoundary($lfPos);
- }
- elseif (isset($setextLines[$lfPos]) && $setextLines[$lfPos]['quoteDepth'] === $quoteDepth && !$lineIsEmpty && !$listsCnt && !isset($codeTag))
- {
- $this->parser->addTagPair(
- $setextLines[$lfPos]['tagName'],
- $matchPos + $ignoreLen,
- 0,
- $setextLines[$lfPos]['endTagPos'],
- $setextLines[$lfPos]['endTagLen']
- );
- $this->markBoundary($setextLines[$lfPos]['endTagPos'] + $setextLines[$lfPos]['endTagLen']);
- }
- if ($breakParagraph)
- {
- $this->parser->addParagraphBreak($textBoundary);
- $this->markBoundary($textBoundary);
- }
- if (!$lineIsEmpty)
- $textBoundary = $lfPos;
- if ($ignoreLen)
- $this->parser->addIgnoreTag($matchPos, $ignoreLen, 1000);
- }
- }
- protected function matchEmphasis()
- {
- $this->matchEmphasisByCharacter('*', '/\\*+/');
- $this->matchEmphasisByCharacter('_', '/_+/');
- }
- protected function matchEmphasisByCharacter($character, $regexp)
- {
- $pos = \strpos($this->text, $character);
- if ($pos === \false)
- return;
- foreach ($this->getEmphasisByBlock($regexp, $pos) as $block)
- $this->processEmphasisBlock($block);
- }
- protected function matchForcedLineBreaks()
- {
- $pos = \strpos($this->text, " \n");
- while ($pos !== \false)
- {
- $this->parser->addBrTag($pos + 2);
- $pos = \strpos($this->text, " \n", $pos + 3);
- }
- }
- protected function matchImages()
- {
- $pos = \strpos($this->text, '![');
- if ($pos === \false)
- return;
- if (\strpos($this->text, '](', $pos) !== \false)
- $this->matchInlineImages();
- if ($this->hasRefs)
- $this->matchReferenceImages();
- }
- protected function matchInlineImages()
- {
- \preg_match_all(
- '/!\\[(?:[^\\x17[\\]]|\\[[^\\x17[\\]]*\\])*\\]\\(( *(?:[^\\x17\\s()]|\\([^\\x17\\s()]*\\))*(?=[ )]) *(?:"[^\\x17]*?"|\'[^\\x17]*?\'|\\([^\\x17)]*\\))? *)\\)/',
- $this->text,
- $matches,
- \PREG_OFFSET_CAPTURE | \PREG_SET_ORDER
- );
- foreach ($matches as $m)
- {
- $linkInfo = $m[1][0];
- $startTagPos = $m[0][1];
- $endTagLen = 3 + \strlen($linkInfo);
- $endTagPos = $startTagPos + \strlen($m[0][0]) - $endTagLen;
- $alt = \substr($m[0][0], 2, \strlen($m[0][0]) - $endTagLen - 2);
- $this->addImageTag($startTagPos, $endTagPos, $endTagLen, $linkInfo, $alt);
- }
- }
- protected function matchReferenceImages()
- {
- \preg_match_all(
- '/!\\[((?:[^\\x17[\\]]|\\[[^\\x17[\\]]*\\])*)\\](?: ?\\[([^\\x17[\\]]+)\\])?/',
- $this->text,
- $matches,
- \PREG_OFFSET_CAPTURE | \PREG_SET_ORDER
- );
- foreach ($matches as $m)
- {
- $startTagPos = $m[0][1];
- $endTagPos = $startTagPos + 2 + \strlen($m[1][0]);
- $endTagLen = 1;
- $alt = $m[1][0];
- $id = $alt;
- if (isset($m[2][0], $this->refs[$m[2][0]]))
- {
- $endTagLen = \strlen($m[0][0]) - \strlen($alt) - 2;
- $id = $m[2][0];
- }
- elseif (!isset($this->refs[$id]))
- continue;
- $this->addImageTag($startTagPos, $endTagPos, $endTagLen, $this->refs[$id], $alt);
- }
- }
- protected function matchInlineCode()
- {
- $markers = $this->getInlineCodeMarkers();
- $i = -1;
- $cnt = \count($markers);
- while (++$i < ($cnt - 1))
- {
- $pos = $markers[$i]['next'];
- $j = $i;
- if ($this->text[$markers[$i]['pos']] !== '`')
- {
- ++$markers[$i]['pos'];
- --$markers[$i]['len'];
- }
- while (++$j < $cnt && $markers[$j]['pos'] === $pos)
- {
- if ($markers[$j]['len'] === $markers[$i]['len'])
- {
- $this->addInlineCodeTags($markers[$i], $markers[$j]);
- $i = $j;
- break;
- }
- $pos = $markers[$j]['next'];
- }
- }
- }
- protected function matchInlineLinks()
- {
- \preg_match_all(
- '/\\[(?:[^\\x17[\\]]|\\[[^\\x17[\\]]*\\])*\\]\\(( *(?:[^\\x17\\s()]|\\([^\\x17\\s()]*\\))*(?=[ )]) *(?:"[^\\x17]*?"|\'[^\\x17]*?\'|\\([^\\x17)]*\\))? *)\\)/',
- $this->text,
- $matches,
- \PREG_OFFSET_CAPTURE | \PREG_SET_ORDER
- );
- foreach ($matches as $m)
- {
- $linkInfo = $m[1][0];
- $startTagPos = $m[0][1];
- $endTagLen = 3 + \strlen($linkInfo);
- $endTagPos = $startTagPos + \strlen($m[0][0]) - $endTagLen;
- $this->addLinkTag($startTagPos, $endTagPos, $endTagLen, $linkInfo);
- }
- }
- protected function matchLinkReferences()
- {
- $this->hasRefs = \false;
- $this->refs = array();
- if (\strpos($this->text, ']:') === \false)
- return;
- $regexp = '/^\\x1A* {0,3}\\[([^\\x17\\]]+)\\]: *([^\\s\\x17]+ *(?:"[^\\x17]*?"|\'[^\\x17]*?\'|\\([^\\x17)]*\\))?)[^\\x17\\n]*\\n?/m';
- \preg_match_all($regexp, $this->text, $matches, \PREG_OFFSET_CAPTURE | \PREG_SET_ORDER);
- foreach ($matches as $m)
- {
- $this->parser->addIgnoreTag($m[0][1], \strlen($m[0][0]), -2);
- $id = \strtolower($m[1][0]);
- if (isset($this->refs[$id]))
- continue;
- $this->hasRefs = \true;
- $this->refs[$id] = $m[2][0];
- }
- }
- protected function matchLinks()
- {
- if (\strpos($this->text, '](') !== \false)
- $this->matchInlineLinks();
- if ($this->hasRefs)
- $this->matchReferenceLinks();
- }
- protected function matchReferenceLinks()
- {
- $labels = $this->getLabels();
- foreach ($labels as $startTagPos => $id)
- {
- $labelPos = $startTagPos + 2 + \strlen($id);
- $endTagPos = $labelPos - 1;
- $endTagLen = 1;
- if ($this->text[$labelPos] === ' ')
- ++$labelPos;
- if (isset($labels[$labelPos], $this->refs[$labels[$labelPos]]))
- {
- $id = $labels[$labelPos];
- $endTagLen = $labelPos + 2 + \strlen($id) - $endTagPos;
- }
- if (isset($this->refs[$id]))
- $this->addLinkTag($startTagPos, $endTagPos, $endTagLen, $this->refs[$id]);
- }
- }
- protected function matchStrikethrough()
- {
- $pos = \strpos($this->text, '~~');
- if ($pos === \false)
- return;
- \preg_match_all(
- '/~~[^\\x17]+?~~/',
- $this->text,
- $matches,
- \PREG_OFFSET_CAPTURE,
- $pos
- );
- foreach ($matches[0] as $_4b034d25)
- {
- list($match, $matchPos) = $_4b034d25;
- $matchLen = \strlen($match);
- $this->parser->addTagPair('DEL', $matchPos, 2, $matchPos + $matchLen - 2, 2);
- }
- }
- protected function matchSuperscript()
- {
- $pos = \strpos($this->text, '^');
- if ($pos === \false)
- return;
- \preg_match_all(
- '/\\^[^\\x17\\s]++/',
- $this->text,
- $matches,
- \PREG_OFFSET_CAPTURE,
- $pos
- );
- foreach ($matches[0] as $_4b034d25)
- {
- list($match, $matchPos) = $_4b034d25;
- $matchLen = \strlen($match);
- $startTagPos = $matchPos;
- $endTagPos = $matchPos + $matchLen;
- $parts = \explode('^', $match);
- unset($parts[0]);
- foreach ($parts as $part)
- {
- $this->parser->addTagPair('SUP', $startTagPos, 1, $endTagPos, 0);
- $startTagPos += 1 + \strlen($part);
- }
- }
- }
- protected function overwrite($pos, $len)
- {
- $this->text = \substr($this->text, 0, $pos) . \str_repeat("\x1A", $len) . \substr($this->text, $pos + $len);
- }
- protected function processEmphasisBlock(array $block)
- {
- $buffered = 0;
- $emPos = -1;
- $strongPos = -1;
- foreach ($block as $_aab3a45e)
- {
- list($matchPos, $matchLen) = $_aab3a45e;
- $closeLen = \min(3, $matchLen);
- $closeEm = $closeLen & $buffered & 1;
- $closeStrong = $closeLen & $buffered & 2;
- $emEndPos = $matchPos;
- $strongEndPos = $matchPos;
- if ($buffered > 2 && $emPos === $strongPos)
- if ($closeEm)
- $emPos += 2;
- else
- ++$strongPos;
- if ($closeEm && $closeStrong)
- if ($emPos < $strongPos)
- $emEndPos += 2;
- else
- ++$strongEndPos;
- $remaining = $matchLen;
- if ($closeEm)
- {
- --$buffered;
- --$remaining;
- $this->parser->addTagPair('EM', $emPos, 1, $emEndPos, 1);
- }
- if ($closeStrong)
- {
- $buffered -= 2;
- $remaining -= 2;
- $this->parser->addTagPair('STRONG', $strongPos, 2, $strongEndPos, 2);
- }
- $remaining = \min(3, $remaining);
- if ($remaining & 1)
- $emPos = $matchPos + $matchLen - $remaining;
- if ($remaining & 2)
- $strongPos = $matchPos + $matchLen - $remaining;
- $buffered += $remaining;
- }
- }
- protected function setLinkAttributes(Tag $tag, $linkInfo, $attrName)
- {
- $url = \trim($linkInfo);
- $title = '';
- $pos = \strpos($url, ' ');
- if ($pos !== \false)
- {
- $title = \substr(\trim(\substr($url, $pos)), 1, -1);
- $url = \substr($url, 0, $pos);
- }
- $tag->setAttribute($attrName, $this->decode($url));
- if ($title > '')
- $tag->setAttribute('title', $this->decode($title));
- }
- }