From eae04943d8c8e94fad842dcc01d84521364900f8 Mon Sep 17 00:00:00 2001
From: Dominique Fournier
Date: Sat, 10 May 2014 17:17:52 +0000
Subject: [PATCH] First version of Markdown converter. Not complete, but there
is a workbase
git-svn-id: https://svn.fournier38.fr/svn/ProgSVN/trunk@1282 bf3deb0d-5f1a-0410-827f-c0cc1f45334c
---
markdown.php | 248 +++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 248 insertions(+)
create mode 100644 markdown.php
diff --git a/markdown.php b/markdown.php
new file mode 100644
index 0000000..2d69220
--- /dev/null
+++ b/markdown.php
@@ -0,0 +1,248 @@
+ */
+
+function debug ($msg)
+{
+ $trace = debug_backtrace();
+ $back = reset ($trace);
+ file_put_contents ("/tmp/debug", "[".$back["line"]."] $msg\n", FILE_APPEND);
+}
+error_reporting (E_ALL);
+/** Markdown management */
+class markdown
+{
+ /** Convert the markdown language to HTML
+ Return the HTML string
+ @param string $mark Message in markdown syntax to display */
+ public function html ($mark)
+ {
+ $res = "";
+ $search = array ();
+ $replace = array ();
+
+ // VALIDATION
+// if (substr ($mark, -1) !== "\n")
+// $mark .= "\n";
+
+ // SEPARATORS : *** --- ___ * * * - - - _ _ _
+ // Must be placed before EMPHASIS
+ $search[] = "/\\n^[*_-] ?[*_-] ?[*_-]$/Um";
+ $replace[] = "
\n
\n";
+
+ // EMPHASIS : _ or * for normal, __ or ** for strong
+ $search[] = "/__(.+)__/"; $replace[] = "\\1";
+ $search[] = "/_(.+)_/"; $replace[] = "\\1";
+ $search[] = "/\*\*(.+)\*\*/"; $replace[] = "\\1";
+ $search[] = "/\*(.+)\*/"; $replace[] = "\\1";
+
+ // CODE : `code` ->
+ $search[] = "/\\n?\`((\\n|.)+)\`/Um";
+ $replace[] = " \\1";
+
+ // LINKS
+ // [Google Site](http://google.fr/ "With help bubble")
+ $search[] = "(\[(.+)\]\((https?://.+) \"(.+)\"\))";
+ $replace[] = "\\1";
+ // [Google Site](http://google.fr/)
+ $search[] = "(\[(.+)\]\((http.+)\))"; $replace[] = "\\1";
+ // Automatics links :
+ //
+ //
+ $search[] = "(\<(https?://.+)\>)"; $replace[] = "\\1";
+ $search[] = "(\<(.+@.+)\>)"; $replace[] = "\\1";
+ // TODO : Links by reference :
+ // Voici un petit texte écrit par [Michel Fortin][mf].
+ // [mf]: http://michelf.ca/ "Mon site web"
+
+ // TITLES
+ // Titles ATX (Optionnal sharp at the end)
+ // ###### Title6
+ $search[] = "/\\n^###### ([^#]+)(#*)$\\n/Um";
+ $replace[] = "
\n\\1
\n";
+ // ##### Title5
+ $search[] = "/\\n^##### ([^#]+)(#*)$\\n/Um";
+ $replace[] = "
\n\\1
\n";
+ // #### Title4
+ $search[] = "/\\n^#### ([^#]+)(#*)$\\n/Um";
+ $replace[] = "
\n\\1
\n";
+ // ### Title3
+ $search[] = "/\\n^### ([^#]+)(#*)$\\n/Um";
+ $replace[] = "
\n\\1
\n";
+ // ## Title2
+ $search[] = "/\\n^## ([^#]+)(#*)$\\n/Um";
+ $replace[] = "
\n\\1
\n";
+ // # Title1
+ $search[] = "/\\n^# ([^#]+)(#*)$\\n/Um";
+ $replace[] = "
\n\\1
\n";
+ // Titles with underline (SeText)
+ // Titre1
+ // ======
+ $search[] = "/\\n^(.+)\\n==+$\\n/Um";
+ $replace[] = "
\n\\1
\n";
+ // Titre2
+ // ------
+ $search[] = "/\\n^(.+)\\n--+$\\n/Um";
+ $replace[] = "
\n\\1
\n";
+
+ // End of line with double space :
+ $search[] = "/( )$/Um"; $replace[] = "
";
+
+ $res = preg_replace ($search, $replace, $mark);
+
+ $res = $this->paragraph ($res);
+ return $res;
+ }
+
+ /** Recursive function to translate the paragraphs
+ return the html */
+ private function paragraph ($mark)
+ {
+ $debug = 1;
+ $mark = str_replace ("\t", " ", $mark);
+ $spacer = " ";
+ $res = "";
+ // P, OL, UL (but not LI !)
+ // Use to found the changing of types
+ $typeStack = array ();
+ // Number of spaces
+ $indentStack = array (-1);
+ // All the HTML stack (with LI)
+ $htmlStack = array ();
+ $lines = explode ("\n", $mark);
+ foreach ($lines as $line)
+ {
+ debug ( "DEBUT:$line");
+ $type = $this->paragraphType ($line);
+ debug ( "DEBUT: Type='$type'");
+ $matches = array ();
+ switch ($type)
+ {
+ case "ol" :
+ preg_match ("/^( *)[0-9]+\. +(.*)/", $line, $matches);
+ $lineTxt = $matches[2];
+ break ;
+ case "ul" :
+ preg_match ("/^( *)[-+*] +(.*)/", $line, $matches);
+ $lineTxt = $matches[2];
+ break ;
+ default:
+ $lineTxt = $line;
+ }
+ $indent = strspn ($line, " ");
+ debug ( "DEBUT: Indent='$indent'");
+
+ // Spacing
+ if ($indent < end ($indentStack))
+ {
+ debug ( "DEB1 : Ending of block");
+ if (end ($htmlStack) === "li")
+ {
+ debug ("Pending
: closing");
+ debug ("");
+ $res .= "";
+ array_pop ($htmlStack);
+ }
+ $oldType = array_pop ($typeStack);
+ debug (str_repeat (" ", end ($indentStack))."$oldType>");
+ $res .= "\n".str_repeat (" ", end ($indentStack))."$oldType>";
+ array_pop ($htmlStack);
+ if ($type === "ol" || $type === "ul")
+ {
+ debug ("DEB2 : Pending : closing");
+ debug ("");
+ $res .= "\n";
+ array_pop ($htmlStack);
+ debug ("DEB2 : Adding li");
+ $htmlStack[] = "li";
+ debug ( str_repeat (" ", $indent)."");
+ $res .= "\n".str_repeat (" ", $indent)."";
+ }
+ debug (str_repeat (" ", $indent)."$lineTxt");
+ $res .= str_repeat (" ", $indent)."$lineTxt";
+ array_pop ($indentStack);
+ }
+ elseif ($indent > end ($indentStack))
+ {
+ debug ( "DEB1 : Starting a new block");
+ array_push ($indentStack, $indent);
+ array_push ($typeStack, $type);
+ debug ( str_repeat (" ", $indent)."<$type>");
+ $res .= "\n".str_repeat (" ", $indent)."<$type>";
+ $htmlStack[] = $type;
+ if ($type === "ol" || $type === "ul")
+ {
+ debug ("DEB2 : Adding li");
+ $htmlStack[] = "li";
+ debug ( str_repeat (" ", $indent)."");
+ $res .= "\n".str_repeat (" ", $indent)."";
+ }
+ debug ( "$lineTxt");
+ $res .= "$lineTxt";
+ }
+ else
+ {
+ debug ( "DEB1 : Continuous block $type/".end ($typeStack));
+ if (end ($htmlStack) === "li")
+ {
+ debug ("Pending : closing");
+ debug ("");
+ $res .= "";
+ array_pop ($htmlStack);
+ }
+ debug ( "DEB1 : Continuous block $type/".end ($typeStack)." SECOND");
+ if ($type !== end ($typeStack))
+ {
+ debug ( "DEB2 : Continuous Block but type change");
+ $oldType = array_pop ($typeStack);
+ debug (str_repeat (" ", end ($indentStack))."$oldType>");
+ $res .= "\n".str_repeat (" ", end ($indentStack))."$oldType>";
+ array_pop ($htmlStack);
+
+ debug (str_repeat (" ", end ($indentStack))."<$type>");
+ $res .= "\n".str_repeat (" ", end ($indentStack))."<$type>";
+ $htmlStack[] = $type;
+ array_push ($indentStack, $indent);
+ array_push ($typeStack, $type);
+ }
+
+ if ($type === "ol" || $type === "ul")
+ {
+ debug ("DEB2 : Adding li");
+ $htmlStack[] = "li";
+ debug ( str_repeat (" ", $indent)."");
+ $res .= "\n".str_repeat (" ", $indent)."";
+ }
+
+ debug ("$lineTxt");
+ $res .= "$lineTxt";
+ }
+ }
+
+ debug ( "DEB1 : End of loop");
+ $htmlStack = array_reverse ($htmlStack);
+ foreach ($htmlStack as $type)
+ {
+ debug ( "FIN$type>");
+ $res .= "$type>\n";
+ }
+
+ debug ( "-----------\n");
+ return $res;
+ }
+
+ /** Return the Type of object in the provided line
+ p, ul, ol, code */
+ private function paragraphType ($line)
+ {
+ $line = ltrim ($line);
+ if (! isset ($line{0}))
+ return "";
+ if ($line{0} === "*" || $line{0} === "-" || $line{0} === "+")
+ return "ul";
+ if (preg_match ("/^[0-9]+\. /", $line) === 1)
+ return "ol";
+ return "p";
+ }
+}