mirror of
https://github.com/erusev/parsedown.git
synced 2023-08-10 21:13:06 +03:00
Compare commits
54 Commits
1.0.0-rc.3
...
1.1.3
Author | SHA1 | Date | |
---|---|---|---|
5bc6d90f8b | |||
9816507a75 | |||
7000cbc2d2 | |||
6df242bc97 | |||
f4453fd729 | |||
d8011c00ab | |||
da5d75e97e | |||
2adb87ef41 | |||
74926c9831 | |||
68f3aea036 | |||
f91e4dece3 | |||
c62365adc4 | |||
bb7a3f41e3 | |||
f64c1387f8 | |||
59c77e706b | |||
e0965ce09b | |||
0a3fde3774 | |||
93f7b26427 | |||
e1cb3b7b23 | |||
5bf56ea041 | |||
9e98ed04de | |||
1c89e6f771 | |||
0220a93010 | |||
512cc1f065 | |||
9437766539 | |||
1127681d56 | |||
e33ac1c56e | |||
d24439ada0 | |||
1ae100beab | |||
82a5a78a36 | |||
4ede4340ab | |||
170a6bf770 | |||
21db821324 | |||
b384839d15 | |||
2da10d277b | |||
532b5ede35 | |||
2bd2f81f4f | |||
e318e66de5 | |||
0820d0a607 | |||
b8d1cfe91a | |||
d85a233611 | |||
973d4a866d | |||
d19c2b6942 | |||
4dde57451d | |||
44686c4f1e | |||
db02ecf259 | |||
aa004d4595 | |||
1bb65457ed | |||
0c9a4af8ab | |||
cc94c1b584 | |||
e8d8801db4 | |||
521803cdcd | |||
0eb480324c | |||
7c78aff578 |
497
Parsedown.php
497
Parsedown.php
@ -18,17 +18,19 @@ class Parsedown
|
||||
#
|
||||
# Philosophy
|
||||
|
||||
# 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.
|
||||
# Parsedown recognises that the Markdown syntax is optimised for humans so
|
||||
# it tries to read like one. It goes through text line by line. It looks at
|
||||
# how lines start to identify blocks. It looks for special characters to
|
||||
# identify inline elements.
|
||||
|
||||
#
|
||||
# ~
|
||||
|
||||
function text($text)
|
||||
{
|
||||
# make sure no definitions are set
|
||||
$this->Definitions = array();
|
||||
|
||||
# standardize line breaks
|
||||
$text = str_replace("\r\n", "\n", $text);
|
||||
$text = str_replace("\r", "\n", $text);
|
||||
@ -48,9 +50,6 @@ class Parsedown
|
||||
# trim line breaks
|
||||
$markup = trim($markup, "\n");
|
||||
|
||||
# clean up
|
||||
$this->definitions = array();
|
||||
|
||||
return $markup;
|
||||
}
|
||||
|
||||
@ -58,6 +57,8 @@ class Parsedown
|
||||
# Setters
|
||||
#
|
||||
|
||||
private $breaksEnabled;
|
||||
|
||||
function setBreaksEnabled($breaksEnabled)
|
||||
{
|
||||
$this->breaksEnabled = $breaksEnabled;
|
||||
@ -65,13 +66,20 @@ class Parsedown
|
||||
return $this;
|
||||
}
|
||||
|
||||
private $breaksEnabled;
|
||||
private $markupEscaped;
|
||||
|
||||
function setMarkupEscaped($markupEscaped)
|
||||
{
|
||||
$this->markupEscaped = $markupEscaped;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
#
|
||||
# Blocks
|
||||
# Lines
|
||||
#
|
||||
|
||||
protected $blockMarkers = array(
|
||||
protected $BlockTypes = array(
|
||||
'#' => array('Atx'),
|
||||
'*' => array('Rule', 'List'),
|
||||
'+' => array('List'),
|
||||
@ -87,24 +95,31 @@ class Parsedown
|
||||
'8' => array('List'),
|
||||
'9' => array('List'),
|
||||
':' => array('Table'),
|
||||
'<' => array('Markup'),
|
||||
'<' => array('Comment', 'Markup'),
|
||||
'=' => array('Setext'),
|
||||
'>' => array('Quote'),
|
||||
'[' => array('Reference'),
|
||||
'_' => array('Rule'),
|
||||
'`' => array('FencedCode'),
|
||||
'|' => array('Table'),
|
||||
'~' => array('FencedCode'),
|
||||
);
|
||||
|
||||
protected $definitionMarkers = array(
|
||||
# ~
|
||||
|
||||
protected $DefinitionTypes = array(
|
||||
'[' => array('Reference'),
|
||||
);
|
||||
|
||||
# ~
|
||||
|
||||
protected $unmarkedBlockTypes = array(
|
||||
'CodeBlock',
|
||||
);
|
||||
|
||||
#
|
||||
# Blocks
|
||||
#
|
||||
|
||||
private function lines(array $lines)
|
||||
{
|
||||
$CurrentBlock = null;
|
||||
@ -134,7 +149,7 @@ class Parsedown
|
||||
|
||||
$Line = array('body' => $line, 'indent' => $indent, 'text' => $text);
|
||||
|
||||
# Multiline block types define "addTo" methods.
|
||||
# ~
|
||||
|
||||
if (isset($CurrentBlock['incomplete']))
|
||||
{
|
||||
@ -161,17 +176,15 @@ class Parsedown
|
||||
|
||||
$marker = $text[0];
|
||||
|
||||
# Definitions
|
||||
|
||||
if (isset($this->definitionMarkers[$marker]))
|
||||
if (isset($this->DefinitionTypes[$marker]))
|
||||
{
|
||||
foreach ($this->definitionMarkers[$marker] as $definitionType)
|
||||
foreach ($this->DefinitionTypes[$marker] as $definitionType)
|
||||
{
|
||||
$Definition = $this->{'identify'.$definitionType}($Line, $CurrentBlock);
|
||||
|
||||
if (isset($Definition))
|
||||
{
|
||||
$this->definitions[$definitionType][$Definition['id']] = $Definition['data'];
|
||||
$this->Definitions[$definitionType][$Definition['id']] = $Definition['data'];
|
||||
|
||||
continue 2;
|
||||
}
|
||||
@ -182,9 +195,9 @@ class Parsedown
|
||||
|
||||
$blockTypes = $this->unmarkedBlockTypes;
|
||||
|
||||
if (isset($this->blockMarkers[$marker]))
|
||||
if (isset($this->BlockTypes[$marker]))
|
||||
{
|
||||
foreach ($this->blockMarkers[$marker] as $blockType)
|
||||
foreach ($this->BlockTypes[$marker] as $blockType)
|
||||
{
|
||||
$blockTypes []= $blockType;
|
||||
}
|
||||
@ -195,23 +208,19 @@ class Parsedown
|
||||
|
||||
foreach ($blockTypes as $blockType)
|
||||
{
|
||||
# Block types define "identify" methods.
|
||||
|
||||
$Block = $this->{'identify'.$blockType}($Line, $CurrentBlock);
|
||||
|
||||
if (isset($Block))
|
||||
{
|
||||
$Block['type'] = $blockType;
|
||||
|
||||
if ( ! isset($Block['identified'])) # »
|
||||
if ( ! isset($Block['identified']))
|
||||
{
|
||||
$Elements []= $CurrentBlock['element'];
|
||||
|
||||
$Block['identified'] = true;
|
||||
}
|
||||
|
||||
# Multiline block types define "addTo" methods.
|
||||
|
||||
if (method_exists($this, 'addTo'.$blockType))
|
||||
{
|
||||
$Block['incomplete'] = true;
|
||||
@ -225,7 +234,7 @@ class Parsedown
|
||||
|
||||
# ~
|
||||
|
||||
if ($CurrentBlock['type'] === 'Paragraph' and ! isset($CurrentBlock['interrupted']))
|
||||
if (isset($CurrentBlock) and ! isset($CurrentBlock['type']) and ! isset($CurrentBlock['interrupted']))
|
||||
{
|
||||
$CurrentBlock['element']['text'] .= "\n".$text;
|
||||
}
|
||||
@ -233,15 +242,9 @@ class Parsedown
|
||||
{
|
||||
$Elements []= $CurrentBlock['element'];
|
||||
|
||||
$CurrentBlock = array(
|
||||
'type' => 'Paragraph',
|
||||
'identified' => true,
|
||||
'element' => array(
|
||||
'name' => 'p',
|
||||
'text' => $text,
|
||||
'handler' => 'line',
|
||||
),
|
||||
);
|
||||
$CurrentBlock = $this->buildParagraph($Line);
|
||||
|
||||
$CurrentBlock['identified'] = true;
|
||||
}
|
||||
}
|
||||
|
||||
@ -285,7 +288,7 @@ class Parsedown
|
||||
|
||||
$Block = array(
|
||||
'element' => array(
|
||||
'name' => 'h'.$level,
|
||||
'name' => 'h' . min(6, $level),
|
||||
'text' => $text,
|
||||
'handler' => 'line',
|
||||
),
|
||||
@ -296,15 +299,22 @@ class Parsedown
|
||||
}
|
||||
|
||||
#
|
||||
# Rule
|
||||
# Code
|
||||
|
||||
protected function identifyRule($Line)
|
||||
protected function identifyCodeBlock($Line)
|
||||
{
|
||||
if (preg_match('/^(['.$Line['text'][0].'])([ ]{0,2}\1){2,}[ ]*$/', $Line['text']))
|
||||
if ($Line['indent'] >= 4)
|
||||
{
|
||||
$text = substr($Line['body'], 4);
|
||||
|
||||
$Block = array(
|
||||
'element' => array(
|
||||
'name' => 'hr'
|
||||
'name' => 'pre',
|
||||
'handler' => 'element',
|
||||
'text' => array(
|
||||
'name' => 'code',
|
||||
'text' => $text,
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
@ -312,104 +322,77 @@ class Parsedown
|
||||
}
|
||||
}
|
||||
|
||||
#
|
||||
# Reference
|
||||
|
||||
protected function identifyReference($Line)
|
||||
protected function addToCodeBlock($Line, $Block)
|
||||
{
|
||||
if (preg_match('/^\[(.+?)\]:[ ]*<?(\S+?)>?(?:[ ]+["\'(](.+)["\')])?[ ]*$/', $Line['text'], $matches))
|
||||
if ($Line['indent'] >= 4)
|
||||
{
|
||||
$Definition = array(
|
||||
'id' => strtolower($matches[1]),
|
||||
'data' => array(
|
||||
'url' => $matches[2],
|
||||
),
|
||||
);
|
||||
|
||||
if (isset($matches[3]))
|
||||
if (isset($Block['interrupted']))
|
||||
{
|
||||
$Definition['data']['title'] = $matches[3];
|
||||
$Block['element']['text']['text'] .= "\n";
|
||||
|
||||
unset($Block['interrupted']);
|
||||
}
|
||||
|
||||
return $Definition;
|
||||
$Block['element']['text']['text'] .= "\n";
|
||||
|
||||
$text = substr($Line['body'], 4);
|
||||
|
||||
$Block['element']['text']['text'] .= $text;
|
||||
|
||||
return $Block;
|
||||
}
|
||||
}
|
||||
|
||||
#
|
||||
# Setext
|
||||
|
||||
protected function identifySetext($Line, array $Block = null)
|
||||
protected function completeCodeBlock($Block)
|
||||
{
|
||||
if ( ! isset($Block) or $Block['type'] !== 'Paragraph' or isset($Block['interrupted']))
|
||||
$text = $Block['element']['text']['text'];
|
||||
|
||||
$text = htmlspecialchars($text, ENT_NOQUOTES, 'UTF-8');
|
||||
|
||||
$Block['element']['text']['text'] = $text;
|
||||
|
||||
return $Block;
|
||||
}
|
||||
|
||||
#
|
||||
# Comment
|
||||
|
||||
protected function identifyComment($Line)
|
||||
{
|
||||
if ($this->markupEscaped)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (chop($Line['text'], $Line['text'][0]) === '')
|
||||
if (isset($Line['text'][3]) and $Line['text'][3] === '-' and $Line['text'][2] === '-' and $Line['text'][1] === '!')
|
||||
{
|
||||
$Block['element']['name'] = $Line['text'][0] === '=' ? 'h1' : 'h2';
|
||||
|
||||
return $Block;
|
||||
}
|
||||
}
|
||||
|
||||
#
|
||||
# Markup
|
||||
|
||||
protected function identifyMarkup($Line)
|
||||
{
|
||||
if (preg_match('/^<(\w[\w\d]*)(?:[ ][^>\/]*)?(\/?)[ ]*>/', $Line['text'], $matches))
|
||||
{
|
||||
if (in_array($matches[1], $this->textLevelElements))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
$Block = array(
|
||||
'element' => $Line['body'],
|
||||
);
|
||||
|
||||
if ($matches[2] or $matches[1] === 'hr' or preg_match('/<\/'.$matches[1].'>[ ]*$/', $Line['text']))
|
||||
if (preg_match('/-->$/', $Line['text']))
|
||||
{
|
||||
$Block['closed'] = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
$Block['depth'] = 0;
|
||||
$Block['start'] = '<'.$matches[1].'>';
|
||||
$Block['end'] = '</'.$matches[1].'>';
|
||||
}
|
||||
|
||||
return $Block;
|
||||
}
|
||||
}
|
||||
|
||||
protected function addToMarkup($Line, array $Block)
|
||||
protected function addToComment($Line, array $Block)
|
||||
{
|
||||
if (isset($Block['closed']))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (stripos($Line['text'], $Block['start']) !== false) # opening tag
|
||||
{
|
||||
$Block['depth'] ++;
|
||||
}
|
||||
$Block['element'] .= "\n" . $Line['body'];
|
||||
|
||||
if (stripos($Line['text'], $Block['end']) !== false) # closing tag
|
||||
if (preg_match('/-->$/', $Line['text']))
|
||||
{
|
||||
if ($Block['depth'] > 0)
|
||||
{
|
||||
$Block['depth'] --;
|
||||
}
|
||||
else
|
||||
{
|
||||
$Block['closed'] = true;
|
||||
}
|
||||
$Block['closed'] = true;
|
||||
}
|
||||
|
||||
$Block['element'] .= "\n".$Line['body'];
|
||||
|
||||
return $Block;
|
||||
}
|
||||
|
||||
@ -418,7 +401,7 @@ class Parsedown
|
||||
|
||||
protected function identifyFencedCode($Line)
|
||||
{
|
||||
if (preg_match('/^(['.$Line['text'][0].']{3,})[ ]*(\w+)?[ ]*$/', $Line['text'], $matches))
|
||||
if (preg_match('/^(['.$Line['text'][0].']{3,})[ ]*([\w-]+)?[ ]*$/', $Line['text'], $matches))
|
||||
{
|
||||
$Element = array(
|
||||
'name' => 'code',
|
||||
@ -593,6 +576,8 @@ class Parsedown
|
||||
if (isset($Block['interrupted']))
|
||||
{
|
||||
$Block['element']['text'] []= '';
|
||||
|
||||
unset($Block['interrupted']);
|
||||
}
|
||||
|
||||
$Block['element']['text'] []= $matches[1];
|
||||
@ -608,12 +593,118 @@ class Parsedown
|
||||
}
|
||||
}
|
||||
|
||||
#
|
||||
# Rule
|
||||
|
||||
protected function identifyRule($Line)
|
||||
{
|
||||
if (preg_match('/^(['.$Line['text'][0].'])([ ]{0,2}\1){2,}[ ]*$/', $Line['text']))
|
||||
{
|
||||
$Block = array(
|
||||
'element' => array(
|
||||
'name' => 'hr'
|
||||
),
|
||||
);
|
||||
|
||||
return $Block;
|
||||
}
|
||||
}
|
||||
|
||||
#
|
||||
# Setext
|
||||
|
||||
protected function identifySetext($Line, array $Block = null)
|
||||
{
|
||||
if ( ! isset($Block) or isset($Block['type']) or isset($Block['interrupted']))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (chop($Line['text'], $Line['text'][0]) === '')
|
||||
{
|
||||
$Block['element']['name'] = $Line['text'][0] === '=' ? 'h1' : 'h2';
|
||||
|
||||
return $Block;
|
||||
}
|
||||
}
|
||||
|
||||
#
|
||||
# Markup
|
||||
|
||||
protected function identifyMarkup($Line)
|
||||
{
|
||||
if ($this->markupEscaped)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (preg_match('/^<(\w[\w\d]*)(?:[ ][^>]*)?(\/?)[ ]*>/', $Line['text'], $matches))
|
||||
{
|
||||
if (in_array($matches[1], $this->textLevelElements))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
$Block = array(
|
||||
'element' => $Line['body'],
|
||||
);
|
||||
|
||||
if ($matches[2] or in_array($matches[1], $this->voidElements) or preg_match('/<\/'.$matches[1].'>[ ]*$/', $Line['text']))
|
||||
{
|
||||
$Block['closed'] = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
$Block['depth'] = 0;
|
||||
$Block['name'] = $matches[1];
|
||||
}
|
||||
|
||||
return $Block;
|
||||
}
|
||||
}
|
||||
|
||||
protected function addToMarkup($Line, array $Block)
|
||||
{
|
||||
if (isset($Block['closed']))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (preg_match('/<'.$Block['name'].'([ ][^\/]+)?>/', $Line['text'])) # opening tag
|
||||
{
|
||||
$Block['depth'] ++;
|
||||
}
|
||||
|
||||
if (stripos($Line['text'], '</'.$Block['name'].'>') !== false) # closing tag
|
||||
{
|
||||
if ($Block['depth'] > 0)
|
||||
{
|
||||
$Block['depth'] --;
|
||||
}
|
||||
else
|
||||
{
|
||||
$Block['closed'] = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (isset($Block['interrupted']))
|
||||
{
|
||||
$Block['element'] .= "\n";
|
||||
|
||||
unset($Block['interrupted']);
|
||||
}
|
||||
|
||||
$Block['element'] .= "\n".$Line['body'];
|
||||
|
||||
return $Block;
|
||||
}
|
||||
|
||||
#
|
||||
# Table
|
||||
|
||||
protected function identifyTable($Line, array $Block = null)
|
||||
{
|
||||
if ( ! isset($Block) or $Block['type'] !== 'Paragraph' or isset($Block['interrupted']))
|
||||
if ( ! isset($Block) or isset($Block['type']) or isset($Block['interrupted']))
|
||||
{
|
||||
return;
|
||||
}
|
||||
@ -764,57 +855,42 @@ class Parsedown
|
||||
}
|
||||
|
||||
#
|
||||
# Code
|
||||
# Definitions
|
||||
#
|
||||
|
||||
protected function identifyCodeBlock($Line)
|
||||
protected function identifyReference($Line)
|
||||
{
|
||||
if ($Line['indent'] >= 4)
|
||||
if (preg_match('/^\[(.+?)\]:[ ]*<?(\S+?)>?(?:[ ]+["\'(](.+)["\')])?[ ]*$/', $Line['text'], $matches))
|
||||
{
|
||||
$text = substr($Line['body'], 4);
|
||||
|
||||
$Block = array(
|
||||
'element' => array(
|
||||
'name' => 'pre',
|
||||
'handler' => 'element',
|
||||
'text' => array(
|
||||
'name' => 'code',
|
||||
'text' => $text,
|
||||
),
|
||||
$Definition = array(
|
||||
'id' => strtolower($matches[1]),
|
||||
'data' => array(
|
||||
'url' => $matches[2],
|
||||
),
|
||||
);
|
||||
|
||||
return $Block;
|
||||
}
|
||||
}
|
||||
|
||||
protected function addToCodeBlock($Line, $Block)
|
||||
{
|
||||
if ($Line['indent'] >= 4)
|
||||
{
|
||||
if (isset($Block['interrupted']))
|
||||
if (isset($matches[3]))
|
||||
{
|
||||
$Block['element']['text']['text'] .= "\n";
|
||||
|
||||
unset($Block['interrupted']);
|
||||
$Definition['data']['title'] = $matches[3];
|
||||
}
|
||||
|
||||
$Block['element']['text']['text'] .= "\n";
|
||||
|
||||
$text = substr($Line['body'], 4);
|
||||
|
||||
$Block['element']['text']['text'] .= $text;
|
||||
|
||||
return $Block;
|
||||
return $Definition;
|
||||
}
|
||||
}
|
||||
|
||||
protected function completeCodeBlock($Block)
|
||||
#
|
||||
# ~
|
||||
#
|
||||
|
||||
protected function buildParagraph($Line)
|
||||
{
|
||||
$text = $Block['element']['text']['text'];
|
||||
|
||||
$text = htmlspecialchars($text, ENT_NOQUOTES, 'UTF-8');
|
||||
|
||||
$Block['element']['text']['text'] = $text;
|
||||
$Block = array(
|
||||
'element' => array(
|
||||
'name' => 'p',
|
||||
'text' => $Line['text'],
|
||||
'handler' => 'line',
|
||||
),
|
||||
);
|
||||
|
||||
return $Block;
|
||||
}
|
||||
@ -823,7 +899,7 @@ class Parsedown
|
||||
# ~
|
||||
#
|
||||
|
||||
private function element(array $Element)
|
||||
protected function element(array $Element)
|
||||
{
|
||||
$markup = '<'.$Element['name'];
|
||||
|
||||
@ -858,7 +934,7 @@ class Parsedown
|
||||
return $markup;
|
||||
}
|
||||
|
||||
private function elements(array $Elements)
|
||||
protected function elements(array $Elements)
|
||||
{
|
||||
$markup = '';
|
||||
|
||||
@ -871,7 +947,7 @@ class Parsedown
|
||||
|
||||
$markup .= "\n";
|
||||
|
||||
if (is_string($Element)) # because of markup
|
||||
if (is_string($Element)) # because of Markup
|
||||
{
|
||||
$markup .= $Element;
|
||||
|
||||
@ -890,7 +966,7 @@ class Parsedown
|
||||
# Spans
|
||||
#
|
||||
|
||||
protected $spanMarkers = array(
|
||||
protected $SpanTypes = array(
|
||||
'!' => array('Link'), # ?
|
||||
'&' => array('Ampersand'),
|
||||
'*' => array('Emphasis'),
|
||||
@ -903,8 +979,14 @@ class Parsedown
|
||||
'\\' => array('EscapeSequence'),
|
||||
);
|
||||
|
||||
# ~
|
||||
|
||||
protected $spanMarkerList = '*_!&[</`~\\';
|
||||
|
||||
#
|
||||
# ~
|
||||
#
|
||||
|
||||
public function line($text)
|
||||
{
|
||||
$markup = '';
|
||||
@ -913,17 +995,19 @@ class Parsedown
|
||||
|
||||
$markerPosition = 0;
|
||||
|
||||
while ($markedExcerpt = strpbrk($remainder, $this->spanMarkerList))
|
||||
while ($excerpt = strpbrk($remainder, $this->spanMarkerList))
|
||||
{
|
||||
$marker = $markedExcerpt[0];
|
||||
$marker = $excerpt[0];
|
||||
|
||||
$markerPosition += strpos($remainder, $marker);
|
||||
|
||||
foreach ($this->spanMarkers[$marker] as $spanType)
|
||||
$Excerpt = array('text' => $excerpt, 'context' => $text);
|
||||
|
||||
foreach ($this->SpanTypes[$marker] as $spanType)
|
||||
{
|
||||
$handler = 'identify'.$spanType;
|
||||
|
||||
$Span = $this->$handler($markedExcerpt, $text);
|
||||
$Span = $this->$handler($Excerpt);
|
||||
|
||||
if ( ! isset($Span))
|
||||
{
|
||||
@ -948,7 +1032,7 @@ class Parsedown
|
||||
|
||||
$markup .= $this->readPlainText($plainText);
|
||||
|
||||
$markup .= isset($Span['element']) ? $this->element($Span['element']) : $Span['markup'];
|
||||
$markup .= isset($Span['markup']) ? $Span['markup'] : $this->element($Span['element']);
|
||||
|
||||
$text = substr($text, $Span['position'] + $Span['extent']);
|
||||
|
||||
@ -959,7 +1043,7 @@ class Parsedown
|
||||
continue 2;
|
||||
}
|
||||
|
||||
$remainder = substr($markedExcerpt, 1);
|
||||
$remainder = substr($excerpt, 1);
|
||||
|
||||
$markerPosition ++;
|
||||
}
|
||||
@ -973,14 +1057,14 @@ class Parsedown
|
||||
# ~
|
||||
#
|
||||
|
||||
protected function identifyUrl($excerpt, $text)
|
||||
protected function identifyUrl($Excerpt)
|
||||
{
|
||||
if ( ! isset($excerpt[1]) or $excerpt[1] !== '/')
|
||||
if ( ! isset($Excerpt['text'][1]) or $Excerpt['text'][1] !== '/')
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (preg_match('/\bhttps?:[\/]{2}[^\s]+\b\/*/ui', $text, $matches, PREG_OFFSET_CAPTURE))
|
||||
if (preg_match('/\bhttps?:[\/]{2}[^\s<]+\b\/*/ui', $Excerpt['context'], $matches, PREG_OFFSET_CAPTURE))
|
||||
{
|
||||
$url = str_replace(array('&', '<'), array('&', '<'), $matches[0][0]);
|
||||
|
||||
@ -998,9 +1082,9 @@ class Parsedown
|
||||
}
|
||||
}
|
||||
|
||||
protected function identifyAmpersand($excerpt)
|
||||
protected function identifyAmpersand($Excerpt)
|
||||
{
|
||||
if ( ! preg_match('/^&#?\w+;/', $excerpt))
|
||||
if ( ! preg_match('/^&#?\w+;/', $Excerpt['text']))
|
||||
{
|
||||
return array(
|
||||
'markup' => '&',
|
||||
@ -1009,14 +1093,14 @@ class Parsedown
|
||||
}
|
||||
}
|
||||
|
||||
protected function identifyStrikethrough($excerpt)
|
||||
protected function identifyStrikethrough($Excerpt)
|
||||
{
|
||||
if ( ! isset($excerpt[1]))
|
||||
if ( ! isset($Excerpt['text'][1]))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if ($excerpt[1] === $excerpt[0] and preg_match('/^~~(?=\S)(.+?)(?<=\S)~~/', $excerpt, $matches))
|
||||
if ($Excerpt['text'][1] === '~' and preg_match('/^~~(?=\S)(.+?)(?<=\S)~~/', $Excerpt['text'], $matches))
|
||||
{
|
||||
return array(
|
||||
'extent' => strlen($matches[0]),
|
||||
@ -1029,12 +1113,12 @@ class Parsedown
|
||||
}
|
||||
}
|
||||
|
||||
protected function identifyEscapeSequence($excerpt)
|
||||
protected function identifyEscapeSequence($Excerpt)
|
||||
{
|
||||
if (in_array($excerpt[1], $this->specialCharacters))
|
||||
if (isset($Excerpt['text'][1]) and in_array($Excerpt['text'][1], $this->specialCharacters))
|
||||
{
|
||||
return array(
|
||||
'markup' => $excerpt[1],
|
||||
'markup' => $Excerpt['text'][1],
|
||||
'extent' => 2,
|
||||
);
|
||||
}
|
||||
@ -1048,9 +1132,9 @@ class Parsedown
|
||||
);
|
||||
}
|
||||
|
||||
protected function identifyUrlTag($excerpt)
|
||||
protected function identifyUrlTag($Excerpt)
|
||||
{
|
||||
if (strpos($excerpt, '>') !== false and preg_match('/^<(https?:[\/]{2}[^\s]+?)>/i', $excerpt, $matches))
|
||||
if (strpos($Excerpt['text'], '>') !== false and preg_match('/^<(https?:[\/]{2}[^\s]+?)>/i', $Excerpt['text'], $matches))
|
||||
{
|
||||
$url = str_replace(array('&', '<'), array('&', '<'), $matches[1]);
|
||||
|
||||
@ -1067,9 +1151,9 @@ class Parsedown
|
||||
}
|
||||
}
|
||||
|
||||
protected function identifyEmailTag($excerpt)
|
||||
protected function identifyEmailTag($Excerpt)
|
||||
{
|
||||
if (strpos($excerpt, '>') !== false and preg_match('/<(\S+?@\S+?)>/', $excerpt, $matches))
|
||||
if (strpos($Excerpt['text'], '>') !== false and preg_match('/^<(\S+?@\S+?)>/', $Excerpt['text'], $matches))
|
||||
{
|
||||
return array(
|
||||
'extent' => strlen($matches[0]),
|
||||
@ -1084,9 +1168,14 @@ class Parsedown
|
||||
}
|
||||
}
|
||||
|
||||
protected function identifyTag($excerpt)
|
||||
protected function identifyTag($Excerpt)
|
||||
{
|
||||
if (strpos($excerpt, '>') !== false and preg_match('/^<\/?\w.*?>/', $excerpt, $matches))
|
||||
if ($this->markupEscaped)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (strpos($Excerpt['text'], '>') !== false and preg_match('/^<\/?\w.*?>/', $Excerpt['text'], $matches))
|
||||
{
|
||||
return array(
|
||||
'markup' => $matches[0],
|
||||
@ -1095,11 +1184,11 @@ class Parsedown
|
||||
}
|
||||
}
|
||||
|
||||
protected function identifyInlineCode($excerpt)
|
||||
protected function identifyInlineCode($Excerpt)
|
||||
{
|
||||
$marker = $excerpt[0];
|
||||
$marker = $Excerpt['text'][0];
|
||||
|
||||
if (preg_match('/^('.$marker.'+)[ ]*(.+?)[ ]*(?<!'.$marker.')\1(?!'.$marker.')/', $excerpt, $matches))
|
||||
if (preg_match('/^('.$marker.'+)[ ]*(.+?)[ ]*(?<!'.$marker.')\1(?!'.$marker.')/', $Excerpt['text'], $matches))
|
||||
{
|
||||
$text = $matches[2];
|
||||
$text = htmlspecialchars($text, ENT_NOQUOTES, 'UTF-8');
|
||||
@ -1114,25 +1203,25 @@ class Parsedown
|
||||
}
|
||||
}
|
||||
|
||||
protected function identifyLink($excerpt)
|
||||
protected function identifyLink($Excerpt)
|
||||
{
|
||||
$extent = $excerpt[0] === '!' ? 1 : 0;
|
||||
$extent = $Excerpt['text'][0] === '!' ? 1 : 0;
|
||||
|
||||
if (strpos($excerpt, ']') and preg_match('/\[((?:[^][]|(?R))*)\]/', $excerpt, $matches))
|
||||
if (strpos($Excerpt['text'], ']') and preg_match('/\[((?:[^][]|(?R))*)\]/', $Excerpt['text'], $matches))
|
||||
{
|
||||
$Link = array('text' => $matches[1], 'label' => strtolower($matches[1]));
|
||||
|
||||
$extent += strlen($matches[0]);
|
||||
|
||||
$substring = substr($excerpt, $extent);
|
||||
$substring = substr($Excerpt['text'], $extent);
|
||||
|
||||
if (preg_match('/^\s*\[(.+?)\]/', $substring, $matches))
|
||||
if (preg_match('/^\s*\[([^][]+)\]/', $substring, $matches))
|
||||
{
|
||||
$Link['label'] = strtolower($matches[1]);
|
||||
|
||||
if (isset($this->definitions['Reference'][$Link['label']]))
|
||||
if (isset($this->Definitions['Reference'][$Link['label']]))
|
||||
{
|
||||
$Link += $this->definitions['Reference'][$Link['label']];
|
||||
$Link += $this->Definitions['Reference'][$Link['label']];
|
||||
|
||||
$extent += strlen($matches[0]);
|
||||
}
|
||||
@ -1141,9 +1230,9 @@ class Parsedown
|
||||
return;
|
||||
}
|
||||
}
|
||||
elseif (isset($this->definitions['Reference'][$Link['label']]))
|
||||
elseif (isset($this->Definitions['Reference'][$Link['label']]))
|
||||
{
|
||||
$Link += $this->definitions['Reference'][$Link['label']];
|
||||
$Link += $this->Definitions['Reference'][$Link['label']];
|
||||
|
||||
if (preg_match('/^[ ]*\[\]/', $substring, $matches))
|
||||
{
|
||||
@ -1173,7 +1262,7 @@ class Parsedown
|
||||
|
||||
$url = str_replace(array('&', '<'), array('&', '<'), $Link['url']);
|
||||
|
||||
if ($excerpt[0] === '!')
|
||||
if ($Excerpt['text'][0] === '!')
|
||||
{
|
||||
$Element = array(
|
||||
'name' => 'img',
|
||||
@ -1206,20 +1295,20 @@ class Parsedown
|
||||
);
|
||||
}
|
||||
|
||||
protected function identifyEmphasis($excerpt)
|
||||
protected function identifyEmphasis($Excerpt)
|
||||
{
|
||||
if ( ! isset($excerpt[1]))
|
||||
if ( ! isset($Excerpt['text'][1]))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
$marker = $excerpt[0];
|
||||
$marker = $Excerpt['text'][0];
|
||||
|
||||
if ($excerpt[1] === $marker and preg_match($this->strongRegex[$marker], $excerpt, $matches))
|
||||
if ($Excerpt['text'][1] === $marker and preg_match($this->StrongRegex[$marker], $Excerpt['text'], $matches))
|
||||
{
|
||||
$emphasis = 'strong';
|
||||
}
|
||||
elseif (preg_match($this->emRegex[$marker], $excerpt, $matches))
|
||||
elseif (preg_match($this->EmRegex[$marker], $Excerpt['text'], $matches))
|
||||
{
|
||||
$emphasis = 'em';
|
||||
}
|
||||
@ -1311,7 +1400,7 @@ class Parsedown
|
||||
# Fields
|
||||
#
|
||||
|
||||
protected $definitions;
|
||||
protected $Definitions;
|
||||
|
||||
#
|
||||
# Read-only
|
||||
@ -1320,25 +1409,29 @@ class Parsedown
|
||||
'\\', '`', '*', '_', '{', '}', '[', ']', '(', ')', '>', '#', '+', '-', '.', '!',
|
||||
);
|
||||
|
||||
protected $strongRegex = array(
|
||||
'*' => '/^[*]{2}((?:[^*]|[*][^*]*[*])+?)[*]{2}(?![*])/s',
|
||||
'_' => '/^__((?:[^_]|_[^_]*_)+?)__(?!_)/us',
|
||||
protected $StrongRegex = array(
|
||||
'*' => '/^[*]{2}((?:\\\\\*|[^*]|[*][^*]*[*])+?)[*]{2}(?![*])/s',
|
||||
'_' => '/^__((?:\\\\_|[^_]|_[^_]*_)+?)__(?!_)/us',
|
||||
);
|
||||
|
||||
protected $emRegex = array(
|
||||
'*' => '/^[*]((?:[^*]|[*][*][^*]+?[*][*])+?)[*](?![*])/s',
|
||||
'_' => '/^_((?:[^_]|__[^_]*__)+?)_(?!_)\b/us',
|
||||
protected $EmRegex = array(
|
||||
'*' => '/^[*]((?:\\\\\*|[^*]|[*][*][^*]+?[*][*])+?)[*](?![*])/s',
|
||||
'_' => '/^_((?:\\\\_|[^_]|__[^_]*__)+?)_(?!_)\b/us',
|
||||
);
|
||||
|
||||
protected $voidElements = array(
|
||||
'area', 'base', 'br', 'col', 'command', 'embed', 'hr', 'img', 'input', 'link', 'meta', 'param', 'source',
|
||||
);
|
||||
|
||||
protected $textLevelElements = 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',
|
||||
'i', 'rp', 'del', 'code', 'strike', 'marquee',
|
||||
'q', 'rt', 'ins', 'font', 'strong',
|
||||
's', 'tt', 'sub', 'mark',
|
||||
'u', 'xm', 'sup', 'nobr',
|
||||
'var', 'ruby',
|
||||
'wbr', 'span',
|
||||
'time',
|
||||
);
|
||||
}
|
||||
|
27
README.md
27
README.md
@ -1,17 +1,18 @@
|
||||
## Parsedown
|
||||
|
||||
Better [Markdown](http://en.wikipedia.org/wiki/Markdown) parser for PHP.
|
||||
Better Markdown Parser in PHP
|
||||
|
||||
- [Demo](http://parsedown.org/demo)
|
||||
- [Tests](http://parsedown.org/tests/)
|
||||
[[ demo ]](http://parsedown.org/demo)
|
||||
|
||||
### Features
|
||||
|
||||
* [Fast](http://parsedown.org/speed)
|
||||
* [Consistent](http://parsedown.org/consistency)
|
||||
* [GitHub Flavored](https://help.github.com/articles/github-flavored-markdown)
|
||||
* [Tested](https://travis-ci.org/erusev/parsedown) in PHP 5.2, 5.3, 5.4, 5.5, 5.6 and [hhvm](http://www.hhvm.com/)
|
||||
* [GitHub flavored](https://help.github.com/articles/github-flavored-markdown)
|
||||
* [Tested](http://parsedown.org/tests/) in PHP 5.2, 5.3, 5.4, 5.5, 5.6 and [hhvm](http://www.hhvm.com/)
|
||||
* Extensible
|
||||
* [Markdown Extra extension](https://github.com/erusev/parsedown-extra) <sup>new</sup>
|
||||
* [JavaScript port](https://github.com/hkdobrev/parsedown.js) under development <sup>new</sup>
|
||||
|
||||
### Installation
|
||||
|
||||
@ -24,3 +25,19 @@ $Parsedown = new Parsedown();
|
||||
|
||||
echo $Parsedown->text('Hello _Parsedown_!'); # prints: <p>Hello <em>Parsedown</em>!</p>
|
||||
```
|
||||
|
||||
More examples in [the wiki](https://github.com/erusev/parsedown/wiki/Usage) and in [this video tutorial](http://youtu.be/wYZBY8DEikI).
|
||||
|
||||
### Questions
|
||||
|
||||
**How does Parsedown work?**<br/>
|
||||
Parsedown recognises that the Markdown syntax is optimised for humans so it tries to read like one. It goes through text line by line. It looks at how lines start to identify blocks. It looks for special characters to identify inline elements.
|
||||
|
||||
**Why doesn’t Parsedown use namespaces?**<br/>
|
||||
Using namespaces would mean dropping support for PHP 5.2. We believe that since Parsedown is a single class with an uncommon name, making this trade wouldn't be worth it.
|
||||
|
||||
**Is Parsedown compliant with CommonMark?**<br/>
|
||||
We are [working on it](https://github.com/erusev/parsedown/tree/commonmark).
|
||||
|
||||
**Who uses Parsedown?**<br/>
|
||||
[phpDocumentor](http://www.phpdoc.org/), [October CMS](http://octobercms.com/), [Bolt CMS](http://bolt.cm/), [RaspberryPi.org](http://www.raspberrypi.org/) and [more](https://www.versioneye.com/php/erusev:parsedown/references).
|
||||
|
@ -2,7 +2,7 @@
|
||||
<phpunit bootstrap="test/bootstrap.php" colors="true">
|
||||
<testsuites>
|
||||
<testsuite>
|
||||
<file>test/Test.php</file>
|
||||
<file>test/ParsedownTest.php</file>
|
||||
</testsuite>
|
||||
</testsuites>
|
||||
</phpunit>
|
139
test/ParsedownTest.php
Normal file
139
test/ParsedownTest.php
Normal file
@ -0,0 +1,139 @@
|
||||
<?php
|
||||
|
||||
class ParsedownTest extends PHPUnit_Framework_TestCase
|
||||
{
|
||||
final function __construct($name = null, array $data = array(), $dataName = '')
|
||||
{
|
||||
$this->dirs = $this->initDirs();
|
||||
$this->Parsedown = $this->initParsedown();
|
||||
|
||||
parent::__construct($name, $data, $dataName);
|
||||
}
|
||||
|
||||
private $dirs, $Parsedown;
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
protected function initDirs()
|
||||
{
|
||||
$dirs []= dirname(__FILE__).'/data/';
|
||||
|
||||
return $dirs;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Parsedown
|
||||
*/
|
||||
protected function initParsedown()
|
||||
{
|
||||
$Parsedown = new Parsedown();
|
||||
|
||||
return $Parsedown;
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider data
|
||||
* @param $test
|
||||
* @param $dir
|
||||
*/
|
||||
function test_($test, $dir)
|
||||
{
|
||||
$markdown = file_get_contents($dir . $test . '.md');
|
||||
|
||||
$expectedMarkup = file_get_contents($dir . $test . '.html');
|
||||
|
||||
$expectedMarkup = str_replace("\r\n", "\n", $expectedMarkup);
|
||||
$expectedMarkup = str_replace("\r", "\n", $expectedMarkup);
|
||||
|
||||
$actualMarkup = $this->Parsedown->text($markdown);
|
||||
|
||||
$this->assertEquals($expectedMarkup, $actualMarkup);
|
||||
}
|
||||
|
||||
function data()
|
||||
{
|
||||
$data = array();
|
||||
|
||||
foreach ($this->dirs as $dir)
|
||||
{
|
||||
$Folder = new DirectoryIterator($dir);
|
||||
|
||||
foreach ($Folder as $File)
|
||||
{
|
||||
/** @var $File DirectoryIterator */
|
||||
|
||||
if ( ! $File->isFile())
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
$filename = $File->getFilename();
|
||||
|
||||
$extension = pathinfo($filename, PATHINFO_EXTENSION);
|
||||
|
||||
if ($extension !== 'md')
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
$basename = $File->getBasename('.md');
|
||||
|
||||
if (file_exists($dir . $basename . '.html'))
|
||||
{
|
||||
$data []= array($basename, $dir);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
public function test_no_markup()
|
||||
{
|
||||
$markdownWithHtml = <<<MARKDOWN_WITH_MARKUP
|
||||
<div>_content_</div>
|
||||
|
||||
sparse:
|
||||
|
||||
<div>
|
||||
<div class="inner">
|
||||
_content_
|
||||
</div>
|
||||
</div>
|
||||
|
||||
paragraph
|
||||
|
||||
<style type="text/css">
|
||||
p {
|
||||
color: red;
|
||||
}
|
||||
</style>
|
||||
|
||||
comment
|
||||
|
||||
<!-- html comment -->
|
||||
MARKDOWN_WITH_MARKUP;
|
||||
|
||||
$expectedHtml = <<<EXPECTED_HTML
|
||||
<p><div><em>content</em></div></p>
|
||||
<p>sparse:</p>
|
||||
<p><div>
|
||||
<div class="inner">
|
||||
<em>content</em>
|
||||
</div>
|
||||
</div></p>
|
||||
<p>paragraph</p>
|
||||
<p><style type="text/css"></p>
|
||||
<pre><code>p {
|
||||
color: red;
|
||||
}</code></pre>
|
||||
<p></style></p>
|
||||
<p>comment</p>
|
||||
<p><!-- html comment --></p>
|
||||
EXPECTED_HTML;
|
||||
$parsedownWithNoMarkup = new Parsedown();
|
||||
$parsedownWithNoMarkup->setMarkupEscaped(true);
|
||||
$this->assertEquals($expectedHtml, $parsedownWithNoMarkup->text($markdownWithHtml));
|
||||
}
|
||||
}
|
@ -1,65 +0,0 @@
|
||||
<?php
|
||||
|
||||
class Test extends PHPUnit_Framework_TestCase
|
||||
{
|
||||
public function __construct($name = null, array $data = array(), $dataName = '')
|
||||
{
|
||||
$this->dataDir = dirname(__FILE__).'/data/';
|
||||
|
||||
parent::__construct($name, $data, $dataName);
|
||||
}
|
||||
|
||||
private $dataDir;
|
||||
|
||||
/**
|
||||
* @dataProvider data
|
||||
*/
|
||||
function test_($filename)
|
||||
{
|
||||
$markdown = file_get_contents($this->dataDir . $filename . '.md');
|
||||
|
||||
$expectedMarkup = file_get_contents($this->dataDir . $filename . '.html');
|
||||
|
||||
$expectedMarkup = str_replace("\r\n", "\n", $expectedMarkup);
|
||||
$expectedMarkup = str_replace("\r", "\n", $expectedMarkup);
|
||||
|
||||
$actualMarkup = Parsedown::instance()->text($markdown);
|
||||
|
||||
$this->assertEquals($expectedMarkup, $actualMarkup);
|
||||
}
|
||||
|
||||
function data()
|
||||
{
|
||||
$data = array();
|
||||
|
||||
$Folder = new DirectoryIterator($this->dataDir);
|
||||
|
||||
foreach ($Folder as $File)
|
||||
{
|
||||
/** @var $File DirectoryIterator */
|
||||
|
||||
if ( ! $File->isFile())
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
$filename = $File->getFilename();
|
||||
|
||||
$extension = pathinfo($filename, PATHINFO_EXTENSION);
|
||||
|
||||
if ($extension !== 'md')
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
$basename = $File->getBasename('.md');
|
||||
|
||||
if (file_exists($this->dataDir . $basename . '.html'))
|
||||
{
|
||||
$data []= array($basename);
|
||||
}
|
||||
}
|
||||
|
||||
return $data;
|
||||
}
|
||||
}
|
@ -4,5 +4,6 @@
|
||||
<h4>h4</h4>
|
||||
<h5>h5</h5>
|
||||
<h6>h6</h6>
|
||||
<h6>h6</h6>
|
||||
<h1>closed h1</h1>
|
||||
<p>#</p>
|
@ -10,6 +10,8 @@
|
||||
|
||||
###### h6
|
||||
|
||||
####### h6
|
||||
|
||||
# closed h1 #
|
||||
|
||||
#
|
@ -1,5 +1,13 @@
|
||||
<div>_content_</div>
|
||||
<p>sparse:</p>
|
||||
<div>
|
||||
<div class="inner">
|
||||
_content_
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<p>paragraph</p>
|
||||
<style type="text/css">
|
||||
p {
|
||||
color: red;
|
||||
}
|
||||
</style>
|
@ -3,5 +3,15 @@
|
||||
sparse:
|
||||
|
||||
<div>
|
||||
<div class="inner">
|
||||
_content_
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
paragraph
|
||||
|
||||
<style type="text/css">
|
||||
p {
|
||||
color: red;
|
||||
}
|
||||
</style>
|
||||
|
@ -1,4 +1,6 @@
|
||||
<p>escaped *emphasis*.</p>
|
||||
<p><code>escaped \*emphasis\* in a code span</code></p>
|
||||
<pre><code>escaped \*emphasis\* in a code block</code></pre>
|
||||
<p>\ ` * _ { } [ ] ( ) > # + - . !</p>
|
||||
<p>\ ` * _ { } [ ] ( ) > # + - . !</p>
|
||||
<p><em>one_two</em> <strong>one_two</strong></p>
|
||||
<p><em>one*two</em> <strong>one*two</strong></p>
|
@ -4,4 +4,8 @@ escaped \*emphasis\*.
|
||||
|
||||
escaped \*emphasis\* in a code block
|
||||
|
||||
\\ \` \* \_ \{ \} \[ \] \( \) \> \# \+ \- \. \!
|
||||
\\ \` \* \_ \{ \} \[ \] \( \) \> \# \+ \- \. \!
|
||||
|
||||
_one\_two_ __one\_two__
|
||||
|
||||
*one\*two* **one\*two**
|
5
test/data/html_comment.html
Normal file
5
test/data/html_comment.html
Normal file
@ -0,0 +1,5 @@
|
||||
<!-- single line -->
|
||||
<p>paragraph</p>
|
||||
<!--
|
||||
multiline -->
|
||||
<p>paragraph</p>
|
8
test/data/html_comment.md
Normal file
8
test/data/html_comment.md
Normal file
@ -0,0 +1,8 @@
|
||||
<!-- single line -->
|
||||
|
||||
paragraph
|
||||
|
||||
<!--
|
||||
multiline -->
|
||||
|
||||
paragraph
|
@ -1,28 +0,0 @@
|
||||
<p>Headings:</p>
|
||||
<h2 id="overview">Overview</h2>
|
||||
<p>blah</p>
|
||||
<H2 id="block">Block Elements</H2>
|
||||
<p>blah</p>
|
||||
<h3 id="span">
|
||||
Span Elements
|
||||
</h3>
|
||||
<p>blah</p>
|
||||
<p>Hr's:</p>
|
||||
<hr>
|
||||
<p>blah</p>
|
||||
<hr/>
|
||||
<p>blah</p>
|
||||
<hr />
|
||||
<p>blah</p>
|
||||
<hr>
|
||||
<p>blah</p>
|
||||
<hr/>
|
||||
<p>blah</p>
|
||||
<hr />
|
||||
<p>blah</p>
|
||||
<hr class="foo" id="bar" />
|
||||
<p>blah</p>
|
||||
<hr class="foo" id="bar"/>
|
||||
<p>blah</p>
|
||||
<hr class="foo" id="bar" >
|
||||
<p>blah</p>
|
@ -1,39 +0,0 @@
|
||||
Headings:
|
||||
|
||||
<h2 id="overview">Overview</h2>
|
||||
blah
|
||||
<H2 id="block">Block Elements</H2>
|
||||
blah
|
||||
<h3 id="span">
|
||||
Span Elements
|
||||
</h3>
|
||||
blah
|
||||
|
||||
Hr's:
|
||||
|
||||
<hr>
|
||||
blah
|
||||
|
||||
<hr/>
|
||||
blah
|
||||
|
||||
<hr />
|
||||
blah
|
||||
|
||||
<hr>
|
||||
blah
|
||||
|
||||
<hr/>
|
||||
blah
|
||||
|
||||
<hr />
|
||||
blah
|
||||
|
||||
<hr class="foo" id="bar" />
|
||||
blah
|
||||
|
||||
<hr class="foo" id="bar"/>
|
||||
blah
|
||||
|
||||
<hr class="foo" id="bar" >
|
||||
blah
|
@ -1,3 +1,4 @@
|
||||
<p>an <a href="http://example.com">implicit</a> reference link</p>
|
||||
<p>an <a href="http://example.com">implicit</a> reference link with an empty link definition</p>
|
||||
<p>an <a href="http://example.com">implicit</a> reference link followed by <a href="http://cnn.com">another</a></p>
|
||||
<p>an <a href="http://example.com" title="Example">explicit</a> reference link with a title</p>
|
@ -4,6 +4,10 @@ an [implicit] reference link
|
||||
|
||||
an [implicit][] reference link with an empty link definition
|
||||
|
||||
an [implicit][] reference link followed by [another][]
|
||||
|
||||
[another]: http://cnn.com
|
||||
|
||||
an [explicit][example] reference link with a title
|
||||
|
||||
[example]: http://example.com "Example"
|
@ -1,4 +1,6 @@
|
||||
<blockquote>
|
||||
<p>quote
|
||||
the rest of it</p>
|
||||
<p>another paragraph
|
||||
the rest of it</p>
|
||||
</blockquote>
|
@ -1,2 +1,5 @@
|
||||
> quote
|
||||
the rest of it
|
||||
|
||||
> another paragraph
|
||||
the rest of it
|
@ -1,4 +0,0 @@
|
||||
<hr />
|
||||
<p>attributes:</p>
|
||||
<hr style="background: #9bd;" />
|
||||
<p>...</p>
|
@ -1,7 +0,0 @@
|
||||
<hr />
|
||||
|
||||
attributes:
|
||||
|
||||
<hr style="background: #9bd;" />
|
||||
|
||||
...
|
12
test/data/self-closing_html.html
Normal file
12
test/data/self-closing_html.html
Normal file
@ -0,0 +1,12 @@
|
||||
<hr>
|
||||
<p>paragraph</p>
|
||||
<hr/>
|
||||
<p>paragraph</p>
|
||||
<hr />
|
||||
<p>paragraph</p>
|
||||
<hr class="foo" id="bar" />
|
||||
<p>paragraph</p>
|
||||
<hr class="foo" id="bar"/>
|
||||
<p>paragraph</p>
|
||||
<hr class="foo" id="bar" >
|
||||
<p>paragraph</p>
|
12
test/data/self-closing_html.md
Normal file
12
test/data/self-closing_html.md
Normal file
@ -0,0 +1,12 @@
|
||||
<hr>
|
||||
paragraph
|
||||
<hr/>
|
||||
paragraph
|
||||
<hr />
|
||||
paragraph
|
||||
<hr class="foo" id="bar" />
|
||||
paragraph
|
||||
<hr class="foo" id="bar"/>
|
||||
paragraph
|
||||
<hr class="foo" id="bar" >
|
||||
paragraph
|
@ -1,4 +1,5 @@
|
||||
<p>an <b>important</b> <a href=''>link</a></p>
|
||||
<p>broken<br/>
|
||||
line</p>
|
||||
<p><b>inline tag</b> at the beginning</p>
|
||||
<p><b>inline tag</b> at the beginning</p>
|
||||
<p><span><a href="http://example.com">http://example.com</a></span></p>
|
@ -3,4 +3,6 @@ an <b>important</b> <a href=''>link</a>
|
||||
broken<br/>
|
||||
line
|
||||
|
||||
<b>inline tag</b> at the beginning
|
||||
<b>inline tag</b> at the beginning
|
||||
|
||||
<span>http://example.com</span>
|
8
test/data/sparse_html.html
Normal file
8
test/data/sparse_html.html
Normal file
@ -0,0 +1,8 @@
|
||||
<div>
|
||||
line 1
|
||||
|
||||
line 2
|
||||
line 3
|
||||
|
||||
line 4
|
||||
</div>
|
8
test/data/sparse_html.md
Normal file
8
test/data/sparse_html.md
Normal file
@ -0,0 +1,8 @@
|
||||
<div>
|
||||
line 1
|
||||
|
||||
line 2
|
||||
line 3
|
||||
|
||||
line 4
|
||||
</div>
|
Reference in New Issue
Block a user