Skip to content
Open
5 changes: 5 additions & 0 deletions Sources/Ink/API/MarkdownParser.swift
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,11 @@ private extension MarkdownParser {
return HorizontalLine.self
case "-", "*", "+", \.isNumber: return List.self
case "|": return Table.self
case "\\":
if ["[","("].contains(nextCharacter) {
return Math.self
}
fallthrough
default: return Paragraph.self
}
}
Expand Down
17 changes: 13 additions & 4 deletions Sources/Ink/Internal/Math.swift
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,11 @@ internal struct Math: Fragment {

while !reader.didReachEnd {
switch reader.currentCharacter {
case \.isNewline :
throw Reader.Error()

case "&":
tex.append(reader.currentCharacter)
reader.advanceIndex()

case "\\" :
guard let nextCharacter = reader.nextCharacter else {
throw Reader.Error()
Expand All @@ -39,22 +42,28 @@ internal struct Math: Fragment {
}

fallthrough

default:
if let escaped = reader.currentCharacter.escaped {
tex.append(escaped)
} else {
tex.append(reader.currentCharacter)
}
reader.advanceIndex()

}
}
throw Reader.Error()
}

func html(usingURLs urls: NamedURLCollection,
modifiers: ModifierCollection) -> String {
let modeString = displayMode ? "display" : "inline"
return "<span class=\"math \(modeString)\">\(tex)</span>"

if displayMode {
return "<p><span class=\"math display\">\\[\(tex)\\]</span></p>"
} else {
return "<span class=\"math inline\">\\(\(tex)\\)</span>"
}
}

func plainText() -> String {
Expand Down
13 changes: 11 additions & 2 deletions Tests/InkTests/LinkTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -66,8 +66,16 @@ final class LinkTests: XCTestCase {
}

func testLinkWithEscapedSquareBrackets() {
// It doesn't make a ton of sense to include a display equation inside a link, but I believe this assertion is accurate, since display-mode equations are always displayed distinct from another body of text – so the <p></p> tags inside the link are required.
// SEE: https://www.overleaf.com/learn/latex/Display_style_in_math_mode for visual example.
let html = MarkdownParser().html(from: "[\\[Hello\\]](hello)")
XCTAssertEqual(html, #"<p><a href="hello"><span class="math display">Hello</span></a></p>"#)
XCTAssertEqual(html, #"<p><a href="hello"><p><span class="math display">\[Hello\]</span></p></a></p>"#)
}

func testLinkWithEscapedRoundBrackets() {
// If someone was going to include an equation inside a link, it seems like they would use an inline equation.
let html = MarkdownParser().html(from: "[\\(Hello\\)](hello)")
XCTAssertEqual(html, #"<p><a href="hello"><span class="math inline">\(Hello\)</span></a></p>"#)
}
}

Expand All @@ -82,7 +90,8 @@ extension LinkTests {
("testBoldLinkWithExternalMarkers", testBoldLinkWithExternalMarkers),
("testLinkWithUnderscores", testLinkWithUnderscores),
("testUnterminatedLink", testUnterminatedLink),
("testLinkWithEscapedSquareBrackets", testLinkWithEscapedSquareBrackets)
("testLinkWithEscapedSquareBrackets", testLinkWithEscapedSquareBrackets),
("testLinkWithEscapedRoundBrackets", testLinkWithEscapedRoundBrackets),
]
}
}
91 changes: 87 additions & 4 deletions Tests/InkTests/MathTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -10,17 +10,95 @@ import Ink
final class MathTests: XCTestCase {
func testInlineMath() {
let html = MarkdownParser().html(from: #"\(Hello \Latex\)"#)
XCTAssertEqual(html, #"<p><span class="math inline">Hello \Latex</span></p>"#)
XCTAssertEqual(html, #"<span class="math inline">\(Hello \Latex\)</span>"#)
}

func testDisplayMath() {
let html = MarkdownParser().html(from: #"\[Hello \Latex\]"#)
XCTAssertEqual(html, #"<p><span class="math display">Hello \Latex</span></p>"#)
XCTAssertEqual(html, #"<p><span class="math display">\[Hello \Latex\]</span></p>"#)
}


func testDisplayStandardFormQuadraticSingleLine() {
let html = MarkdownParser().html(from: #"\[y = a\left(x-h\right)^2+k\]"#)
XCTAssertEqual(html, #"<p><span class="math display">\[y = a\left(x-h\right)^2+k\]</span></p>"#)
}

func testDisplayStandardFormQuadraticMultiLine() {
let html = MarkdownParser().html(from: #"""
\[
y = a\left(x-h\right)^2+k
\]
"""#)
XCTAssertEqual(html, #"""
<p><span class="math display">\[
y = a\left(x-h\right)^2+k
\]</span></p>
"""#)
}

func testDisplayMultiLineProgression() {
let html = MarkdownParser().html(from: #"""
\[
y = 5\\
x^2
\]
"""#)
XCTAssertEqual(html, #"""
<p><span class="math display">\[
y = 5\\
x^2
\]</span></p>
"""#)
}

func testDisplayMultiLineAlignedEquationProgression() {
let html = MarkdownParser().html(from: #"""
\[
\begin{aligned}
y&=\left(x-r\right)\left(x-s\right)\\
y&=\left(x-\left(-7\right)\right)\left(x-\left(-2\right)\right)\\
y&=\left(x+7\right)\left(x+2\right)\\
y&=x^2+9x+14\\
y&=x^2+bx+c\\
\end{aligned}
\]
"""#)
XCTAssertEqual(html, #"""
<p><span class="math display">\[
\begin{aligned}
y&=\left(x-r\right)\left(x-s\right)\\
y&=\left(x-\left(-7\right)\right)\left(x-\left(-2\right)\right)\\
y&=\left(x+7\right)\left(x+2\right)\\
y&=x^2+9x+14\\
y&=x^2+bx+c\\
\end{aligned}
\]</span></p>
"""#)
}

func testMathWithEscape() {
let html = MarkdownParser().html(from: #"Asterix \* and \(Hello \Latex\)"#)
XCTAssertEqual(html, #"<p>Asterix * and <span class="math inline">Hello \Latex</span></p>"#)
XCTAssertEqual(html, #"<p>Asterix * and <span class="math inline">\(Hello \Latex\)</span></p>"#)
}

func testPictureTagWithDisplayModeEquationAndParagraphWithLink() {
let html = MarkdownParser().html(from: #"""
<picture>
<source srcset="equation-2-dark.png" media="(prefers-color-scheme: dark)">
<img src="equation-2.png" loading="lazy" alt="Vertex form of a quadratic" style="width:166px;"/>
</picture>

\[y = a\left(x-h\right)^2+k\]

You might even struggle to make it through, who knows, dressing up some drab review of quadratic relations by [using a *Jeopardy!* template](https://duckduckgo.com/?q=jeopardy+templates&t=osx&ia=web) at the end of a unit of study.
"""#)

XCTAssertEqual(html, #"""
<picture>
<source srcset="equation-2-dark.png" media="(prefers-color-scheme: dark)">
<img src="equation-2.png" loading="lazy" alt="Vertex form of a quadratic" style="width:166px;"/>
</picture><p><span class="math display">\[y = a\left(x-h\right)^2+k\]</span></p><p>You might even struggle to make it through, who knows, dressing up some drab review of quadratic relations by <a href="https://duckduckgo.com/?q=jeopardy+templates&t=osx&ia=web">using a <em>Jeopardy!</em> template</a> at the end of a unit of study.</p>
"""#)
}
}

Expand All @@ -29,7 +107,12 @@ extension MathTests {
return [
("testInlineMath", testInlineMath),
("testDisplayMath", testDisplayMath),
("testDisplayStandardFormQuadraticSingleLine", testDisplayStandardFormQuadraticSingleLine),
("testDisplayStandardFormQuadraticMultiLine", testDisplayStandardFormQuadraticMultiLine),
("testDisplayMultiLineProgression", testDisplayMultiLineProgression),
("testDisplayMultiLineAlignedEquationProgression", testDisplayMultiLineAlignedEquationProgression),
("testMathWithEscape", testMathWithEscape),
("testPictureTagWithDisplayModeEquationAndParagraphWithLink", testPictureTagWithDisplayModeEquationAndParagraphWithLink),
]
}
}