mirror of
https://github.com/renbaoshuo/S2OJ.git
synced 2024-12-23 16:51:52 +00:00
249 lines
7.6 KiB
PHP
249 lines
7.6 KiB
PHP
<?php
|
|
|
|
class ParsedownMath extends Parsedown
|
|
{
|
|
const VERSION = '1.2';
|
|
|
|
public function __construct($options = '')
|
|
{
|
|
if (version_compare(parent::version, '1.7.3') < 0) {
|
|
throw new Exception('ParsedownMath requires a later version of Parsedown');
|
|
}
|
|
// Blocks
|
|
$this->BlockTypes['\\'][] = 'Math';
|
|
$this->BlockTypes['$'][] = 'Math';
|
|
|
|
// Inline
|
|
$this->InlineTypes['\\'][] = 'Math';
|
|
$this->inlineMarkerList .= '\\';
|
|
|
|
$this->InlineTypes['$'][] = 'Math';
|
|
$this->inlineMarkerList .= '$';
|
|
|
|
$this->options['math']['enabled'] = (isset($options['math']['enabled']) ? $options['math']['enabled'] : false);
|
|
$this->options['math']['inline']['enabled'] = (isset($options['math']['inline']['enabled']) ? $options['math']['inline']['enabled'] : true);
|
|
$this->options['math']['block']['enabled'] = (isset($options['math']['block']['enabled']) ? $options['math']['block']['enabled'] : true);
|
|
$this->options['math']['matchSingleDollar'] = (isset($options['math']['matchSingleDollar']) ? $options['math']['matchSingleDollar'] : false);
|
|
}
|
|
|
|
protected function element(array $Element)
|
|
{
|
|
if ($this->safeMode) {
|
|
$Element = $this->sanitiseElement($Element);
|
|
}
|
|
|
|
if (isset($Element['name'])) {
|
|
$markup = '<'.$Element['name'];
|
|
} else {
|
|
$markup = '';
|
|
}
|
|
|
|
if (isset($Element['attributes'])) {
|
|
foreach ($Element['attributes'] as $name => $value) {
|
|
if ($value === null) {
|
|
continue;
|
|
}
|
|
|
|
$markup .= ' '.$name.'="'.self::escape($value).'"';
|
|
}
|
|
}
|
|
|
|
if (isset($Element['text'])) {
|
|
if (isset($Element['name'])) {
|
|
$markup .= '>';
|
|
}
|
|
|
|
if (!isset($Element['nonNestables'])) {
|
|
$Element['nonNestables'] = array();
|
|
}
|
|
|
|
if (isset($Element['handler'])) {
|
|
$markup .= $this->{$Element['handler']}($Element['text'], $Element['nonNestables']);
|
|
} else {
|
|
$markup .= self::escape($Element['text'], true);
|
|
}
|
|
|
|
if (isset($Element['name'])) {
|
|
$markup .= '</'.$Element['name'].'>';
|
|
}
|
|
} else {
|
|
if (isset($Element['name'])) {
|
|
$markup .= ' />';
|
|
}
|
|
}
|
|
|
|
return $markup;
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// -------------------------------------------------------------------------
|
|
// ----------------------- Inline --------------------------
|
|
// -------------------------------------------------------------------------
|
|
|
|
|
|
//
|
|
// Inline Math
|
|
// -------------------------------------------------------------------------
|
|
|
|
protected function inlineMath($Excerpt)
|
|
{
|
|
if (!$this->options['math']['enabled'] === true && !$this->options['math']['inline']['enabled'] !== false) {
|
|
return;
|
|
}
|
|
|
|
$matchSignleDollar = $this->options['math']['matchSingleDollar'] ?? false;
|
|
|
|
|
|
// Using inline detection to detect Block single-line math.
|
|
|
|
if (preg_match('/^(?<!\\\\)(?<!\$)\${2}(?!\$)[^$]*?(?<!\$)\${2}(?!\$)$/', $Excerpt['text'], $matches)) {
|
|
$Block = array(
|
|
'element' => array(
|
|
'text' => '',
|
|
),
|
|
);
|
|
|
|
$Block['end'] = '$$';
|
|
$Block['complete'] = true;
|
|
$Block['latex'] = true;
|
|
$Block['element']['text'] = $matches[0];
|
|
$Block['extent'] = strlen($Block['element']['text']);
|
|
return $Block;
|
|
}
|
|
|
|
|
|
// Inline Matches
|
|
if ($matchSignleDollar === true) {
|
|
// Experimental
|
|
if (preg_match('/^(?<!\\\\)((?<!\$)\$(?!\$)(.*?)(?<!\$)\$(?!\$)|(?<!\\\\\()\\\\\((.*?)(?<!\\\\\()\\\\\)(?!\\\\\)))/s', $Excerpt['text'], $matches)) {
|
|
$this->mathMatch = $matches[0];
|
|
}
|
|
} else {
|
|
if (preg_match('/^(?<!\\\\)(?<!\\\\\()\\\\\((.*?)(?<!\\\\\()\\\\\)(?!\\\\\))/s', $Excerpt['text'], $matches)) {
|
|
$this->mathMatch = $matches[0];
|
|
}
|
|
}
|
|
|
|
if (isset($this->mathMatch)) {
|
|
return array(
|
|
'extent' => strlen($this->mathMatch),
|
|
'element' => array(
|
|
'text' => $this->mathMatch,
|
|
),
|
|
);
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
protected $specialCharacters = array(
|
|
'\\', '`', '*', '_', '{', '}', '[', ']', '(', ')', '<', '>', '#', '+', '-', '.', '!', '|', '~', '^', '='
|
|
);
|
|
|
|
|
|
//
|
|
// Inline Escape
|
|
// -------------------------------------------------------------------------
|
|
|
|
protected function inlineEscapeSequence($Excerpt)
|
|
{
|
|
$Element = array(
|
|
'element' => array(
|
|
'rawHtml' => $Excerpt['text'][1],
|
|
),
|
|
'extent' => 2,
|
|
);
|
|
|
|
if ($this->options['math']['enabled'] === true) {
|
|
if (isset($Excerpt['text'][1]) && in_array($Excerpt['text'][1], $this->specialCharacters) && !preg_match('/^(?<!\\\\)((?<!\\\\\()\\\\\((?!\\\\\())(.*?)(?<!\\\\)(?<!\\\\\()((?<!\\\\\))\\\\\)(?!\\\\\)))(?!\\\\\()/s', $Excerpt['text'])) {
|
|
return $Element;
|
|
} elseif (isset($Excerpt['text'][1]) && in_array($Excerpt['text'][1], $this->specialCharacters) && !preg_match('/^(?<!\\\\)(?<!\\\\\()\\\\\((.{1,}?)(?<!\\\\\()\\\\\)(?!\\\\\))/s', $Excerpt['text'])) {
|
|
return $Element;
|
|
}
|
|
} else {
|
|
if (isset($Excerpt['text'][1]) && in_array($Excerpt['text'][1], $this->specialCharacters)) {
|
|
return $Element;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
// -------------------------------------------------------------------------
|
|
// ----------------------- Blocks --------------------------
|
|
// -------------------------------------------------------------------------
|
|
|
|
|
|
//
|
|
// Block Math
|
|
// --------------------------------------------------------------------------
|
|
|
|
protected function blockMath($Line)
|
|
{
|
|
if (!$this->options['math']['enabled'] === true && !$this->options['math']['block']['enabled'] !== false) {
|
|
return;
|
|
}
|
|
|
|
$Block = array(
|
|
'element' => array(
|
|
'text' => '',
|
|
),
|
|
);
|
|
|
|
if (preg_match('/^(?<!\\\\)(\\\\\[)(?!.)$/', $Line['text'])) {
|
|
$Block['end'] = '\]';
|
|
return $Block;
|
|
} elseif (preg_match('/^(?<!\\\\)(\$\$)(?!.)$/', $Line['text'])) {
|
|
$Block['end'] = '$$';
|
|
return $Block;
|
|
}
|
|
}
|
|
|
|
// ~
|
|
|
|
protected function blockMathContinue($Line, $Block)
|
|
{
|
|
if (isset($Block['complete'])) {
|
|
return;
|
|
}
|
|
|
|
if (isset($Block['interrupted'])) {
|
|
$Block['element']['text'] .= str_repeat("\n", $Block['interrupted']);
|
|
|
|
unset($Block['interrupted']);
|
|
}
|
|
|
|
if (preg_match('/^(?<!\\\\)(\\\\\])$/', $Line['text']) && $Block['end'] === '\]') {
|
|
$Block['complete'] = true;
|
|
$Block['latex'] = true;
|
|
$Block['element']['text'] = "\\[".$Block['element']['text']."\\]";
|
|
return $Block;
|
|
} elseif (preg_match('/^(?<!\\\\)(\$\$)$/', $Line['text']) && $Block['end'] === '$$') {
|
|
$Block['complete'] = true;
|
|
$Block['latex'] = true;
|
|
$Block['element']['text'] = "$$".$Block['element']['text']."$$";
|
|
return $Block;
|
|
}
|
|
|
|
|
|
$Block['element']['text'] .= "\n" . $Line['body'];
|
|
|
|
// ~
|
|
|
|
return $Block;
|
|
}
|
|
|
|
// ~
|
|
|
|
protected function blockMathComplete($Block)
|
|
{
|
|
return $Block;
|
|
}
|
|
}
|