<?php namespace HashOver;// Copyright (C) 2015-2021 Jacob Barkdull// This file is part of HashOver.//// HashOver is free software: you can redistribute it and/or modify// it under the terms of the GNU Affero General Public License as// published by the Free Software Foundation, either version 3 of the// License, or (at your option) any later version.//// HashOver is distributed in the hope that it will be useful,// but WITHOUT ANY WARRANTY; without even the implied warranty of// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the// GNU Affero General Public License for more details.//// You should have received a copy of the GNU Affero General Public License// along with HashOver.  If not, see <http://www.gnu.org/licenses/>.class Markdown{	// Matches a markdown code block	protected $blockCodeRegex = '/```([\s\S]+?)```/S';	// Matches a paragraph/double line break	protected $paragraphRegex = '/(?:\r\n|\r|\n){2}/S';	// Matches markdown inline code	protected $inlineCodeRegex = '/(^|[^a-z0-9`])`((?!`)[\s\S]+?)`([^a-z0-9`]|$)/iS';	// Array for inline code and code block markers	protected $codeMarkers = array (		'block' => array ('marks' => array (), 'count' => 0),		'inline' => array ('marks' => array (), 'count' => 0)	);	// Markdown patterns to search for	protected $search = array (		// Matches **bold** text		'/\*\*([^ *])([\s\S]+?)([^ *])\*\*/S',		// Matches *italic* text		'/\*([^ *])([\s\S]+?)([^ *])\*/S',		// Matches _underlined_ text		'/(^|\W)_((?!_)[\s\S]+?)_(\W|$)/S',		// Matches forced __underlined__ text		'/__([^ _])([\s\S]+?)([^ _])__/S',		// Matches ~~strikethrough~~ text		'/~~([^ ~])([\s\S]+?)([^ ~])~~/S'	);	// HTML replacements for markdown patterns	protected $replace = array (		'<strong>\\1\\2\\3</strong>',		'<em>\\1\\2\\3</em>',		'\\1<u>\\2</u>\\3',		'<u>\\1\\2\\3</u>',		'<s>\\1\\2\\3</s>'	);	// Replaces markdown for inline code with a marker	protected function codeReplace ($grp, $display)	{		$markName = 'CODE_' . strtoupper ($display);		$markCount = $this->codeMarkers[$display]['count']++;		if ($display !== 'block') {			$codeMarker = $grp[1] . $markName . '[' . $markCount . ']' . $grp[3];			$this->codeMarkers[$display]['marks'][$markCount] = trim ($grp[2], "\r\n");		} else {			$codeMarker = $markName . '[' . $markCount . ']';			$this->codeMarkers[$display]['marks'][$markCount] = trim ($grp[1], "\r\n");		}		return $codeMarker;	}	// Replaces markdown for code block with a marker	protected function blockCodeReplace ($grp)	{		return $this->codeReplace ($grp, 'block');	}	// Replaces markdown for inline code with a marker	protected function inlineCodeReplace ($grp)	{		return $this->codeReplace ($grp, 'inline');	}	// Returns the original inline markdown code with HTML replacement	protected function inlineCodeReturn ($grp)	{		return '<code class="hashover-inline">' . $this->codeMarkers['inline']['marks'][($grp[1])] . '</code>';	}	// Returns the original markdown code block with HTML replacement	protected function blockCodeReturn ($grp)	{		return '<code>' . $this->codeMarkers['block']['marks'][($grp[1])] . '</code>';	}	// Parses a string as markdown	public function parseMarkdown ($string)	{		// Reset marker arrays		$this->codeMarkers = array (			'block' => array ('marks' => array (), 'count' => 0),			'inline' => array ('marks' => array (), 'count' => 0)		);		// Replace code blocks with markers		$string = preg_replace_callback ($this->blockCodeRegex, 'self::blockCodeReplace', $string);		// Break string into paragraphs		$paragraphs = preg_split ($this->paragraphRegex, $string);		// Run through each paragraph		for ($i = 0, $il = count ($paragraphs); $i < $il; $i++) {			// Replace inline code with markers			$paragraphs[$i] = preg_replace_callback ($this->inlineCodeRegex, 'self::inlineCodeReplace', $paragraphs[$i]);			// Replace markdown patterns			$paragraphs[$i] = preg_replace ($this->search, $this->replace, $paragraphs[$i]);			// Replace markers with original markdown code			$paragraphs[$i] = preg_replace_callback ('/CODE_INLINE\[([0-9]+)\]/S', 'self::inlineCodeReturn', $paragraphs[$i]);		}		// Join paragraphs		$string = implode (PHP_EOL . PHP_EOL, $paragraphs);		// Replace code block markers with original markdown code		$string = preg_replace_callback ('/CODE_BLOCK\[([0-9]+)\]/S', 'self::blockCodeReturn', $string);		return $string;	}}