+module markdown_maths
+
+intrude import markdown_inline_parsing
+intrude import markdown_block_parsing
+
+redef class MdParser
+
+ # Enable maths mode
+ var maths_mode = false is writable
+
+ redef var inline_parser is lazy do
+ var parser = super
+ parser.maths_mode = maths_mode
+ return parser
+ end
+end
+
+redef class MdInlineParser
+
+ # Enable maths mode
+ private var maths_mode = false
+
+ redef var delimiter_processors is lazy do
+ var processors = super
+ if maths_mode then
+ processors.add new MdMathsProcessor
+ end
+ return processors
+ end
+end
+
+# Maths equation processor
+class MdMathsProcessor
+ super MdDelimiterProcessor
+
+ # Maths equation delimiter
+ #
+ # Default is `$`.
+ var delimiter_char = '$'
+
+ redef var min_length = 1
+ redef fun opening_delimiter do return delimiter_char
+ redef fun closing_delimiter do return delimiter_char
+ redef fun delimiter_use(opener, closer) do return 1
+
+ redef fun process(opener, closer, delimiter_use) do
+ var node = new MdMaths(
+ new MdLocation(
+ opener.location.line_start, opener.location.column_start,
+ closer.location.line_end, closer.location.column_end),
+ opening_delimiter.to_s)
+
+ var buffer = new Buffer
+ var tmp = opener.next
+ while tmp != null and tmp != closer do
+ var next = tmp.next
+ tmp.maths_literal(buffer)
+ tmp.unlink
+ tmp = next
+ end
+ node.literal = buffer.to_s
+ opener.insert_after(node)
+ end
+end
+
+# Math equation node
+class MdMaths
+ super MdDelimited
+
+ # Literal Maths string
+ var literal: nullable String = null
+end
+
+# Inline nodes
+
+redef class MdNode
+
+ # Return the content of the node as a literal string
+ private fun maths_literal(buffer: Buffer) do
+ var node = first_child
+ while node != null do
+ node.maths_literal(buffer)
+ node = node.next
+ end
+ end
+end
+
+redef class MdCode
+ redef fun maths_literal(buffer) do buffer.append "{delimiter}{literal}{delimiter}"
+end
+
+redef class MdDelimited
+ redef fun maths_literal(buffer) do
+ buffer.append opening_delimiter
+ super
+ buffer.append closing_delimiter
+ end
+end
+
+redef class MdHtmlInline
+ redef fun maths_literal(buffer) do buffer.append literal
+end
+
+redef class MdLinkOrImage
+ redef fun maths_literal(buffer) do
+ if self isa MdLink and is_autolink then
+ buffer.append "<{destination}>"
+ return
+ end
+ if self isa MdImage then
+ buffer.append "!"
+ end
+ buffer.append "["
+ super
+ buffer.append "]"
+ buffer.append "({destination})"
+ end
+end
+
+redef class MdLink
+ redef fun maths_literal(buffer) do buffer.append "[{title or else ""}]({destination})"
+end
+
+redef class MdText
+ redef fun maths_literal(buffer) do buffer.append literal
+end
diff --git a/lib/markdown2/markdown_md_rendering.nit b/lib/markdown2/markdown_md_rendering.nit
index eadda1b684..1123ba874f 100644
--- a/lib/markdown2/markdown_md_rendering.nit
+++ b/lib/markdown2/markdown_md_rendering.nit
@@ -18,6 +18,7 @@ module markdown_md_rendering
import markdown_rendering
import markdown_github
import markdown_wikilinks
+import markdown_maths
# Markdown document renderer to Markdown
class MarkdownRenderer
@@ -390,3 +391,13 @@ redef class MdWikilink
v.add_raw "]]"
end
end
+
+# Math mode
+
+redef class MdMaths
+ redef fun render_md(v) do
+ v.add_raw "$"
+ v.add_raw literal or else ""
+ v.add_raw "$"
+ end
+end
diff --git a/lib/markdown2/tests/test_markdown_maths.nit b/lib/markdown2/tests/test_markdown_maths.nit
new file mode 100644
index 0000000000..cc36137340
--- /dev/null
+++ b/lib/markdown2/tests/test_markdown_maths.nit
@@ -0,0 +1,176 @@
+# This file is part of NIT ( http://www.nitlanguage.org ).
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# Tests for markdown Maths mode
+module test_markdown_maths is test
+
+import test_markdown
+import test_markdown_location
+import test_markdown_md
+import test_markdown_man
+import test_markdown_latex
+
+redef class TestMarkdown
+ redef var md_parser is lazy do
+ var parser = super
+ parser.maths_mode = true
+ return parser
+ end
+end
+
+class TestMathsLocation
+ super TestMarkdownLocation
+ test
+
+ fun test_maths_strike is test do
+ var md = """
+A $formula$ text.
+"""
+ var loc = """
+MdDocument: 1,1--1,17
+ MdParagraph: 1,1--1,17
+ MdText: 1,1--1,2
+ MdMaths: 1,3--1,11
+ MdText: 1,12--1,17
+"""
+ assert md_to_loc(md) == loc
+ end
+
+ fun test_maths_strike2 is test do
+ var md = """
+A $$formula$$ text.
+"""
+ var loc = """
+MdDocument: 1,1--1,19
+ MdParagraph: 1,1--1,19
+ MdText: 1,1--1,2
+ MdMaths: 1,3--1,13
+ MdText: 1,14--1,19
+"""
+ assert md_to_loc(md) == loc
+ end
+end
+
+class TestMathsHtml
+ super TestMarkdownHtml
+ test
+
+ var img_out_dir = "maths.out"
+
+ fun before is before do
+ html_renderer.maths_img_outdir = null
+ end
+
+ fun after is after do
+ img_out_dir.rmdir
+ end
+
+ fun test_maths1 is test do
+ var md = """foo $bar$ baz\n"""
+ var html = """foo $bar$ baz
\n"""
+ assert md_to_html(md) == html
+ end
+
+ fun test_maths2 is test do
+ var md = """foo $1 * 2 * 3$ baz\n"""
+ var html = """foo $1 * 2 * 3$ baz
\n"""
+ assert md_to_html(md) == html
+ end
+
+ fun test_maths3 is test do
+ var md = """foo $1 ^ 2 ^ 3$ baz\n"""
+ var html = """foo $1 ^ 2 ^ 3$ baz
\n"""
+ assert md_to_html(md) == html
+ end
+
+ fun test_maths4 is test do
+ var md = """foo $1 _2_3$ baz\n"""
+ var html = """foo $1 _2_3$ baz
\n"""
+ assert md_to_html(md) == html
+ end
+
+ fun test_maths5 is test do
+ var md = """foo $\\psi_{tot}(x,-t_0,r) = \\frac{1}{(2\\pi)^2} \\int\\!\\!\\!\\int\\tilde\\Psi_{tot}\\left(k_x,\\frac{c}{2}\\sqrt{k_x^2 + k_r^2},r=0\\right)$ baz\n"""
+ var html = """foo $\\psi_{tot}(x,-t_0,r) = \\frac{1}{(2\\pi)^2} \\int!!!\\int\\tilde\\Psi_{tot}\\left(k_x,\\frac{c}{2}\\sqrt{k_x^2 + k_r^2},r=0\\right)$ baz
\n"""
+ assert md_to_html(md) == html
+ end
+
+ fun test_maths6 is test do
+ html_renderer.maths_img_outdir = img_out_dir
+ var md = """foo $\\psi_{tot}(x,-t_0,r) = \\frac{1}{(2\\pi)^2}$ baz\n"""
+ var html = """foo baz
\n"""
+ assert md_to_html(md) == html
+ end
+
+ fun test_maths_bad is test do
+ var md = """foo $bar baz\n"""
+ var html = """foo $bar baz
\n"""
+ assert md_to_html(md) == html
+ end
+
+ fun test_maths_bad2 is test do
+ var md = """foo $$bar$ baz\n"""
+ var html = """foo $$bar$ baz
\n"""
+ assert md_to_html(md) == html
+ end
+
+ fun test_maths_bad3 is test do
+ var md = """foo $$$bar$ baz\n"""
+ var html = """foo $$$bar$ baz
\n"""
+ assert md_to_html(md) == html
+ end
+
+ fun test_maths_bad4 is test do
+ var md = """foo bar$ baz\n"""
+ var html = """foo bar$ baz
\n"""
+ assert md_to_html(md) == html
+ end
+
+ fun test_maths_bad5 is test do
+ var md = """foo $bar$$$$ baz\n"""
+ var html = """foo $bar$$$$ baz
\n"""
+ assert md_to_html(md) == html
+ end
+end
+
+class TestMathsMd
+ super TestMarkdownMd
+ test
+
+ fun test_maths_md is test do
+ var md = """$foo$\n"""
+ assert md_to_md(md) == md
+ end
+end
+
+class TessMathsMan
+ super TestMarkdownMan
+ test
+
+ fun test_maths_man is test do
+ var md = """$formula$\n"""
+ var man = """\n$formula$\n"""
+ assert md_to_man(md) == man
+ end
+end
+
+class TestMathsLatex
+ super TestMarkdownLatex
+ test
+
+ fun test_maths_latex is test do
+ var md = """A $formula$ text.\n"""
+ assert md_to_tex(md) == md
+ end
+end