Skip to content

Instantly share code, notes, and snippets.

@timothyqiu
Last active March 12, 2020 06:55
Show Gist options
  • Save timothyqiu/d1dfffd54e1ed02854cf9e67f0b01993 to your computer and use it in GitHub Desktop.
Save timothyqiu/d1dfffd54e1ed02854cf9e67f0b01993 to your computer and use it in GitHub Desktop.
Math support patch for PHP Markdown Extra 1.2.8
--- markdown.php 2013-11-30 00:09:34.000000000 +0800
+++ markdown.php 2020-03-12 14:54:15.000000000 +0800
@@ -41,6 +41,9 @@
# setting this to true will put attributes on the `pre` tag instead.
@define( 'MARKDOWN_CODE_ATTR_ON_PRE', false );
+# Optional class attribute for math.
+@define( 'MARKDOWN_MATH_CLASS', "" );
+
#
# WordPress settings:
@@ -1146,6 +1149,20 @@
}
+ function makeMathSpan($code) {
+ #
+ # Create a math span markup for $code. Called from handleSpanToken.
+ #
+ $code = htmlspecialchars(trim($code), ENT_NOQUOTES);
+ if ($this->math_class) {
+ $attr = " class=\"$this->math_class\"";
+ } else {
+ $attr = "";
+ }
+ return $this->hashPart("<span$attr>$$code$</span>");
+ }
+
+
function makeCodeSpan($code) {
#
# Create a code span markup for $code. Called from handleSpanToken.
@@ -1555,6 +1572,9 @@
|
(?<![`\\\\])
`+ # code span marker
+ |
+ (?<![$\\\\])
+ \$+ # math span marker
'.( $this->no_markup ? '' : '
|
<!-- .*? --> # comment
@@ -1610,6 +1630,16 @@
switch ($token{0}) {
case "\\":
return $this->hashPart("&#". ord($token{1}). ";");
+ case "$":
+ # Search for end marker in remaining text.
+ if (preg_match('/^(.*?[^$])'.preg_quote($token).'(?!\$)(.*)$/sm',
+ $str, $matches))
+ {
+ $str = $matches[2];
+ $codespan = $this->makeMathSpan($matches[1]);
+ return $this->hashPart($codespan);
+ }
+ return $token; // return as text since no ending marker found.
case "`":
# Search for end marker in remaining text.
if (preg_match('/^(.*?[^`])'.preg_quote($token).'(?!`)(.*)$/sm',
@@ -1715,6 +1745,9 @@
var $fn_link_class = MARKDOWN_FN_LINK_CLASS;
var $fn_backlink_class = MARKDOWN_FN_BACKLINK_CLASS;
+ # Optional class attribute for math.
+ var $math_class = MARKDOWN_MATH_CLASS;
+
# Optional class prefix for fenced code block.
var $code_class_prefix = MARKDOWN_CODE_CLASS_PREFIX;
# Class attribute for code blocks goes on the `code` tag;
@@ -1739,12 +1772,14 @@
# Parent constructor will do the sorting.
$this->document_gamut += array(
"doFencedCodeBlocks" => 5,
+ "doFencedMathBlocks" => 10,
"stripFootnotes" => 15,
"stripAbbreviations" => 25,
"appendFootnotes" => 50,
);
$this->block_gamut += array(
"doFencedCodeBlocks" => 5,
+ "doFencedMathBlocks" => 10,
"doTables" => 15,
"doDefLists" => 45,
);
@@ -2918,6 +2953,60 @@
}
+ function doFencedMathBlocks($text) {
+ #
+ # Adding the fenced math block syntax to regular Markdown:
+ #
+ # $$
+ # Math block
+ # $$
+ #
+ $less_than_tab = $this->tab_width;
+
+ $text = preg_replace_callback('{
+ (?:\n|\A)
+ # 1: Opening marker
+ (
+ (?:\$\$)
+ )
+ [ ]* \n # Whitespace and newline following marker.
+
+ # 4: Content
+ (
+ (?>
+ (?!\$\$ [ ]* \n) # Not a closing marker.
+ .*\n+
+ )+
+ )
+
+ # Closing marker.
+ \$\$ [ ]* (?= \n )
+ }xm',
+ array(&$this, '_doFencedMathBlocks_callback'), $text);
+
+ return $text;
+ }
+ function _doFencedMathBlocks_callback($matches) {
+ $codeblock = $matches[2];
+ $codeblock = htmlspecialchars($codeblock, ENT_NOQUOTES);
+ $codeblock = preg_replace_callback('/^\n+/',
+ array(&$this, '_doFencedMathBlocks_newlines'), $codeblock);
+
+ if ($this->math_class) {
+ $attr = " class=\"$this->math_class\"";
+ } else {
+ $attr = "";
+ }
+ $codeblock = "<div$attr>$$\n$codeblock$$</div>";
+
+ return "\n\n".$this->hashBlock($codeblock)."\n\n";
+ }
+ function _doFencedMathBlocks_newlines($matches) {
+ return str_repeat("<br$this->empty_element_suffix",
+ strlen($matches[0]));
+ }
+
+
function doFencedCodeBlocks($text) {
#
# Adding the fenced code block syntax to regular Markdown:
@timothyqiu
Copy link
Author

Uses $ for inline math and $$ for a fenced math block, similar to inline code and fenced code block in regular Markdown.

This keeps the wrapped math code untouched by the Markdown parser, so we can use KaTex or MathJax to detect and render them.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment