|
<?php |
|
/** |
|
* Parse the text with *limited* markdown support. |
|
* |
|
* @param string $text |
|
* @return string |
|
*/ |
|
function markdown_limited($text) |
|
{ |
|
// Make it HTML safe for starters |
|
$text = htmlspecialchars($text, ENT_QUOTES, 'UTF-8'); |
|
|
|
// Replace for spaces with a tab (for lists and code blocks) |
|
$text = str_replace(" ", "\t", $text); |
|
|
|
// Blockquotes (they have email-styled > at the start) |
|
$regex = '^>.*?$(^(?:>).*?\n|\n)*'; |
|
preg_match_all("~$regex~m", $text, $matches, PREG_SET_ORDER); |
|
|
|
foreach($matches as $set) |
|
{ |
|
$block = "<blockquote>\n". trim(preg_replace('~(^|\n)[> ]+~', "\n", $set[0])) . "\n</blockquote>\n"; |
|
$text = str_replace($set[0], $block, $text); |
|
} |
|
|
|
// Titles |
|
$text = preg_replace_callback("~(^|\n)(#{1,6}) ([^\n#]+)[^\n]*~", function($match) |
|
{ |
|
$n = strlen($match[2]); |
|
return "\n<h$n>". $match[3]. "</h$n>"; |
|
}, $text); |
|
|
|
// Lists must start with a tab (four spaces are converted to tabs ^above^) |
|
$regex = '(?:^|\n)(?:\t+[\-\+\*0-9.][^\n]+\n+)+'; |
|
|
|
preg_match_all("~$regex~", $text, $matches, PREG_SET_ORDER); |
|
|
|
// Recursive closure |
|
$list = function($block, $top_level = false) use (&$list) |
|
{ |
|
if(is_array($block)) $block = $block[0]; |
|
|
|
// Chop one level of all the lines |
|
$block = preg_replace("~(^|\n)\t~", "\n", $block); |
|
|
|
// Is this an ordered or un-ordered list? |
|
$tag = ctype_digit(substr(ltrim($block), 0, 1)) ? 'ol' : 'ul'; |
|
|
|
// Only replace elements of THIS LEVEL with li |
|
$block = preg_replace('~(?:^|\n)[^\s]+ ([^\n]+)~', "\n<li>$1</li>", $block); |
|
|
|
if($top_level) $block .= "\n"; |
|
|
|
$block = "<$tag>$block</$tag>"; |
|
|
|
// Replace nested list items now |
|
$block = preg_replace_callback('~(\t[^\n]+\n?)+~', $list, $block); |
|
|
|
// return the finished list |
|
return $top_level ? "\n$block\n\n" : $block; |
|
}; |
|
|
|
foreach($matches as $set) |
|
{ |
|
$text = str_replace($set[0], $list(trim($set[0], "\n "), true), $text); |
|
} |
|
|
|
// Paragraphs |
|
$text = preg_replace('~\n([^><\t]+)\n~', "\n\n<p>$1</p>\n\n", $text); |
|
|
|
// Paragraphs (what about fixing the above?) |
|
$text = str_replace(array("<p>\n", "\n</p>"), array('<p>', '</p>'), $text); |
|
|
|
// Lines that end in two spaces require a BR |
|
$text = str_replace(" \n", "<br>\n", $text); |
|
|
|
// Bold, Italic, Code |
|
$regex = '([*_`])((?:(?!\1).)+)\1'; |
|
preg_match_all("~$regex~", $text, $matches, PREG_SET_ORDER); |
|
|
|
foreach($matches as $set) |
|
{ |
|
if($set[1] == '`') $tag = 'code'; |
|
elseif($set[1] == '*') $tag = 'b'; |
|
else $tag = 'em'; |
|
|
|
$text = str_replace($set[0], "<$tag>{$set[2]}</$tag>", $text); |
|
} |
|
|
|
// Links and Images |
|
$regex = '(!)*\[([^\]]+)\]\(([^\)]+?)(?: "([\w\s]+)")*\)'; |
|
preg_match_all("~$regex~", $text, $matches, PREG_SET_ORDER); |
|
|
|
foreach($matches as $set) |
|
{ |
|
$title = isset($set[4]) ? " title=\"{$set[4]}\"" : ''; |
|
if($set[1]) |
|
{ |
|
$text = str_replace($set[0], "<img src=\"{$set[3]}\"$title alt=\"{$set[2]}\"/>", $text); |
|
} |
|
else |
|
{ |
|
$text = str_replace($set[0], "<a href=\"{$set[3]}\"$title>{$set[2]}</a>", $text); |
|
} |
|
} |
|
|
|
// Preformated (often code) blocks |
|
$regex = '(?:(?:( |\t)[^\n]*\n)|\n)+'; |
|
preg_match_all("~$regex~", $text, $matches, PREG_SET_ORDER); |
|
|
|
foreach($matches as $set) |
|
{ |
|
if( ! trim($set[0])) continue; |
|
|
|
// If any tags were added (i.e. <p></p>), remove them! |
|
$lines = strip_tags($set[0]); |
|
|
|
// Remove the starting tab from each line |
|
$lines = trim(str_replace("\n\t", "\n", $lines), "\n"); |
|
|
|
// Mark strings |
|
$regex = '((')|("))(?:[^\\\\1]|\\\.)*?\1'; |
|
$lines = preg_replace("~$regex~", '<span class="string">$0</span>', $lines); |
|
|
|
// Mark comments |
|
$regex = '(/\*.*?\*/)|((#(?!\w+;)|(-- )|(//))[^\n]+)'; |
|
$lines = preg_replace("~$regex~s", '<span class="comment">$0</span>', $lines); |
|
|
|
$text = str_replace($set[0], "\n<pre>". $lines. "</pre>\n", $text); |
|
} |
|
|
|
// Reduce crazy newlines |
|
return preg_replace("~\n\n\n+~", "\n\n", $text); |
|
} |
Nice one. Thanks