1
0
mirror of https://github.com/erusev/parsedown.git synced 2023-08-10 21:13:06 +03:00

Compare commits

...

40 Commits
0.8.3 ... 0.9.1

Author SHA1 Message Date
f5f1706e58 improve consistency of list item 2014-02-02 22:27:22 +02:00
b257d0ecaa add contributing guidelines 2014-02-02 22:14:53 +02:00
a7510b97e7 dense list items that follow sparse ones should not be rendered as sparse ones 2014-01-31 03:03:52 +02:00
e9098aebfa improve parsing of list item and code block by measuring line indentation 2014-01-31 02:19:18 +02:00
72f4a375ef Merge pull request #69 from KaneCohen/master 2014-01-29 15:16:00 -08:00
07b738b1c8 Remove one unnecessary /u flag. 2014-01-29 23:05:05 +00:00
f7181ee9b6 Remove /u flag from '*' chars. Add /u to urls. 2014-01-29 22:57:29 +00:00
0ce6caf81e Merge pull request #72 from cebe/code-edge
some edge case tests for the code tag
2014-01-29 14:31:39 -08:00
d3c975d4d8 some edge case tests for the code tag 2014-01-29 15:36:41 +01:00
55f360a591 Add unicode support for strong/em regex. 2014-01-29 10:30:21 +00:00
215ff63594 improve comments 2014-01-29 02:14:59 +02:00
3d581dcaa9 simplify names of block types 2014-01-27 22:21:58 +02:00
bbce965a9a read-only fields should be static 2014-01-27 00:58:18 +02:00
6069fdac81 refactor parsing of html 2014-01-27 00:10:24 +02:00
0f090e1a6e remove trailing line break 2014-01-27 00:08:55 +02:00
618ab4e156 improve layout of class members 2014-01-26 19:53:24 +02:00
7661b7c8f9 simplify comments 2014-01-26 19:14:44 +02:00
8f6495ce86 ternaries should not do more than assign a value 2014-01-26 19:13:08 +02:00
250ba80356 expression assignments should be separate 2014-01-26 19:05:24 +02:00
3ac9b96e57 element » block 2014-01-26 13:47:56 +02:00
b764deca66 improve comments 2014-01-26 03:36:25 +02:00
65ef541fda improve comments 2014-01-25 18:47:44 +02:00
c7b6d0235d unset brackets should not be separated 2014-01-25 14:53:39 +02:00
1a2124daae Merge pull request #65 from hkdobrev/comments-imperative
Use imperative tense in comments
2014-01-25 04:53:19 -08:00
bf6c9a6db2 Use imperative tense in comments 2014-01-24 01:47:44 +02:00
0494c6b274 improve comments 2014-01-24 01:28:03 +02:00
3e0c010c1f improve comments 2014-01-23 23:48:38 +02:00
3a5eecc23d replace logical operators with conditionals to improve readability 2014-01-23 22:46:49 +02:00
c8c5ae9df8 control structures should use braces 2014-01-23 22:34:02 +02:00
843786c07c improve comments 2014-01-23 22:08:06 +02:00
0c61f71e3f rtrim » chop 2014-01-23 13:07:15 +02:00
01a147c574 replace tabs with spaces to improve compatibility with psr-2 2014-01-23 00:57:36 +02:00
f0fbdaa6ca backtick within code span 2014-01-22 21:28:29 +02:00
e20c0a29bd nested elements should render on a new line 2014-01-22 21:28:29 +02:00
712dd23d30 simplify parsing of list 2014-01-22 21:28:29 +02:00
68f2871996 resolve #3 2014-01-22 21:28:29 +02:00
17e7e33847 name image title test 2014-01-22 21:28:29 +02:00
7cb9646d98 simplify compiling of links 2014-01-22 21:28:29 +02:00
325bdd9ff6 improve readme 2014-01-21 23:15:02 +02:00
2a0700abda resolve #61 2014-01-20 22:19:23 +02:00
13 changed files with 901 additions and 766 deletions

15
CONTRIBUTING.md Normal file
View File

@ -0,0 +1,15 @@
Do create pull requests that:
* resolve an issue
* optimise an existing feature or text
Do NOT create pull requests that:
* introduce a feature or text
* change the currently used coding style
Pull requests should do only ONE thing. If a pull request contains unrelated updates, they should be submitted as separate pull requests.
By contributing to the project, you grant to the creator of the project a perpetual, worldwide, no-charge, irrevocable license to use, reproduce and distribute your contributions and derivative works.
You also warrant that you are the sole owner of your contributions and that they are your original works of authorship.

View File

@ -8,21 +8,21 @@
# (c) Emanuil Rusev
# http://erusev.com
#
# For the full license information, please view the LICENSE file that was
# distributed with this source code.
# For the full license information, view the LICENSE file that was distributed
# with this source code.
#
#
class Parsedown
{
#
# Multiton (http://en.wikipedia.org/wiki/Multiton_pattern)
#
# Multiton
static function instance($name = 'default')
{
if (isset(self::$instances[$name]))
{
return self::$instances[$name];
}
$instance = new Parsedown();
@ -37,7 +37,7 @@ class Parsedown
# Setters
#
private $breaks_enabled = false;
# Enables GFM line breaks.
function set_breaks_enabled($breaks_enabled)
{
@ -46,69 +46,79 @@ class Parsedown
return $this;
}
#
# Fields
#
private $reference_map = array();
private $breaks_enabled = false;
#
# Public Methods
# Synopsis
#
# Markdown is intended to be easy-to-read by humans - those of us who read
# line by line, left to right, top to bottom. In order to take advantage of
# this, Parsedown tries to read in a similar way. It breaks texts into
# lines, it iterates through them and it looks at how they start and relate
# to each other.
#
# Methods
#
function parse($text)
{
# removes \r characters
# standardize line breaks
$text = str_replace("\r\n", "\n", $text);
$text = str_replace("\r", "\n", $text);
# replaces tabs with spaces
# replace tabs with spaces
$text = str_replace("\t", ' ', $text);
# ~
# remove surrounding line breaks
$text = trim($text, "\n");
# split text into lines
$lines = explode("\n", $text);
# convert lines into html
$text = $this->parse_block_elements($lines);
$text = rtrim($text, "\n");
# remove trailing line breaks
$text = chop($text, "\n");
return $text;
}
#
# Private Methods
#
# Private
private function parse_block_elements(array $lines, $context = '')
{
$elements = array();
$blocks = array();
$element = array(
$block = array(
'type' => '',
);
foreach ($lines as $line)
{
# fenced elements
# context
switch ($element['type'])
switch ($block['type'])
{
case 'fenced block':
case 'fenced':
if ( ! isset($element['closed']))
if ( ! isset($block['closed']))
{
if (preg_match('/^[ ]*'.$element['fence'][0].'{3,}[ ]*$/', $line))
if (preg_match('/^[ ]*'.$block['fence'][0].'{3,}[ ]*$/', $line))
{
$element['closed'] = true;
$block['closed'] = true;
}
else
{
$element['text'] !== '' and $element['text'] .= "\n";
if ($block['text'] !== '')
{
$block['text'] .= "\n";
}
$element['text'] .= $line;
$block['text'] .= $line;
}
continue 2;
@ -116,23 +126,28 @@ class Parsedown
break;
case 'block-level markup':
case 'markup':
if ( ! isset($element['closed']))
if ( ! isset($block['closed']))
{
if (strpos($line, $element['start']) !== false) # opening tag
if (strpos($line, $block['start']) !== false) # opening tag
{
$element['depth']++;
$block['depth']++;
}
if (strpos($line, $element['end']) !== false) # closing tag
if (strpos($line, $block['end']) !== false) # closing tag
{
$element['depth'] > 0
? $element['depth']--
: $element['closed'] = true;
if ($block['depth'] > 0)
{
$block['depth']--;
}
else
{
$block['closed'] = true;
}
}
$element['text'] .= "\n".$line;
$block['text'] .= "\n".$line;
continue 2;
}
@ -140,28 +155,37 @@ class Parsedown
break;
}
# *
# ~
$deindented_line = ltrim($line);
$indentation = 0;
while(isset($line[$indentation]) and $line[$indentation] === ' ')
{
$indentation++;
}
$deindented_line = $indentation > 0 ? ltrim($line) : $line;
# blank
if ($deindented_line === '')
{
$element['interrupted'] = true;
$block['interrupted'] = true;
continue;
}
# composite elements
# context
switch ($element['type'])
switch ($block['type'])
{
case 'blockquote':
case 'quote':
if ( ! isset($element['interrupted']))
if ( ! isset($block['interrupted']))
{
$line = preg_replace('/^[ ]*>[ ]?/', '', $line);
$element['lines'] []= $line;
$block['lines'] []= $line;
continue 2;
}
@ -170,51 +194,38 @@ class Parsedown
case 'li':
if (preg_match('/^([ ]{0,3})(\d+[.]|[*+-])[ ](.*)/', $line, $matches))
if ($block['indentation'] === $indentation and preg_match('/^'.$block['marker'].'[ ]+(.*)/', $deindented_line, $matches))
{
if ($element['indentation'] !== $matches[1])
{
$element['lines'] []= $line;
}
else
{
unset($element['last']);
unset($block['last']);
$elements []= $element;
$blocks []= $block;
$element = array(
'type' => 'li',
'indentation' => $matches[1],
'last' => true,
'lines' => array(
preg_replace('/^[ ]{0,4}/', '', $matches[3]),
),
);
}
$block['last'] = true;
$block['lines'] = array($matches[1]);
unset($block['first']);
unset($block['interrupted']);
continue 2;
}
if (isset($element['interrupted']))
if ( ! isset($block['interrupted']))
{
if ($line[0] === ' ')
{
$element['lines'] []= '';
$line = preg_replace('/^[ ]{0,'.$block['baseline'].'}/', '', $line);
$line = preg_replace('/^[ ]{0,4}/', '', $line);
$element['lines'] []= $line;
unset($element['interrupted']);
$block['lines'] []= $line;
continue 2;
}
}
else
elseif ($line[0] === ' ')
{
$line = preg_replace('/^[ ]{0,4}/', '', $line);
$block['lines'] []= '';
$element['lines'] []= $line;
$line = preg_replace('/^[ ]{0,'.$block['baseline'].'}/', '', $line);
$block['lines'] []= $line;
unset($block['interrupted']);
continue 2;
}
@ -228,29 +239,29 @@ class Parsedown
{
case ' ':
# code block
# code
if (isset($line[3]) and $line[3] === ' ' and $line[2] === ' ' and $line[1] === ' ')
if ($indentation >= 4)
{
$code_line = substr($line, 4);
if ($element['type'] === 'code block')
if ($block['type'] === 'code')
{
if (isset($element['interrupted']))
if (isset($block['interrupted']))
{
$element['text'] .= "\n";
$block['text'] .= "\n";
unset ($element['interrupted']);
unset($block['interrupted']);
}
$element['text'] .= "\n".$code_line;
$block['text'] .= "\n".$code_line;
}
else
{
$elements []= $element;
$blocks []= $block;
$element = array(
'type' => 'code block',
$block = array(
'type' => 'code',
'text' => $code_line,
);
}
@ -266,7 +277,7 @@ class Parsedown
if (isset($line[1]))
{
$elements []= $element;
$blocks []= $block;
$level = 1;
@ -275,7 +286,7 @@ class Parsedown
$level++;
}
$element = array(
$block = array(
'type' => 'heading',
'text' => trim($line, '# '),
'level' => $level,
@ -289,11 +300,11 @@ class Parsedown
case '-':
case '=':
# setext heading
# setext heading (===)
if ($element['type'] === 'paragraph' and isset($element['interrupted']) === false)
if ($block['type'] === 'paragraph' and isset($block['interrupted']) === false)
{
$chopped_line = rtrim($line);
$chopped_line = chop($line);
$i = 1;
@ -307,8 +318,9 @@ class Parsedown
$i++;
}
$element['type'] = 'heading';
$element['level'] = $line[0] === '-' ? 2 : 1;
$block['type'] = 'heading';
$block['level'] = $line[0] === '-' ? 2 : 1;
continue 2;
}
@ -324,23 +336,28 @@ class Parsedown
$position = strpos($deindented_line, '>');
if ($position > 1) # tag
if ($position > 1)
{
$name = substr($deindented_line, 1, $position - 1);
$name = rtrim($name);
$substring = substr($deindented_line, 1, $position - 1);
if (substr($name, -1) === '/')
$substring = chop($substring);
if (substr($substring, -1) === '/')
{
$self_closing = true;
$is_self_closing = true;
$name = substr($name, 0, -1);
$substring = substr($substring, 0, -1);
}
$position = strpos($name, ' ');
$position = strpos($substring, ' ');
if ($position)
{
$name = substr($name, 0, $position);
$name = substr($substring, 0, $position);
}
else
{
$name = $substring;
}
if ( ! ctype_alpha($name))
@ -348,36 +365,36 @@ class Parsedown
break;
}
if (in_array($name, $this->inline_tags))
if (in_array($name, self::$text_level_elements))
{
break;
}
$elements []= $element;
$blocks []= $block;
if (isset($self_closing))
if (isset($is_self_closing))
{
$element = array(
$block = array(
'type' => 'self-closing tag',
'text' => $deindented_line,
);
unset($self_closing);
unset($is_self_closing);
continue 2;
}
$element = array(
'type' => 'block-level markup',
$block = array(
'type' => 'markup',
'text' => $deindented_line,
'start' => '<'.$name.'>',
'end' => '</'.$name.'>',
'depth' => 0,
);
if (strpos($deindented_line, $element['end']))
if (strpos($deindented_line, $block['end']))
{
$element['closed'] = true;
$block['closed'] = true;
}
continue 2;
@ -391,10 +408,10 @@ class Parsedown
if (preg_match('/^>[ ]?(.*)/', $deindented_line, $matches))
{
$elements []= $element;
$blocks []= $block;
$element = array(
'type' => 'blockquote',
$block = array(
'type' => 'quote',
'lines' => array(
$matches[1],
),
@ -434,15 +451,18 @@ class Parsedown
if (preg_match('/^([`]{3,}|[~]{3,})[ ]*(\S+)?[ ]*$/', $deindented_line, $matches))
{
$elements []= $element;
$blocks []= $block;
$element = array(
'type' => 'fenced block',
$block = array(
'type' => 'fenced',
'text' => '',
'fence' => $matches[1],
);
isset($matches[2]) and $element['language'] = $matches[2];
if (isset($matches[2]))
{
$block['language'] = $matches[2];
}
continue 2;
}
@ -458,10 +478,10 @@ class Parsedown
if (preg_match('/^([-*_])([ ]{0,2}\1){2,}[ ]*$/', $deindented_line))
{
$elements []= $element;
$blocks []= $block;
$element = array(
'type' => 'hr',
$block = array(
'type' => 'rule',
);
continue 2;
@ -469,100 +489,115 @@ class Parsedown
# li
if (preg_match('/^([ ]*)[*+-][ ](.*)/', $line, $matches))
if (preg_match('/^([*+-][ ]+)(.*)/', $deindented_line, $matches))
{
$elements []= $element;
$blocks []= $block;
$element = array(
$baseline = $indentation + strlen($matches[1]);
$block = array(
'type' => 'li',
'ordered' => false,
'indentation' => $matches[1],
'indentation' => $indentation,
'baseline' => $baseline,
'marker' => '[*+-]',
'first' => true,
'last' => true,
'lines' => array(
preg_replace('/^[ ]{0,4}/', '', $matches[2]),
),
'lines' => array(),
);
$block['lines'] []= preg_replace('/^[ ]{0,4}/', '', $matches[2]);
continue 2;
}
}
# li
if ($deindented_line[0] <= '9' and $deindented_line[0] >= '0' and preg_match('/^([ ]*)\d+[.][ ](.*)/', $line, $matches))
if ($deindented_line[0] <= '9' and preg_match('/^(\d+[.][ ]+)(.*)/', $deindented_line, $matches))
{
$elements []= $element;
$blocks []= $block;
$element = array(
$baseline = $indentation + strlen($matches[1]);
$block = array(
'type' => 'li',
'indentation' => $indentation,
'baseline' => $baseline,
'marker' => '\d+[.]',
'first' => true,
'last' => true,
'ordered' => true,
'indentation' => $matches[1],
'last' => true,
'lines' => array(
preg_replace('/^[ ]{0,4}/', '', $matches[2]),
),
'lines' => array(),
);
$block['lines'] []= preg_replace('/^[ ]{0,4}/', '', $matches[2]);
continue;
}
# paragraph
if ($element['type'] === 'paragraph')
if ($block['type'] === 'paragraph')
{
if (isset($element['interrupted']))
if (isset($block['interrupted']))
{
$elements []= $element;
$blocks []= $block;
$element['text'] = $line;
$block['text'] = $line;
unset($element['interrupted']);
unset($block['interrupted']);
}
else
{
$this->breaks_enabled and $element['text'] .= ' ';
if ($this->breaks_enabled)
{
$block['text'] .= ' ';
}
$element['text'] .= "\n".$line;
$block['text'] .= "\n".$line;
}
}
else
{
$elements []= $element;
$blocks []= $block;
$element = array(
$block = array(
'type' => 'paragraph',
'text' => $line,
);
}
}
$elements []= $element;
$blocks []= $block;
unset($elements[0]);
unset($blocks[0]);
#
# ~
#
# $blocks » HTML
$markup = '';
foreach ($elements as $element)
foreach ($blocks as $block)
{
switch ($element['type'])
switch ($block['type'])
{
case 'paragraph':
$text = $this->parse_span_elements($element['text']);
$text = $this->parse_span_elements($block['text']);
if ($context === 'li' and $markup === '')
{
if (isset($element['interrupted']))
if (isset($block['interrupted']))
{
$markup .= "\n".'<p>'.$text.'</p>'."\n";
}
else
{
$markup .= $text;
if (isset($blocks[2]))
{
$markup .= "\n";
}
}
}
else
@ -572,29 +607,32 @@ class Parsedown
break;
case 'blockquote':
case 'quote':
$text = $this->parse_block_elements($element['lines']);
$text = $this->parse_block_elements($block['lines']);
$markup .= '<blockquote>'."\n".$text.'</blockquote>'."\n";
break;
case 'code block':
case 'code':
$text = htmlspecialchars($element['text'], ENT_NOQUOTES, 'UTF-8');
$text = htmlspecialchars($block['text'], ENT_NOQUOTES, 'UTF-8');
$markup .= '<pre><code>'.$text.'</code></pre>'."\n";
break;
case 'fenced block':
case 'fenced':
$text = htmlspecialchars($element['text'], ENT_NOQUOTES, 'UTF-8');
$text = htmlspecialchars($block['text'], ENT_NOQUOTES, 'UTF-8');
$markup .= '<pre><code';
isset($element['language']) and $markup .= ' class="language-'.$element['language'].'"';
if (isset($block['language']))
{
$markup .= ' class="language-'.$block['language'].'"';
}
$markup .= '>'.$text.'</code></pre>'."\n";
@ -602,13 +640,13 @@ class Parsedown
case 'heading':
$text = $this->parse_span_elements($element['text']);
$text = $this->parse_span_elements($block['text']);
$markup .= '<h'.$element['level'].'>'.$text.'</h'.$element['level'].'>'."\n";
$markup .= '<h'.$block['level'].'>'.$text.'</h'.$block['level'].'>'."\n";
break;
case 'hr':
case 'rule':
$markup .= '<hr />'."\n";
@ -616,35 +654,40 @@ class Parsedown
case 'li':
if (isset($element['ordered'])) # first
if (isset($block['first']))
{
$list_type = $element['ordered'] ? 'ol' : 'ul';
$type = isset($block['ordered']) ? 'ol' : 'ul';
$markup .= '<'.$list_type.'>'."\n";
$markup .= '<'.$type.'>'."\n";
}
if (isset($element['interrupted']) and ! isset($element['last']))
if (isset($block['interrupted']) and ! isset($block['last']))
{
$element['lines'] []= '';
$block['lines'] []= '';
}
$text = $this->parse_block_elements($element['lines'], 'li');
$text = $this->parse_block_elements($block['lines'], 'li');
$markup .= '<li>'.$text.'</li>'."\n";
isset($element['last']) and $markup .= '</'.$list_type.'>'."\n";
if (isset($block['last']))
{
$type = isset($block['ordered']) ? 'ol' : 'ul';
$markup .= '</'.$type.'>'."\n";
}
break;
case 'block-level markup':
case 'markup':
$markup .= $element['text']."\n";
$markup .= $block['text']."\n";
break;
default:
$markup .= $element['text']."\n";
$markup .= $block['text']."\n";
}
}
@ -730,7 +773,10 @@ class Parsedown
$offset = strlen($matches[0]);
$element['!'] and $offset++;
if ($element['!'])
{
$offset++;
}
$remaining_text = substr($text, $offset);
@ -785,15 +831,27 @@ class Parsedown
if ($element['!'])
{
$markup .= '<img alt="'.$element['a'].'" src="'.$element['»'].'" />';
$markup .= '<img alt="'.$element['a'].'" src="'.$element['»'].'"';
if (isset($element['#']))
{
$markup .= ' title="'.$element['#'].'"';
}
$markup .= ' />';
}
else
{
$element['a'] = $this->parse_span_elements($element['a'], $markers);
$markup .= isset($element['#'])
? '<a href="'.$element['»'].'" title="'.$element['#'].'">'.$element['a'].'</a>'
: '<a href="'.$element['»'].'">'.$element['a'].'</a>';
$markup .= '<a href="'.$element['»'].'"';
if (isset($element['#']))
{
$markup .= ' title="'.$element['#'].'"';
}
$markup .= '>'.$element['a'].'</a>';
}
unset($element);
@ -827,19 +885,19 @@ class Parsedown
case '*':
case '_':
if ($text[1] === $closest_marker and preg_match($this->strong_regex[$closest_marker], $text, $matches))
if ($text[1] === $closest_marker and preg_match(self::$strong_regex[$closest_marker], $text, $matches))
{
$matches[1] = $this->parse_span_elements($matches[1], $markers);
$markup .= '<strong>'.$matches[1].'</strong>';
}
elseif (preg_match($this->em_regex[$closest_marker], $text, $matches))
elseif (preg_match(self::$em_regex[$closest_marker], $text, $matches))
{
$matches[1] = $this->parse_span_elements($matches[1], $markers);
$markup .= '<em>'.$matches[1].'</em>';
}
elseif ($text[1] === $closest_marker and preg_match($this->strong_em_regex[$closest_marker], $text, $matches))
elseif ($text[1] === $closest_marker and preg_match(self::$strong_em_regex[$closest_marker], $text, $matches))
{
$matches[2] = $this->parse_span_elements($matches[2], $markers);
@ -848,7 +906,7 @@ class Parsedown
$markup .= '<strong>'.$matches[1].'<em>'.$matches[2].'</em>'.$matches[3].'</strong>';
}
elseif (preg_match($this->em_strong_regex[$closest_marker], $text, $matches))
elseif (preg_match(self::$em_strong_regex[$closest_marker], $text, $matches))
{
$matches[2] = $this->parse_span_elements($matches[2], $markers);
@ -885,6 +943,12 @@ class Parsedown
$offset = strlen($matches[0]);
}
elseif (strpos($text, '@') > 1 and preg_match('/<(\S+?@\S+?)>/', $text, $matches))
{
$markup .= '<a href="mailto:'.$matches[1].'">'.$matches[1].'</a>';
$offset = strlen($matches[0]);
}
elseif (preg_match('/^<\/?\w.*?>/', $text, $matches))
{
$markup .= $matches[0];
@ -909,7 +973,7 @@ class Parsedown
case '\\':
if (in_array($text[1], $this->special_characters))
if (in_array($text[1], self::$special_characters))
{
$markup .= $text[1];
@ -926,9 +990,9 @@ class Parsedown
case '`':
if (preg_match('/^`(.+?)`/', $text, $matches))
if (preg_match('/^(`+)(.+?)\1(?!`)/', $text, $matches))
{
$element_text = $matches[1];
$element_text = $matches[2];
$element_text = htmlspecialchars($element_text, ENT_NOQUOTES, 'UTF-8');
$markup .= '<code>'.$element_text.'</code>';
@ -946,7 +1010,7 @@ class Parsedown
case 'http':
if (preg_match('/^https?:[\/]{2}[^\s]+\b/i', $text, $matches))
if (preg_match('/^https?:[\/]{2}[^\s]+\b/ui', $text, $matches))
{
$element_url = $matches[0];
$element_url = str_replace('&', '&amp;', $element_url);
@ -997,37 +1061,47 @@ class Parsedown
}
#
# Read-only
# Fields
#
private $inline_tags = array(
'a', 'abbr', 'acronym', 'b', 'bdo', 'big', 'br', 'button',
'cite', 'code', 'dfn', 'em', 'i', 'img', 'input', 'kbd',
'label', 'map', 'object', 'q', 'samp', 'script', 'select', 'small',
'span', 'strong', 'sub', 'sup', 'textarea', 'tt', 'var',
);
private $reference_map = array();
private $special_characters = array('\\', '`', '*', '_', '{', '}', '[', ']', '(', ')', '>', '#', '+', '-', '.', '!');
#
# Read-only
# ~
private $strong_regex = array(
private static $strong_regex = array(
'*' => '/^[*]{2}([^*]+?)[*]{2}(?![*])/s',
'_' => '/^__([^_]+?)__(?!_)/s',
'_' => '/^__([^_]+?)__(?!_)/us',
);
private $em_regex = array(
private static $em_regex = array(
'*' => '/^[*]([^*]+?)[*](?![*])/s',
'_' => '/^_([^_]+?)[_](?![_])\b/s',
'_' => '/^_([^_]+?)[_](?![_])\b/us',
);
private $strong_em_regex = array(
private static $strong_em_regex = array(
'*' => '/^[*]{2}(.*?)[*](.+?)[*](.*?)[*]{2}/s',
'_' => '/^__(.*?)_(.+?)_(.*?)__/s',
'_' => '/^__(.*?)_(.+?)_(.*?)__/us',
);
private $em_strong_regex = array(
private static $em_strong_regex = array(
'*' => '/^[*](.*?)[*]{2}(.+?)[*]{2}(.*?)[*]/s',
'_' => '/^_(.*?)__(.+?)__(.*?)_/s',
'_' => '/^_(.*?)__(.+?)__(.*?)_/us',
);
private static $special_characters = array(
'\\', '`', '*', '_', '{', '}', '[', ']', '(', ')', '>', '#', '+', '-', '.', '!',
);
private static $text_level_elements = array(
'a', 'br', 'bdo', 'abbr', 'blink', 'nextid', 'acronym', 'basefont',
'b', 'em', 'big', 'cite', 'small', 'spacer', 'listing',
'i', 'rp', 'sub', 'code', 'strike', 'marquee',
'q', 'rt', 'sup', 'font', 'strong',
's', 'tt', 'var', 'mark',
'u', 'xm', 'wbr', 'nobr',
'ruby',
'span',
'time',
);
}

View File

@ -13,8 +13,8 @@ Better [Markdown](http://en.wikipedia.org/wiki/Markdown) parser for PHP.
* [fast](http://parsedown.org/speed)
* [consistent](http://parsedown.org/consistency)
* [GitHub Flavored](https://help.github.com/articles/github-flavored-markdown)
* friendly to international input
* [tested](https://travis-ci.org/erusev/parsedown) in PHP 5.2, 5.3, 5.4, 5.5 and [hhvm](http://www.hhvm.com/)
* friendly to international input
### Installation
@ -23,7 +23,7 @@ Include `Parsedown.php` or install [the composer package](https://packagist.org/
### Example
```php
$text = 'Hello _Parsedown_!';
$text = 'Hello *Parsedown*!';
$result = Parsedown::instance()->parse($text);

View File

@ -1 +1,3 @@
<p>a <code>code span</code></p>
<p><code>this is also a codespan</code> trailing text</p>
<p><code>and look at this one!</code></p>

View File

@ -1 +1,5 @@
a `code span`
`this is also a codespan` trailing text
`and look at this one!`

View File

@ -0,0 +1,18 @@
<ul>
<li>li
<ul>
<li>li
<ul>
<li>li
<ul>
<li>li</li>
</ul>
</li>
<li>li</li>
</ul>
</li>
<li>li</li>
</ul>
</li>
<li>li</li>
</ul>

View File

@ -0,0 +1,7 @@
- li
- li
- li
- li
- li
- li
- li

1
tests/data/email.html Normal file
View File

@ -0,0 +1 @@
<p>my email is <a href="mailto:me@example.com">me@example.com</a></p>

1
tests/data/email.md Normal file
View File

@ -0,0 +1 @@
my email is <me@example.com>

View File

@ -0,0 +1 @@
<p><img alt="alt" src="/md.png" title="title" /></p>

View File

@ -0,0 +1 @@
![alt](/md.png "title")

View File

@ -0,0 +1,7 @@
<ul>
<li>
<p>li</p>
</li>
<li>li</li>
<li>li</li>
</ul>

View File

@ -0,0 +1,4 @@
- li
- li
- li