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

Compare commits

...

49 Commits
1.4.2 ... 1.5.2

Author SHA1 Message Date
468d1e3da8 improve readme 2015-03-18 20:44:57 +02:00
7aa1d97bba improve readme 2015-03-18 20:43:30 +02:00
f768f9c63f improve readme 2015-03-18 20:42:44 +02:00
aa83968534 improve readme 2015-03-18 20:41:23 +02:00
85eadccc05 Merge pull request #297 from hkdobrev/patch-1
Remove "tested in PHP 5.2"
2015-03-18 20:39:40 +02:00
c94fa12d67 Remove "tested on PHP 5.2"
It is no longer tested on PHP 5.2 in Travis CI.

See https://github.com/erusev/parsedown/pull/286
2015-03-18 17:15:00 +02:00
11e02d45fa improve readme 2015-03-18 16:20:28 +02:00
ecd53f9add improve readme 2015-03-18 16:16:51 +02:00
844b2f49ea Merge pull request #249 from HelpingHand1/patch-1
Updated readme to display travis-ci.org build test
2015-03-18 16:08:13 +02:00
65116c3cb0 Merge pull request #286 from henriquemoody/travis
Remove PHP version 5.2 from Travis builds
2015-02-09 01:04:08 +02:00
147003107a Remove PHP version 5.2 from Travis builds 2015-02-08 21:00:50 -02:00
618b26056c Merge pull request #284 from jstanden/master
Fixes #283
2015-02-04 00:39:05 +02:00
b828fe7c8d Fixes #283 2015-02-03 13:58:47 -08:00
6c9df528aa Merge pull request #280 from kelunik/master
Fixes PHP 7 compatibility
2015-02-02 02:33:38 +02:00
cb8cc57742 Fixes #279 2015-02-02 00:58:24 +01:00
9da19c1108 version 1.5.1 2015-01-24 15:01:47 +02:00
ffd9d3b407 improve tests 2015-01-24 14:37:40 +02:00
e94ecf4adc resolve #277 2015-01-24 14:21:55 +02:00
4d3079b908 resolve #274 2015-01-24 14:03:05 +02:00
70e7a17380 update readme 2015-01-24 04:54:01 +02:00
9518c8e384 improve readme 2015-01-24 04:51:13 +02:00
c581284231 improve readme 2015-01-24 02:33:41 +02:00
cb1940255a improve readme 2015-01-24 01:31:49 +02:00
93d0ec9397 improve readme 2015-01-24 01:27:48 +02:00
9c6e7e880a improve readme 2015-01-24 01:26:59 +02:00
2d62e29625 improve readme 2015-01-24 01:21:16 +02:00
595f33871e improve readme 2015-01-24 01:18:49 +02:00
97e1e0efaa improve readme 2015-01-24 01:15:08 +02:00
648419467a clean up 2015-01-21 01:32:20 +02:00
6ddb6b2b33 resolve #90 2015-01-19 17:11:13 +02:00
0008e69a83 clean up 2015-01-19 17:09:51 +02:00
c664785485 inline methods should be able to handle unmarked inline elements 2015-01-19 17:05:10 +02:00
bdf0ef024e setter variables should not be private 2015-01-18 19:38:57 +02:00
21a3e8790a no need for a separate method for every special character 2015-01-16 03:57:47 +02:00
e5e8d02934 improve order of methods 2015-01-16 03:18:07 +02:00
7ff0f97811 improve performance 2015-01-16 02:59:51 +02:00
596350d1f5 improve names of elements 2015-01-16 02:49:55 +02:00
2cbd3010e4 url elements should not be restricted to http 2015-01-16 02:31:58 +02:00
3b4aa6bff7 change the parsing order of tag elements to improve performance 2015-01-16 01:46:43 +02:00
05a8f16e95 improve CommonMark compliance 2015-01-16 01:44:35 +02:00
79d924040a improve CommonMark compliance 2015-01-16 01:24:02 +02:00
b4a8eb3315 resolve #156 2015-01-16 00:04:18 +02:00
4383cce85b resolve #143 2015-01-15 22:31:31 +02:00
ada39109e4 resolve #189 2015-01-15 22:04:02 +02:00
a06cdfb814 improve fix for #184 2015-01-15 21:32:18 +02:00
6bee326c92 resolve #184 2015-01-15 21:10:09 +02:00
3fe867d294 update readme 2015-01-15 18:28:11 +02:00
4b7d7cdef2 updated readme.md per comment by cebe 2014-12-13 13:01:40 -05:00
97e667ab30 Updated readme to display travis-ci.org build test 2014-12-10 18:13:48 -05:00
15 changed files with 337 additions and 335 deletions

View File

@ -5,6 +5,4 @@ php:
- 5.5
- 5.4
- 5.3
- 5.2
- hhvm

View File

@ -15,15 +15,10 @@
class Parsedown
{
#
# Philosophy
# ~
# 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.
const version = '1.5.1';
#
# ~
function text($text)
@ -53,8 +48,6 @@ class Parsedown
# Setters
#
private $breaksEnabled;
function setBreaksEnabled($breaksEnabled)
{
$this->breaksEnabled = $breaksEnabled;
@ -62,7 +55,7 @@ class Parsedown
return $this;
}
private $markupEscaped;
protected $breaksEnabled;
function setMarkupEscaped($markupEscaped)
{
@ -71,7 +64,7 @@ class Parsedown
return $this;
}
private $urlsLinked = true;
protected $markupEscaped;
function setUrlsLinked($urlsLinked)
{
@ -80,6 +73,8 @@ class Parsedown
return $this;
}
protected $urlsLinked = true;
#
# Lines
#
@ -534,7 +529,7 @@ class Parsedown
protected function blockListContinue($Line, array $Block)
{
if ($Block['indent'] === $Line['indent'] and preg_match('/^'.$Block['pattern'].'[ ]+(.*)/', $Line['text'], $matches))
if ($Block['indent'] === $Line['indent'] and preg_match('/^'.$Block['pattern'].'(?:[ ]+(.*)|$)/', $Line['text'], $matches))
{
if (isset($Block['interrupted']))
{
@ -545,11 +540,13 @@ class Parsedown
unset($Block['li']);
$text = isset($matches[1]) ? $matches[1] : '';
$Block['li'] = array(
'name' => 'li',
'handler' => 'li',
'text' => array(
$matches[1],
$text,
),
);
@ -558,6 +555,11 @@ class Parsedown
return $Block;
}
if ($Line['text'][0] === '[' and $this->blockReference($Line))
{
return $Block;
}
if ( ! isset($Block['interrupted']))
{
$text = preg_replace('/^[ ]{0,4}/', '', $Line['body']);
@ -734,8 +736,6 @@ class Parsedown
{
$Block['closed'] = true;
}
$Block['markup'] .= $matches[1];
}
if (isset($Block['interrupted']))
@ -850,7 +850,7 @@ class Parsedown
$alignment = $alignments[$index];
$HeaderElement['attributes'] = array(
'align' => $alignment,
'style' => 'text-align: '.$alignment.';',
);
}
@ -905,9 +905,9 @@ class Parsedown
$row = trim($row);
$row = trim($row, '|');
$cells = explode('|', $row);
preg_match_all('/(?:(\\\\[|])|[^|`]|`[^`]+`|`)+/', $row, $matches);
foreach ($cells as $index => $cell)
foreach ($matches[0] as $index => $cell)
{
$cell = trim($cell);
@ -920,7 +920,7 @@ class Parsedown
if (isset($Block['alignments'][$index]))
{
$Element['attributes'] = array(
'align' => $Block['alignments'][$index],
'style' => 'text-align: '.$Block['alignments'][$index].';',
);
}
@ -956,75 +956,18 @@ class Parsedown
return $Block;
}
#
# ~
#
protected function element(array $Element)
{
$markup = '<'.$Element['name'];
if (isset($Element['attributes']))
{
foreach ($Element['attributes'] as $name => $value)
{
if ($value === null)
{
continue;
}
$markup .= ' '.$name.'="'.$value.'"';
}
}
if (isset($Element['text']))
{
$markup .= '>';
if (isset($Element['handler']))
{
$markup .= $this->$Element['handler']($Element['text']);
}
else
{
$markup .= $Element['text'];
}
$markup .= '</'.$Element['name'].'>';
}
else
{
$markup .= ' />';
}
return $markup;
}
protected function elements(array $Elements)
{
$markup = '';
foreach ($Elements as $Element)
{
$markup .= "\n" . $this->element($Element);
}
$markup .= "\n";
return $markup;
}
#
# Inline Elements
#
protected $InlineTypes = array(
'"' => array('QuotationMark'),
'"' => array('SpecialCharacter'),
'!' => array('Image'),
'&' => array('Ampersand'),
'&' => array('SpecialCharacter'),
'*' => array('Emphasis'),
'<' => array('UrlTag', 'EmailTag', 'Tag', 'LessThan'),
'>' => array('GreaterThan'),
':' => array('Url'),
'<' => array('UrlTag', 'EmailTag', 'Markup', 'SpecialCharacter'),
'>' => array('SpecialCharacter'),
'[' => array('Link'),
'_' => array('Emphasis'),
'`' => array('Code'),
@ -1034,7 +977,7 @@ class Parsedown
# ~
protected $inlineMarkerList = '!"*_&[<>`~\\';
protected $inlineMarkerList = '!"*_&[:<>`~\\';
#
# ~
@ -1044,43 +987,53 @@ class Parsedown
{
$markup = '';
$remainder = $text;
$unexaminedText = $text;
$markerPosition = 0;
while ($excerpt = strpbrk($remainder, $this->inlineMarkerList))
while ($excerpt = strpbrk($unexaminedText, $this->inlineMarkerList))
{
$marker = $excerpt[0];
$markerPosition += strpos($remainder, $marker);
$markerPosition += strpos($unexaminedText, $marker);
$Excerpt = array('text' => $excerpt, 'context' => $text);
foreach ($this->InlineTypes[$marker] as $inlineType)
{
$handler = 'inline'.$inlineType;
$Inline = $this->$handler($excerpt);
$Inline = $this->{'inline'.$inlineType}($Excerpt);
if ( ! isset($Inline))
{
continue;
}
$plainText = substr($text, 0, $markerPosition);
if (isset($Inline['position']) and $Inline['position'] > $markerPosition) # position is ahead of marker
{
continue;
}
$markup .= $this->unmarkedText($plainText);
if ( ! isset($Inline['position']))
{
$Inline['position'] = $markerPosition;
}
$unmarkedText = substr($text, 0, $Inline['position']);
$markup .= $this->unmarkedText($unmarkedText);
$markup .= isset($Inline['markup']) ? $Inline['markup'] : $this->element($Inline['element']);
$text = substr($text, $markerPosition + $Inline['extent']);
$text = substr($text, $Inline['position'] + $Inline['extent']);
$remainder = $text;
$unexaminedText = $text;
$markerPosition = 0;
continue 2;
}
$remainder = substr($excerpt, 1);
$unexaminedText = substr($excerpt, 1);
$markerPosition ++;
}
@ -1094,94 +1047,29 @@ class Parsedown
# ~
#
protected function inlineAmpersand($excerpt)
protected function inlineCode($Excerpt)
{
if ( ! preg_match('/^&#?\w+;/', $excerpt))
{
return array(
'markup' => '&amp;',
'extent' => 1,
);
}
}
$marker = $Excerpt['text'][0];
protected function inlineStrikethrough($excerpt)
{
if ( ! isset($excerpt[1]))
if (preg_match('/^('.$marker.'+)[ ]*(.+?)[ ]*(?<!'.$marker.')\1(?!'.$marker.')/s', $Excerpt['text'], $matches))
{
return;
}
$text = $matches[2];
$text = htmlspecialchars($text, ENT_NOQUOTES, 'UTF-8');
$text = preg_replace("/[ ]*\n/", ' ', $text);
if ($excerpt[1] === '~' and preg_match('/^~~(?=\S)(.+?)(?<=\S)~~/', $excerpt, $matches))
{
return array(
'extent' => strlen($matches[0]),
'element' => array(
'name' => 'del',
'text' => $matches[1],
'handler' => 'line',
'name' => 'code',
'text' => $text,
),
);
}
}
protected function inlineEscapeSequence($excerpt)
protected function inlineEmailTag($Excerpt)
{
if (isset($excerpt[1]) and in_array($excerpt[1], $this->specialCharacters))
{
return array(
'markup' => $excerpt[1],
'extent' => 2,
);
}
}
protected function inlineLessThan()
{
return array(
'markup' => '&lt;',
'extent' => 1,
);
}
protected function inlineGreaterThan()
{
return array(
'markup' => '&gt;',
'extent' => 1,
);
}
protected function inlineQuotationMark()
{
return array(
'markup' => '&quot;',
'extent' => 1,
);
}
protected function inlineUrlTag($excerpt)
{
if (strpos($excerpt, '>') !== false and preg_match('/^<(https?:[\/]{2}[^\s]+?)>/i', $excerpt, $matches))
{
$url = str_replace(array('&', '<'), array('&amp;', '&lt;'), $matches[1]);
return array(
'extent' => strlen($matches[0]),
'element' => array(
'name' => 'a',
'text' => $url,
'attributes' => array(
'href' => $url,
),
),
);
}
}
protected function inlineEmailTag($excerpt)
{
if (strpos($excerpt, '>') !== false and preg_match('/^<((mailto:)?\S+?@\S+?)>/i', $excerpt, $matches))
if (strpos($Excerpt['text'], '>') !== false and preg_match('/^<((mailto:)?\S+?@\S+?)>/i', $Excerpt['text'], $matches))
{
$url = $matches[1];
@ -1203,77 +1091,84 @@ class Parsedown
}
}
protected function inlineTag($excerpt)
protected function inlineEmphasis($Excerpt)
{
if ($this->markupEscaped)
if ( ! isset($Excerpt['text'][1]))
{
return;
}
if (strpos($excerpt, '>') !== false and preg_match('/^<\/?\w.*?>/s', $excerpt, $matches))
$marker = $Excerpt['text'][0];
if ($Excerpt['text'][1] === $marker and preg_match($this->StrongRegex[$marker], $Excerpt['text'], $matches))
{
return array(
'markup' => $matches[0],
'extent' => strlen($matches[0]),
);
$emphasis = 'strong';
}
}
protected function inlineCode($excerpt)
{
$marker = $excerpt[0];
if (preg_match('/^('.$marker.'+)[ ]*(.+?)[ ]*(?<!'.$marker.')\1(?!'.$marker.')/s', $excerpt, $matches))
elseif (preg_match($this->EmRegex[$marker], $Excerpt['text'], $matches))
{
$text = $matches[2];
$text = htmlspecialchars($text, ENT_NOQUOTES, 'UTF-8');
$text = preg_replace("/[ ]*\n/", ' ', $text);
return array(
'extent' => strlen($matches[0]),
'element' => array(
'name' => 'code',
'text' => $text,
),
);
$emphasis = 'em';
}
}
protected function inlineImage($excerpt)
{
if ( ! isset($excerpt[1]) or $excerpt[1] !== '[')
else
{
return;
}
$excerpt = substr($excerpt, 1);
return array(
'extent' => strlen($matches[0]),
'element' => array(
'name' => $emphasis,
'handler' => 'line',
'text' => $matches[1],
),
);
}
$InlineLink = $this->inlineLink($excerpt);
protected function inlineEscapeSequence($Excerpt)
{
if (isset($Excerpt['text'][1]) and in_array($Excerpt['text'][1], $this->specialCharacters))
{
return array(
'markup' => $Excerpt['text'][1],
'extent' => 2,
);
}
}
if ($InlineLink === null)
protected function inlineImage($Excerpt)
{
if ( ! isset($Excerpt['text'][1]) or $Excerpt['text'][1] !== '[')
{
return;
}
$Excerpt['text']= substr($Excerpt['text'], 1);
$Link = $this->inlineLink($Excerpt);
if ($Link === null)
{
return;
}
$Inline = array(
'extent' => $InlineLink['extent'] + 1,
'extent' => $Link['extent'] + 1,
'element' => array(
'name' => 'img',
'attributes' => array(
'src' => $InlineLink['element']['attributes']['href'],
'alt' => $InlineLink['element']['text'],
'src' => $Link['element']['attributes']['href'],
'alt' => $Link['element']['text'],
),
),
);
$Inline['element']['attributes'] += $InlineLink['element']['attributes'];
$Inline['element']['attributes'] += $Link['element']['attributes'];
unset($Inline['element']['attributes']['href']);
return $Inline;
}
protected function inlineLink($excerpt)
protected function inlineLink($Excerpt)
{
$Element = array(
'name' => 'a',
@ -1287,7 +1182,7 @@ class Parsedown
$extent = 0;
$remainder = $excerpt;
$remainder = $Excerpt['text'];
if (preg_match('/\[((?:[^][]|(?R))*)\]/', $remainder, $matches))
{
@ -1302,7 +1197,7 @@ class Parsedown
return;
}
if (preg_match('/^[(]((?:[^ (]|[(][^ )]+[)])+)(?:[ ]+("[^"]+"|\'[^\']+\'))?[)]/', $remainder, $matches))
if (preg_match('/^[(]((?:[^ ()]|[(][^ )]+[)])+)(?:[ ]+("[^"]*"|\'[^\']*\'))?[)]/', $remainder, $matches))
{
$Element['attributes']['href'] = $matches[1];
@ -1346,59 +1241,126 @@ class Parsedown
);
}
protected function inlineEmphasis($excerpt)
protected function inlineMarkup($Excerpt)
{
if ( ! isset($excerpt[1]))
if ($this->markupEscaped or strpos($Excerpt['text'], '>') === false)
{
return;
}
$marker = $excerpt[0];
if ($excerpt[1] === $marker and preg_match($this->StrongRegex[$marker], $excerpt, $matches))
if ($Excerpt['text'][1] === '/' and preg_match('/^<\/\w*[ ]*>/s', $Excerpt['text'], $matches))
{
$emphasis = 'strong';
}
elseif (preg_match($this->EmRegex[$marker], $excerpt, $matches))
{
$emphasis = 'em';
}
else
{
return;
return array(
'markup' => $matches[0],
'extent' => strlen($matches[0]),
);
}
return array(
'extent' => strlen($matches[0]),
'element' => array(
'name' => $emphasis,
'handler' => 'line',
'text' => $matches[1],
),
);
if ($Excerpt['text'][1] === '!' and preg_match('/^<!---?[^>-](?:-?[^-])*-->/s', $Excerpt['text'], $matches))
{
return array(
'markup' => $matches[0],
'extent' => strlen($matches[0]),
);
}
if ($Excerpt['text'][1] !== ' ' and preg_match('/^<\w*(?:[ ]*'.$this->regexHtmlAttribute.')*[ ]*\/?>/s', $Excerpt['text'], $matches))
{
return array(
'markup' => $matches[0],
'extent' => strlen($matches[0]),
);
}
}
#
# ~
protected function inlineSpecialCharacter($Excerpt)
{
if ($Excerpt['text'][0] === '&' and ! preg_match('/^&#?\w+;/', $Excerpt['text']))
{
return array(
'markup' => '&amp;',
'extent' => 1,
);
}
protected $unmarkedInlineTypes = array("\n" => 'Break', '://' => 'Url');
$SpecialCharacter = array('>' => 'gt', '<' => 'lt', '"' => 'quot');
if (isset($SpecialCharacter[$Excerpt['text'][0]]))
{
return array(
'markup' => '&'.$SpecialCharacter[$Excerpt['text'][0]].';',
'extent' => 1,
);
}
}
protected function inlineStrikethrough($Excerpt)
{
if ( ! isset($Excerpt['text'][1]))
{
return;
}
if ($Excerpt['text'][1] === '~' and preg_match('/^~~(?=\S)(.+?)(?<=\S)~~/', $Excerpt['text'], $matches))
{
return array(
'extent' => strlen($matches[0]),
'element' => array(
'name' => 'del',
'text' => $matches[1],
'handler' => 'line',
),
);
}
}
protected function inlineUrl($Excerpt)
{
if ($this->urlsLinked !== true or ! isset($Excerpt['text'][2]) or $Excerpt['text'][2] !== '/')
{
return;
}
if (preg_match('/\bhttps?:[\/]{2}[^\s<]+\b\/*/ui', $Excerpt['context'], $matches, PREG_OFFSET_CAPTURE))
{
$Inline = array(
'extent' => strlen($matches[0][0]),
'position' => $matches[0][1],
'element' => array(
'name' => 'a',
'text' => $matches[0][0],
'attributes' => array(
'href' => $matches[0][0],
),
),
);
return $Inline;
}
}
protected function inlineUrlTag($Excerpt)
{
if (strpos($Excerpt['text'], '>') !== false and preg_match('/^<(\w+:\/{2}[^ >]+)>/i', $Excerpt['text'], $matches))
{
$url = str_replace(array('&', '<'), array('&amp;', '&lt;'), $matches[1]);
return array(
'extent' => strlen($matches[0]),
'element' => array(
'name' => 'a',
'text' => $url,
'attributes' => array(
'href' => $url,
),
),
);
}
}
# ~
protected function unmarkedText($text)
{
foreach ($this->unmarkedInlineTypes as $snippet => $inlineType)
{
if (strpos($text, $snippet) !== false)
{
$text = $this->{'unmarkedInline'.$inlineType}($text);
}
}
return $text;
}
protected function unmarkedInlineBreak($text)
{
if ($this->breaksEnabled)
{
@ -1413,38 +1375,65 @@ class Parsedown
return $text;
}
protected function unmarkedInlineUrl($text)
#
# Handlers
#
protected function element(array $Element)
{
if ($this->urlsLinked !== true)
$markup = '<'.$Element['name'];
if (isset($Element['attributes']))
{
return $text;
foreach ($Element['attributes'] as $name => $value)
{
if ($value === null)
{
continue;
}
$markup .= ' '.$name.'="'.$value.'"';
}
}
$re = '/\bhttps?:[\/]{2}[^\s<]+\b\/*/ui';
$offset = 0;
while (strpos($text, '://', $offset) and preg_match($re, $text, $matches, PREG_OFFSET_CAPTURE, $offset))
if (isset($Element['text']))
{
$url = $matches[0][0];
$markup .= '>';
$urlLength = strlen($url);
$urlPosition = $matches[0][1];
if (isset($Element['handler']))
{
$markup .= $this->{$Element['handler']}($Element['text']);
}
else
{
$markup .= $Element['text'];
}
$markup = '<a href="'.$url.'">'.$url.'</a>';
$markupLength = strlen($markup);
$text = substr_replace($text, $markup, $urlPosition, $urlLength);
$offset = $urlPosition + $markupLength;
$markup .= '</'.$Element['name'].'>';
}
else
{
$markup .= ' />';
}
return $text;
return $markup;
}
protected function elements(array $Elements)
{
$markup = '';
foreach ($Elements as $Element)
{
$markup .= "\n" . $this->element($Element);
}
$markup .= "\n";
return $markup;
}
#
# ~
#
protected function li($lines)
{
@ -1466,7 +1455,18 @@ class Parsedown
}
#
# Multiton
# Deprecated Methods
#
function parse($text)
{
$markup = $this->text($text);
return $markup;
}
#
# Static Methods
#
static function instance($name = 'default')
@ -1485,22 +1485,6 @@ class Parsedown
private static $instances = array();
#
# Deprecated Methods
#
/**
* @deprecated in favor of "text"
* @param $text
* @return string
*/
function parse($text)
{
$markup = $this->text($text);
return $markup;
}
#
# Fields
#
@ -1508,10 +1492,10 @@ class Parsedown
protected $DefinitionData;
#
# Read-only
# Read-Only
protected $specialCharacters = array(
'\\', '`', '*', '_', '{', '}', '[', ']', '(', ')', '>', '#', '+', '-', '.', '!',
'\\', '`', '*', '_', '{', '}', '[', ']', '(', ')', '>', '#', '+', '-', '.', '!', '|',
);
protected $StrongRegex = array(

View File

@ -1,18 +1,20 @@
## Parsedown
[![Build Status](https://img.shields.io/travis/erusev/parsedown/master.svg?style=flat-square)](https://travis-ci.org/erusev/parsedown)
<!--[![Total Downloads](http://img.shields.io/packagist/dt/erusev/parsedown.svg?style=flat-square)](https://packagist.org/packages/erusev/parsedown)-->
Better Markdown Parser in PHP
[[ demo ]](http://parsedown.org/demo)
[See 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](http://parsedown.org/tests/) in PHP 5.2, 5.3, 5.4, 5.5, 5.6 and [hhvm](http://www.hhvm.com/)
* Extensible
* [Tested](http://parsedown.org/tests/) in PHP 5.3, 5.4, 5.5, 5.6 and [HHVM](http://www.hhvm.com/)
* [Extensible](https://github.com/erusev/parsedown/wiki/Writing-Extensions)
* [Markdown Extra extension](https://github.com/erusev/parsedown-extra)
* [JavaScript port](https://github.com/hkdobrev/parsedown.js) under development
### Installation
@ -36,14 +38,14 @@ It tries to read Markdown like a human. First, it looks at the lines. Its int
We call this approach "line based". We believe that Parsedown is the first Markdown parser to use it. Since the release of Parsedown, other developers have used the same approach to develop other Markdown parsers in PHP and in other languages.
**Is Parsedown compliant with CommonMark?**
**Is it compliant with CommonMark?**
The majority of the CommonMark tests pass. Most of the tests that don't pass deal with cases that are quite extreme. Yet, we are working on them. As CommonMark matures, compliance should improve.
It passes most of the CommonMark tests. Most of the tests that don't pass deal with cases that are quite uncommon. Still, as CommonMark matures, compliance should improve.
**Who uses Parsedown?**
**Who uses it?**
[phpDocumentor](http://www.phpdoc.org/), [October CMS](http://octobercms.com/), [Bolt CMS](http://bolt.cm/), [Kirby CMS](http://getkirby.com/), [Grav CMS](http://getgrav.org/), [Statamic CMS](http://www.statamic.com/), [RaspberryPi.org](http://www.raspberrypi.org/) and [more](https://www.versioneye.com/php/erusev:parsedown/references).
**How can I help?**
Use the project, tell friends about it and if you feel generous, [donate some money](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=528P3NZQMP8N2).
Use it, star it, share it and if you feel generous, [donate some money](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=528P3NZQMP8N2).

View File

@ -1,21 +1,21 @@
<table>
<thead>
<tr>
<th align="left">header 1</th>
<th align="center">header 2</th>
<th align="right">header 2</th>
<th style="text-align: left;">header 1</th>
<th style="text-align: center;">header 2</th>
<th style="text-align: right;">header 2</th>
</tr>
</thead>
<tbody>
<tr>
<td align="left">cell 1.1</td>
<td align="center">cell 1.2</td>
<td align="right">cell 1.3</td>
<td style="text-align: left;">cell 1.1</td>
<td style="text-align: center;">cell 1.2</td>
<td style="text-align: right;">cell 1.3</td>
</tr>
<tr>
<td align="left">cell 2.1</td>
<td align="center">cell 2.2</td>
<td align="right">cell 2.3</td>
<td style="text-align: left;">cell 2.1</td>
<td style="text-align: center;">cell 2.2</td>
<td style="text-align: right;">cell 2.3</td>
</tr>
</tbody>
</table>

View File

@ -1,13 +1,12 @@
<div>_content_</div>
<p>sparse:</p>
<div>
<div class="inner">
_content_
</div>
</div>
<p>paragraph</p>
<div>
<div class="inner">
_content_
</div>
</div>
<style type="text/css">
p {
color: red;
}
</style>
p {color: #789;}
</style>
<div>
<a href="/">home</a></div>

View File

@ -1,17 +1,16 @@
<div>_content_</div>
sparse:
<div>
<div class="inner">
_content_
</div>
</div>
paragraph
<div>
<div class="inner">
_content_
</div>
</div>
<style type="text/css">
p {
color: red;
}
p {color: #789;}
</style>
<div>
<a href="/">home</a></div>

View File

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

View File

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

View File

@ -1,4 +1,6 @@
<p><a href="http://example.com">link</a> and <a href="/url-with-(parentheses)">another link</a></p>
<p><a href="http://example.com">link</a></p>
<p><a href="/url-(parentheses)">link</a> with parentheses in URL </p>
<p>(<a href="/index.php">link</a>) in parentheses</p>
<p><a href="http://example.com"><code>link</code></a></p>
<p><a href="http://example.com"><img src="http://parsedown.org/md.png" alt="MD Logo" /></a></p>
<p><a href="http://example.com"><img src="http://parsedown.org/md.png" alt="MD Logo" /> and text</a></p>

View File

@ -1,4 +1,8 @@
[link](http://example.com) and [another link](/url-with-(parentheses))
[link](http://example.com)
[link](/url-(parentheses)) with parentheses in URL
([link](/index.php)) in parentheses
[`link`](http://example.com)

View File

@ -1,4 +1,6 @@
<p><a href="http://example.com" title="Title">single quotes</a></p>
<p><a href="http://example.com" title="Title">double quotes</a></p>
<p><a href="http://example.com" title="">single quotes blank</a></p>
<p><a href="http://example.com" title="">double quotes blank</a></p>
<p><a href="http://example.com" title="2 Words">space</a></p>
<p><a href="http://example.com/url-(parentheses)" title="Title">parentheses</a></p>

View File

@ -2,6 +2,10 @@
[double quotes](http://example.com "Title")
[single quotes blank](http://example.com '')
[double quotes blank](http://example.com "")
[space](http://example.com "2 Words")
[parentheses](http://example.com/url-(parentheses) "Title")

View File

@ -20,17 +20,17 @@
<table>
<thead>
<tr>
<th align="left">header 1</th>
<th style="text-align: left;">header 1</th>
<th>header 2</th>
</tr>
</thead>
<tbody>
<tr>
<td align="left">cell 1.1</td>
<td style="text-align: left;">cell 1.1</td>
<td>cell 1.2</td>
</tr>
<tr>
<td align="left">cell 2.1</td>
<td style="text-align: left;">cell 2.1</td>
<td>cell 2.2</td>
</tr>
</tbody>

View File

@ -11,8 +11,12 @@
<td><del>cell</del> 1.2</td>
</tr>
<tr>
<td><code>cell</code> 2.1</td>
<td>cell 2.2</td>
<td><code>|</code> 2.1</td>
<td>| 2.2</td>
</tr>
<tr>
<td><code>\|</code> 2.1</td>
<td><a href="/">link</a></td>
</tr>
</tbody>
</table>

View File

@ -1,4 +1,5 @@
| _header_ 1 | header 2 |
| ------------ | ------------ |
| _cell_ 1.1 | ~~cell~~ 1.2 |
| `cell` 2.1 | cell 2.2 |
| `|` 2.1 | \| 2.2 |
| `\|` 2.1 | [link](/) |