diff options
Diffstat (limited to 'vendor/michelf/php-markdown/Michelf/Markdown.php')
-rw-r--r-- | vendor/michelf/php-markdown/Michelf/Markdown.php | 190 |
1 files changed, 102 insertions, 88 deletions
diff --git a/vendor/michelf/php-markdown/Michelf/Markdown.php b/vendor/michelf/php-markdown/Michelf/Markdown.php index c3eaf4464..e4c2c2361 100644 --- a/vendor/michelf/php-markdown/Michelf/Markdown.php +++ b/vendor/michelf/php-markdown/Michelf/Markdown.php @@ -4,7 +4,7 @@ * * @package php-markdown * @author Michel Fortin <michel.fortin@michelf.com> - * @copyright 2004-2016 Michel Fortin <https://michelf.com/projects/php-markdown/> + * @copyright 2004-2018 Michel Fortin <https://michelf.com/projects/php-markdown/> * @copyright (Original Markdown) 2004-2006 John Gruber <https://daringfireball.net/projects/markdown/> */ @@ -18,7 +18,7 @@ class Markdown implements MarkdownInterface { * Define the package version * @var string */ - const MARKDOWNLIB_VERSION = "1.7.0"; + const MARKDOWNLIB_VERSION = "1.8.0"; /** * Simple function interface - Initialize the parser and return the result @@ -61,14 +61,14 @@ class Markdown implements MarkdownInterface { * @var int */ public $tab_width = 4; - + /** * Change to `true` to disallow markup or entities. * @var boolean */ public $no_markup = false; public $no_entities = false; - + /** * Change to `true` to enable line breaks on \n without two trailling spaces @@ -94,7 +94,7 @@ class Markdown implements MarkdownInterface { * @var callable */ public $header_id_func = null; - + /** * Optional function for converting code block content to HTML * @var callable @@ -111,7 +111,7 @@ class Markdown implements MarkdownInterface { * Class attribute to toggle "enhanced ordered list" behaviour * setting this to true will allow ordered lists to start from the index * number that is defined first. - * + * * For example: * 2. List item two * 3. List item three @@ -155,17 +155,17 @@ class Markdown implements MarkdownInterface { public function __construct() { $this->_initDetab(); $this->prepareItalicsAndBold(); - - $this->nested_brackets_re = + + $this->nested_brackets_re = str_repeat('(?>[^\[\]]+|\[', $this->nested_brackets_depth). str_repeat('\])*', $this->nested_brackets_depth); - - $this->nested_url_parenthesis_re = + + $this->nested_url_parenthesis_re = str_repeat('(?>[^()\s]+|\(', $this->nested_url_parenthesis_depth). str_repeat('(?>\)))*', $this->nested_url_parenthesis_depth); - + $this->escape_chars_re = '['.preg_quote($this->escape_chars).']'; - + // Sort document, block, and span gamut in ascendent priority order. asort($this->document_gamut); asort($this->block_gamut); @@ -180,13 +180,19 @@ class Markdown implements MarkdownInterface { protected $urls = array(); protected $titles = array(); protected $html_hashes = array(); - + /** * Status flag to avoid invalid nesting. * @var boolean */ protected $in_anchor = false; - + + /** + * Status flag to avoid invalid nesting. + * @var boolean + */ + protected $in_emphasis_processing = false; + /** * Called before the transformation process starts to setup parser states. * @return void @@ -197,8 +203,9 @@ class Markdown implements MarkdownInterface { $this->titles = $this->predef_titles; $this->html_hashes = array(); $this->in_anchor = false; + $this->in_emphasis_processing = false; } - + /** * Called after the transformation process to clear any variable which may * be taking up memory unnecessarly. @@ -221,7 +228,7 @@ class Markdown implements MarkdownInterface { */ public function transform($text) { $this->setup(); - + # Remove UTF-8 BOM and marker character in input, if present. $text = preg_replace('{^\xEF\xBB\xBF|\x1A}', '', $text); @@ -248,7 +255,7 @@ class Markdown implements MarkdownInterface { foreach ($this->document_gamut as $method => $priority) { $text = $this->$method($text); } - + $this->teardown(); return $text . "\n"; @@ -271,7 +278,7 @@ class Markdown implements MarkdownInterface { * @return string */ protected function stripLinkDefinitions($text) { - + $less_than_tab = $this->tab_width - 1; // Link defs are in the form: ^[id]: url "optional title" @@ -338,8 +345,8 @@ class Markdown implements MarkdownInterface { * for is hard-coded: * * * List "a" is made of tags which can be both inline or block-level. - * These will be treated block-level when the start tag is alone on - * its line, otherwise they're not matched here and will be taken as + * These will be treated block-level when the start tag is alone on + * its line, otherwise they're not matched here and will be taken as * inline later. * * List "b" is made of tags which are always block-level; */ @@ -363,7 +370,7 @@ class Markdown implements MarkdownInterface { | \'[^\']*\' # text inside single quotes (tolerate ">") )* - )? + )? '; $content = str_repeat(' @@ -380,7 +387,7 @@ class Markdown implements MarkdownInterface { str_repeat(' </\2\s*> # closing nested tag ) - | + | <(?!/\2\s*> # other tags with a different name ) )*', @@ -409,9 +416,9 @@ class Markdown implements MarkdownInterface { ) ( # save in $1 - # Match from `\n<tag>` to `</tag>\n`, handling nested tags + # Match from `\n<tag>` to `</tag>\n`, handling nested tags # in between. - + [ ]{0,'.$less_than_tab.'} <('.$block_tags_b_re.')# start tag = $2 '.$attr.'> # attributes followed by > and \n @@ -429,28 +436,28 @@ class Markdown implements MarkdownInterface { </\3> # the matching end tag [ ]* # trailing spaces/tabs (?=\n+|\Z) # followed by a newline or end of document - - | # Special case just for <hr />. It was easier to make a special + + | # Special case just for <hr />. It was easier to make a special # case than to make the other regex more complicated. - + [ ]{0,'.$less_than_tab.'} <(hr) # start tag = $2 '.$attr.' # attributes /?> # the matching end tag [ ]* (?=\n{2,}|\Z) # followed by a blank line or end of document - + | # Special case for standalone HTML comments: - + [ ]{0,'.$less_than_tab.'} (?s: <!-- .*? --> ) [ ]* (?=\n{2,}|\Z) # followed by a blank line or end of document - + | # PHP and ASP-style processor instructions (<? and <%) - + [ ]{0,'.$less_than_tab.'} (?s: <([?%]) # $2 @@ -459,7 +466,7 @@ class Markdown implements MarkdownInterface { ) [ ]* (?=\n{2,}|\Z) # followed by a blank line or end of document - + ) )}Sxmi', array($this, '_hashHTMLBlocks_callback'), @@ -479,9 +486,9 @@ class Markdown implements MarkdownInterface { $key = $this->hashBlock($text); return "\n\n$key\n\n"; } - + /** - * Called whenever a tag must be hashed when a function insert an atomic + * Called whenever a tag must be hashed when a function insert an atomic * element in the text stream. Passing $text to through this function gives * a unique text-token which will be reverted back when calling unhash. * @@ -498,7 +505,7 @@ class Markdown implements MarkdownInterface { // Swap back any tag hash found in $text so we do not have to `unhash` // multiple times at the end. $text = $this->unhash($text); - + // Then hash the block. static $i = 0; $key = "$boundary\x1A" . ++$i . $boundary; @@ -531,10 +538,10 @@ class Markdown implements MarkdownInterface { /** * Run block gamut tranformations. * - * We need to escape raw HTML in Markdown source before doing anything - * else. This need to be done for each block, and not only at the + * We need to escape raw HTML in Markdown source before doing anything + * else. This need to be done for each block, and not only at the * begining in the Markdown function since hashed blocks can be part of - * list items and could have been indented. Indented blocks would have + * list items and could have been indented. Indented blocks would have * been seen as a code block in a previous pass of hashHTMLBlocks. * * @param string $text @@ -546,7 +553,7 @@ class Markdown implements MarkdownInterface { } /** - * Run block gamut tranformations, without hashing HTML blocks. This is + * Run block gamut tranformations, without hashing HTML blocks. This is * useful when HTML blocks are known to be already hashed, like in the first * whole-document pass. * @@ -554,11 +561,11 @@ class Markdown implements MarkdownInterface { * @return string */ protected function runBasicBlockGamut($text) { - + foreach ($this->block_gamut as $method => $priority) { $text = $this->$method($text); } - + // Finally form paragraph and restore hashed blocks. $text = $this->formParagraphs($text); @@ -582,7 +589,7 @@ class Markdown implements MarkdownInterface { [ ]* # Tailing spaces $ # End of line. }mx', - "\n".$this->hashBlock("<hr$this->empty_element_suffix")."\n", + "\n".$this->hashBlock("<hr$this->empty_element_suffix")."\n", $text ); } @@ -629,10 +636,10 @@ class Markdown implements MarkdownInterface { */ protected function doHardBreaks($text) { if ($this->hard_wrap) { - return preg_replace_callback('/ *\n/', + return preg_replace_callback('/ *\n/', array($this, '_doHardBreaks_callback'), $text); } else { - return preg_replace_callback('/ {2,}\n/', + return preg_replace_callback('/ {2,}\n/', array($this, '_doHardBreaks_callback'), $text); } } @@ -656,7 +663,7 @@ class Markdown implements MarkdownInterface { return $text; } $this->in_anchor = true; - + // First, handle reference-style links: [link text] [id] $text = preg_replace_callback('{ ( # wrap whole match in $1 @@ -729,7 +736,7 @@ class Markdown implements MarkdownInterface { // for shortcut links like [this][] or [this]. $link_id = $link_text; } - + // lower-case and turn embedded newlines into spaces $link_id = strtolower($link_id); $link_id = preg_replace('{[ ]?\n}', ' ', $link_id); @@ -737,14 +744,14 @@ class Markdown implements MarkdownInterface { if (isset($this->urls[$link_id])) { $url = $this->urls[$link_id]; $url = $this->encodeURLAttribute($url); - + $result = "<a href=\"$url\""; if ( isset( $this->titles[$link_id] ) ) { $title = $this->titles[$link_id]; $title = $this->encodeAttribute($title); $result .= " title=\"$title\""; } - + $link_text = $this->runSpanGamut($link_text); $result .= ">$link_text</a>"; $result = $this->hashPart($result); @@ -779,7 +786,7 @@ class Markdown implements MarkdownInterface { $title = $this->encodeAttribute($title); $result .= " title=\"$title\""; } - + $link_text = $this->runSpanGamut($link_text); $result .= ">$link_text</a>"; @@ -807,7 +814,7 @@ class Markdown implements MarkdownInterface { \] ) - }xs', + }xs', array($this, '_doImages_reference_callback'), $text); // Next, handle inline images: ![alt text](url "optional title") @@ -906,7 +913,7 @@ class Markdown implements MarkdownInterface { * Setext-style headers: * Header 1 * ======== - * + * * Header 2 * -------- */ @@ -944,7 +951,7 @@ class Markdown implements MarkdownInterface { if ($matches[2] == '-' && preg_match('{^-(?: |$)}', $matches[1])) { return $matches[0]; } - + $level = $matches[2]{0} == '=' ? 1 : 2; // ID attribute generation @@ -977,7 +984,7 @@ class Markdown implements MarkdownInterface { * @param string $headerValue * @return string */ - protected function _generateIdFromHeaderValue($headerValue) { + protected function _generateIdFromHeaderValue($headerValue) { if (!is_callable($this->header_id_func)) { return ""; } @@ -1035,10 +1042,10 @@ class Markdown implements MarkdownInterface { ) ) '; // mx - + // We use a different prefix before nested lists than top-level lists. //See extended comment in _ProcessListItems(). - + if ($this->list_level) { $text = preg_replace_callback('{ ^ @@ -1132,7 +1139,7 @@ class Markdown implements MarkdownInterface { * without resorting to mind-reading. Perhaps the solution is to * change the syntax rules such that sub-lists must start with a * starting cardinal number; e.g. "1." or "a.". - */ + */ $this->list_level++; // Trim trailing blank lines: @@ -1166,7 +1173,7 @@ class Markdown implements MarkdownInterface { $marker_space = $matches[3]; $tailing_blank_line =& $matches[5]; - if ($leading_line || $tailing_blank_line || + if ($leading_line || $tailing_blank_line || preg_match('/\n{2,}/', $item)) { // Replace marker with the appropriate whitespace indentation @@ -1273,7 +1280,7 @@ class Markdown implements MarkdownInterface { * @var array */ protected $em_strong_prepared_relist; - + /** * Prepare regular expressions for searching emphasis tokens in any * context. @@ -1289,7 +1296,7 @@ class Markdown implements MarkdownInterface { } $token_relist[] = $em_re; $token_relist[] = $strong_re; - + // Construct master expression from list. $token_re = '{(' . implode('|', $token_relist) . ')}'; $this->em_strong_prepared_relist["$em$strong"] = $token_re; @@ -1303,24 +1310,29 @@ class Markdown implements MarkdownInterface { * @return string */ protected function doItalicsAndBold($text) { + if ($this->in_emphasis_processing) { + return $text; // avoid reentrency + } + $this->in_emphasis_processing = true; + $token_stack = array(''); $text_stack = array(''); $em = ''; $strong = ''; $tree_char_em = false; - + while (1) { // Get prepared regular expression for seraching emphasis tokens // in current context. $token_re = $this->em_strong_prepared_relist["$em$strong"]; - - // Each loop iteration search for the next emphasis token. + + // Each loop iteration search for the next emphasis token. // Each token is then passed to handleSpanToken. $parts = preg_split($token_re, $text, 2, PREG_SPLIT_DELIM_CAPTURE); $text_stack[0] .= $parts[0]; $token =& $parts[1]; $text =& $parts[2]; - + if (empty($token)) { // Reached end of text span: empty stack without emitting. // any more emphasis. @@ -1330,7 +1342,7 @@ class Markdown implements MarkdownInterface { } break; } - + $token_len = strlen($token); if ($tree_char_em) { // Reached closing marker while inside a three-char emphasis. @@ -1369,7 +1381,7 @@ class Markdown implements MarkdownInterface { $$tag = ''; // $$tag stands for $em or $strong } } else { - // Reached opening three-char emphasis marker. Push on token + // Reached opening three-char emphasis marker. Push on token // stack; will be handled by the special condition above. $em = $token{0}; $strong = "$em$em"; @@ -1383,6 +1395,7 @@ class Markdown implements MarkdownInterface { if (strlen($token_stack[0]) == 1) { $text_stack[1] .= array_shift($token_stack); $text_stack[0] .= array_shift($text_stack); + $em = ''; } // Closing strong marker: array_shift($token_stack); @@ -1417,6 +1430,7 @@ class Markdown implements MarkdownInterface { } } } + $this->in_emphasis_processing = false; return $text_stack[0]; } @@ -1453,9 +1467,9 @@ class Markdown implements MarkdownInterface { $bq = $this->runBlockGamut($bq); // recurse $bq = preg_replace('/^/m', " ", $bq); - // These leading spaces cause problem with <pre> content, + // These leading spaces cause problem with <pre> content, // so we need to fix that: - $bq = preg_replace_callback('{(\s*<pre>.+?</pre>)}sx', + $bq = preg_replace_callback('{(\s*<pre>.+?</pre>)}sx', array($this, '_doBlockQuotes_callback2'), $bq); return "\n" . $this->hashBlock("<blockquote>\n$bq\n</blockquote>") . "\n\n"; @@ -1525,7 +1539,7 @@ class Markdown implements MarkdownInterface { // // We can't call Markdown(), because that resets the hash; // // that initialization code should be pulled into its own sub, though. // $div_content = $this->hashHTMLBlocks($div_content); -// +// // // Run document gamut methods on the content. // foreach ($this->document_gamut as $method => $priority) { // $div_content = $this->$method($div_content); @@ -1582,9 +1596,9 @@ class Markdown implements MarkdownInterface { return $url; } - + /** - * Smart processing for ampersands and angle brackets that need to + * Smart processing for ampersands and angle brackets that need to * be encoded. Valid character entities are left alone unless the * no-entities mode is set. * @param string $text @@ -1596,7 +1610,7 @@ class Markdown implements MarkdownInterface { } else { // Ampersand-encoding based entirely on Nat Irons's Amputator // MT plugin: <http://bumppo.net/projects/amputator/> - $text = preg_replace('/&(?!#?[xX]?(?:[0-9a-fA-F]+|\w+);)/', + $text = preg_replace('/&(?!#?[xX]?(?:[0-9a-fA-F]+|\w+);)/', '&', $text); } // Encode remaining <'s @@ -1724,7 +1738,7 @@ class Markdown implements MarkdownInterface { */ protected function parseSpan($str) { $output = ''; - + $span_re = '{ ( \\\\'.$this->escape_chars_re.' @@ -1752,16 +1766,16 @@ class Markdown implements MarkdownInterface { }xs'; while (1) { - // Each loop iteration seach for either the next tag, the next - // openning code span marker, or the next escaped character. + // Each loop iteration seach for either the next tag, the next + // openning code span marker, or the next escaped character. // Each token is then passed to handleSpanToken. $parts = preg_split($span_re, $str, 2, PREG_SPLIT_DELIM_CAPTURE); - + // Create token from text preceding tag. if ($parts[0] != "") { $output .= $parts[0]; } - + // Check if we reach the end. if (isset($parts[1])) { $output .= $this->handleSpanToken($parts[1], $parts[2]); @@ -1770,7 +1784,7 @@ class Markdown implements MarkdownInterface { break; } } - + return $output; } @@ -1787,7 +1801,7 @@ class Markdown implements MarkdownInterface { return $this->hashPart("&#". ord($token{1}). ";"); case "`": // Search for end marker in remaining text. - if (preg_match('/^(.*?[^`])'.preg_quote($token).'(?!`)(.*)$/sm', + if (preg_match('/^(.*?[^`])'.preg_quote($token).'(?!`)(.*)$/sm', $str, $matches)) { $str = $matches[2]; @@ -1823,11 +1837,11 @@ class Markdown implements MarkdownInterface { * For each line we separate the line in blocks delemited by tab characters. * Then we reconstruct every line by adding the appropriate number of space * between each blocks. - * + * * @param string $text * @return string */ - protected function detab($text) { + protected function detab($text) { $text = preg_replace_callback('/^.*\t.*$/m', array($this, '_detab_callback'), $text); @@ -1842,7 +1856,7 @@ class Markdown implements MarkdownInterface { protected function _detab_callback($matches) { $line = $matches[0]; $strlen = $this->utf8_strlen; // strlen function for UTF-8. - + // Split in blocks. $blocks = explode("\t", $line); // Add each blocks to the line. @@ -1850,7 +1864,7 @@ class Markdown implements MarkdownInterface { unset($blocks[0]); // Do not add first block twice. foreach ($blocks as $block) { // Calculate amount of space, insert spaces, insert block. - $amount = $this->tab_width - + $amount = $this->tab_width - $strlen($line, 'UTF-8') % $this->tab_width; $line .= str_repeat(" ", $amount) . $block; } @@ -1859,20 +1873,20 @@ class Markdown implements MarkdownInterface { /** * Check for the availability of the function in the `utf8_strlen` property - * (initially `mb_strlen`). If the function is not available, create a + * (initially `mb_strlen`). If the function is not available, create a * function that will loosely count the number of UTF-8 characters with a * regular expression. * @return void */ protected function _initDetab() { - + if (function_exists($this->utf8_strlen)) { return; } - $this->utf8_strlen = create_function('$text', 'return preg_match_all( - "/[\\\\x00-\\\\xBF]|[\\\\xC0-\\\\xFF][\\\\x80-\\\\xBF]*/", - $text, $m);'); + $this->utf8_strlen = function($text) { + return preg_match_all('/[\x00-\xBF]|[\xC0-\xFF][\x80-\xBF]*/', $text, $m); + }; } /** @@ -1881,7 +1895,7 @@ class Markdown implements MarkdownInterface { * @return string */ protected function unhash($text) { - return preg_replace_callback('/(.)\x1A[0-9]+\1/', + return preg_replace_callback('/(.)\x1A[0-9]+\1/', array($this, '_unhash_callback'), $text); } |