/** * @param Text $text */ public function escapeAmpsAndBrackets(Text $text) { if ($text->contains('&')) { $text->replace('/&(?!#?[xX]?(?:[0-9a-fA-F]+|\\w+);)/', '&'); } if ($text->contains('<')) { $text->replace('{<(?![a-z/?\\$!])}i', '<'); } }
/** * @param Text $text */ public function processItalic(Text $text) { if (!$text->contains('*') && !$text->contains('_')) { return; } /** @noinspection PhpUnusedParameterInspection */ $text->replace('{ ([^\\*_\\s]?) (\\*|_) (?=\\S) (.+?) (?<=\\S) \\2 ([^\\*_\\s]?) }sx', function (Text $w, Text $prevChar, Text $a, Text $target, Text $nextChar) { if (!$prevChar->isEmpty() && !$nextChar->isEmpty() && $target->contains(' ')) { $this->getEmitter()->emit('escape.special_chars', [$w->replaceString(['*', '_'], ['\\*', '\\_'])]); return $w; } return $prevChar . $this->getRenderer()->renderItalicText($target) . $nextChar; }); }
/** * @param Text $text */ public function processCodeSpan(Text $text) { if (!$text->contains('`')) { return; } $chars = ['\\\\', '`', '\\*', '_', '{', '}', '\\[', '\\]', '\\(', '\\)', '>', '#', '\\+', '\\-', '\\.', '!']; $chars = implode('|', $chars); /** @noinspection PhpUnusedParameterInspection */ $text->replace('{ (`+) # $1 = Opening run of ` (.+?) # $2 = The code block (?<!`) \\1 # Matching closer (?!`) }x', function (Text $w, Text $b, Text $code) use($chars) { $code->trim()->escapeHtml(ENT_NOQUOTES); $code->replace(sprintf('/(?<!\\\\)(%s)/', $chars), '\\\\${1}'); return $this->getRenderer()->renderCodeSpan($code); }); }
/** * Make links out of things like `<http://example.com/>` * * @param Text $text */ public function processAutoLink(Text $text) { if (!$text->contains('<')) { return; } $text->replace('{<((?:https?|ftp):[^\'">\\s]+)>}', function (Text $w, Text $url) { $this->markdown->emit('escape.special_chars', [$url->replace('/(?<!\\\\)_/', '\\\\_')]); return $this->getRenderer()->renderLink($url, ['href' => $url->getString()]); }); /** @noinspection PhpUnusedParameterInspection */ $text->replace('{ < (?:mailto:)? ( [-.\\w]+ \\@ [-a-z0-9]+(\\.[-a-z0-9]+)*\\.[a-z]+ ) > }ix', function (Text $w, Text $address) { $address = "mailto:" . $address; $encode = array(function ($char) { return '&#' . ord($char) . ';'; }, function ($char) { return '&#x' . dechex(ord($char)) . ';'; }, function ($char) { return $char; }); $chars = new Collection(str_split($address)); $chars->apply(function ($char) use($encode) { if ($char == '@') { return $encode[rand(0, 1)]($char); } elseif ($char != ':') { $rand = rand(0, 100); $key = $rand > 90 ? 2 : ($rand < 45 ? 0 : 1); return $encode[$key]($char); } return $char; }); $address = $chars->join(); $text = $chars->slice(7)->join(); return $this->getRenderer()->renderLink($text, ['href' => $address]); }); }
/** * handle inline images: ![alt text](url "optional title") * * @param Text $text * @param array $options */ public function processInlineImage(Text $text, array $options = array()) { if (!$text->contains('![')) { return; } /** @xnoinspection PhpUnusedParameterInspection */ $text->replace('{ ( # wrap whole match in $1 !\\[ (.*?) # alt text = $2 \\] \\( # literal paren [ \\t]* <?(\\S+?)>? # src url = $3 [ \\t]* ( # $4 ([\'"]) # quote char = $5 (.*?) # title = $6 \\5 # matching quote [ \\t]* )? # title is optional \\) ) }xs', function (Text $w, Text $whole, Text $alt, Text $url, Text $a = null, Text $q = null, Text $title = null) use($options) { $attr = array('alt' => $alt->replace('/"/', '"')); $this->markdown->emit('escape.special_chars', [$url->replace('/(?<!\\\\)_/', '\\\\_')]); $url->escapeHtml(); if ($title) { $attr['title'] = $title->replace('/"/', '"')->escapeHtml(); } return $this->getRenderer()->renderImage($url, array('attr' => $attr)); }); }