Merge branch 'master' into better-extendability

* master:
  simplify em/strong routine
  outdented is shorter and probably more accurate
  improve contributing guidelines
  improve consistency of list item
  add contributing guidelines
  dense list items that follow sparse ones should not be rendered as sparse ones
  improve parsing of list item and code block by measuring line indentation
  Remove one unnecessary /u flag.
  Remove /u flag from '*' chars. Add /u to urls.
  some edge case tests for the code tag
  Add unicode support for strong/em regex.
This commit is contained in:
Carsten Brandt 2014-02-03 15:06:48 +01:00
commit 6ff1ccf561
8 changed files with 134 additions and 97 deletions

19
CONTRIBUTING.md Normal file
View File

@ -0,0 +1,19 @@
Pull Requests
-------------
Do create pull requests that:
* resolve an issue
* improve an existing feature or text
Do not create pull requests that:
* introduce a feature or text
* change the currently used coding style
If a pull request contains unrelated updates, they should be submitted as separate pull requests.
License
-------
By contributing to the project, you grant 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

@ -250,11 +250,18 @@ class Parsedown
# ~
$deindented_line = ltrim($line);
$indentation = 0;
while(isset($line[$indentation]) and $line[$indentation] === ' ')
{
$indentation++;
}
$outdented_line = $indentation > 0 ? ltrim($line) : $line;
# blank
if ($deindented_line === '')
if ($outdented_line === '')
{
$block['interrupted'] = true;
@ -280,53 +287,41 @@ class Parsedown
case 'li':
if (preg_match('/^([ ]{0,3})(\d+[.]|[*+-])[ ](.*)/', $line, $matches))
{
if ($block['indentation'] !== $matches[1])
{
$block['lines'] []= $line;
}
else
if ($block['indentation'] === $indentation and preg_match('/^'.$block['marker'].'[ ]+(.*)/', $outdented_line, $matches))
{
unset($block['last']);
$blocks []= $block;
unset($block['first']);
$block['last'] = true;
$block['lines'] = array($matches[1]);
$block['lines'] = array(
preg_replace('/^[ ]{0,4}/', '', $matches[3]),
);
}
continue 2;
}
if (isset($block['interrupted']))
{
if ($line[0] === ' ')
{
$block['lines'] []= '';
$line = preg_replace('/^[ ]{0,4}/', '', $line);
$block['lines'] []= $line;
unset($block['first']);
unset($block['interrupted']);
continue 2;
}
}
else
if ( ! isset($block['interrupted']))
{
$line = preg_replace('/^[ ]{0,4}/', '', $line);
$line = preg_replace('/^[ ]{0,'.$block['baseline'].'}/', '', $line);
$block['lines'] []= $line;
continue 2;
}
elseif ($line[0] === ' ')
{
$block['lines'] []= '';
$line = preg_replace('/^[ ]{0,'.$block['baseline'].'}/', '', $line);
$block['lines'] []= $line;
unset($block['interrupted']);
continue 2;
}
break;
}
@ -339,7 +334,7 @@ class Parsedown
# code
if (isset($line[3]) and $line[3] === ' ' and $line[2] === ' ' and $line[1] === ' ')
if ($indentation >= 4)
{
$code_line = substr($line, 4);
@ -428,15 +423,15 @@ class Parsedown
# indentation insensitive types
switch ($deindented_line[0])
switch ($outdented_line[0])
{
case '<':
$position = strpos($deindented_line, '>');
$position = strpos($outdented_line, '>');
if ($position > 1)
{
$substring = substr($deindented_line, 1, $position - 1);
$substring = substr($outdented_line, 1, $position - 1);
$substring = chop($substring);
@ -474,7 +469,7 @@ class Parsedown
{
$block = array(
'type' => 'self-closing tag',
'text' => $deindented_line,
'text' => $outdented_line,
);
unset($is_self_closing);
@ -484,13 +479,13 @@ class Parsedown
$block = array(
'type' => 'markup',
'text' => $deindented_line,
'text' => $outdented_line,
'start' => '<'.$name.'>',
'end' => '</'.$name.'>',
'depth' => 0,
);
if (strpos($deindented_line, $block['end']))
if (strpos($outdented_line, $block['end']))
{
$block['closed'] = true;
}
@ -504,7 +499,7 @@ class Parsedown
# quote
if (preg_match('/^>[ ]?(.*)/', $deindented_line, $matches))
if (preg_match('/^>[ ]?(.*)/', $outdented_line, $matches))
{
$blocks []= $block;
@ -524,7 +519,7 @@ class Parsedown
# reference
if (preg_match('/^\[(.+?)\]:[ ]*(.+?)(?:[ ]+[\'"](.+?)[\'"])?[ ]*$/', $deindented_line, $matches))
if (preg_match('/^\[(.+?)\]:[ ]*(.+?)(?:[ ]+[\'"](.+?)[\'"])?[ ]*$/', $outdented_line, $matches))
{
$label = strtolower($matches[1]);
@ -547,7 +542,7 @@ class Parsedown
# fenced code block
if (preg_match('/^([`]{3,}|[~]{3,})[ ]*(\S+)?[ ]*$/', $deindented_line, $matches))
if (preg_match('/^([`]{3,}|[~]{3,})[ ]*(\S+)?[ ]*$/', $outdented_line, $matches))
{
$blocks []= $block;
@ -574,7 +569,7 @@ class Parsedown
# hr
if (preg_match('/^([-*_])([ ]{0,2}\1){2,}[ ]*$/', $deindented_line))
if (preg_match('/^([-*_])([ ]{0,2}\1){2,}[ ]*$/', $outdented_line))
{
$blocks []= $block;
@ -587,42 +582,49 @@ class Parsedown
# li
if (preg_match('/^([ ]*)[*+-][ ](.*)/', $line, $matches))
if (preg_match('/^([*+-][ ]+)(.*)/', $outdented_line, $matches))
{
$blocks []= $block;
$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;
}
}
# list item
# li
if ($deindented_line[0] <= '9' and $deindented_line[0] >= '0' and preg_match('/^([ ]*)\d+[.][ ](.*)/', $line, $matches))
if ($outdented_line[0] <= '9' and preg_match('/^(\d+[.][ ]+)(.*)/', $outdented_line, $matches))
{
$blocks []= $block;
$baseline = $indentation + strlen($matches[1]);
$block = array(
'type' => 'li',
'ordered' => true,
'indentation' => $matches[1],
'indentation' => $indentation,
'baseline' => $baseline,
'marker' => '\d+[.]',
'first' => true,
'last' => true,
'lines' => array(
preg_replace('/^[ ]{0,4}/', '', $matches[2]),
),
'ordered' => true,
'lines' => array(),
);
$block['lines'] []= preg_replace('/^[ ]{0,4}/', '', $matches[2]);
continue;
}
@ -753,7 +755,7 @@ class Parsedown
if (isset($block['first']))
{
$type = $block['ordered'] ? 'ol' : 'ul';
$type = isset($block['ordered']) ? 'ol' : 'ul';
$markup .= '<'.$type.'>'."\n";
}
@ -769,7 +771,7 @@ class Parsedown
if (isset($block['last']))
{
$type = $block['ordered'] ? 'ol' : 'ul';
$type = isset($block['ordered']) ? 'ol' : 'ul';
$markup .= '</'.$type.'>'."\n";
}
@ -990,34 +992,18 @@ class Parsedown
if ($text[1] === $closest_marker and preg_match(self::$strong_regex[$closest_marker], $text, $matches))
{
$markers[] = $closest_marker;
$matches[1] = $this->parse_span_elements($matches[1], $markers);
$markup .= '<strong>'.$matches[1].'</strong>';
}
elseif (preg_match(self::$em_regex[$closest_marker], $text, $matches))
{
$markers[] = $closest_marker;
$matches[1] = $this->parse_span_elements($matches[1], $markers);
$markup .= '<em>'.$matches[1].'</em>';
}
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);
$matches[1] and $matches[1] = $this->parse_span_elements($matches[1], $markers);
$matches[3] and $matches[3] = $this->parse_span_elements($matches[3], $markers);
$markup .= '<strong>'.$matches[1].'<em>'.$matches[2].'</em>'.$matches[3].'</strong>';
}
elseif (preg_match(self::$em_strong_regex[$closest_marker], $text, $matches))
{
$matches[2] = $this->parse_span_elements($matches[2], $markers);
$matches[1] and $matches[1] = $this->parse_span_elements($matches[1], $markers);
$matches[3] and $matches[3] = $this->parse_span_elements($matches[3], $markers);
$markup .= '<em>'.$matches[1].'<strong>'.$matches[2].'</strong>'.$matches[3].'</em>';
}
if (isset($matches) and $matches)
{
@ -1113,7 +1099,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);
@ -1179,23 +1165,13 @@ class Parsedown
# Read-only
private static $strong_regex = array(
'*' => '/^[*]{2}([^*]+?)[*]{2}(?![*])/s',
'_' => '/^__([^_]+?)__(?!_)/s',
'*' => '/^[*]{2}((?:[^*]|[*][^*]*[*])+?)[*]{2}(?![*])/s',
'_' => '/^__((?:[^_]|_[^_]*_)+?)__(?!_)/us',
);
private static $em_regex = array(
'*' => '/^[*]([^*]+?)[*](?![*])/s',
'_' => '/^_([^_]+?)[_](?![_])\b/s',
);
private static $strong_em_regex = array(
'*' => '/^[*]{2}(.*?)[*](.+?)[*](.*?)[*]{2}/s',
'_' => '/^__(.*?)_(.+?)_(.*?)__/s',
);
private static $em_strong_regex = array(
'*' => '/^[*](.*?)[*]{2}(.+?)[*]{2}(.*?)[*]/s',
'_' => '/^_(.*?)__(.+?)__(.*?)_/s',
'*' => '/^[*]((?:[^*]|[*][*][^*]+?[*][*])+?)[*](?![*])/s',
'_' => '/^_((?:[^_]|__[^_]*__)+?)_(?!_)\b/us',
);
private static $special_characters = array(

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

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