on 50de7b2 help sign in
6 files changed+38−262
since splitsnapshots
unifiedsplit
Mathdown/Mathdown/main.swift+27−210 README.md+11−52 images/mat1.png images/mat2.png images/mat3.png images/mat4.png
Mathdown/Mathdown/main.swift+27−210
@@ -8,24 +8,15 @@
88
99import Foundation
1010
11−typealias Lines = [String]
12−typealias Element = [String]
13−let commentChars = CharacterSet.init(charactersIn: "#/")
14−let styleCharecters = CharacterSet.init(charactersIn: "_*")
15−
16−
1711enum BracketStyle {
1812 case square
1913 case round
20− case line
2114 var opening: Character {
2215 switch self {
2316 case .round:
2417 return "("
2518 case .square:
2619 return "["
27− case .line:
28− return "|"
2920 }
3021 }
3122 var closing: Character {
@@ -34,8 +25,6 @@ enum BracketStyle {
3425 return ")"
3526 case .square:
3627 return "]"
37− case .line:
38− return "|"
3928 }
4029 }
4130}
@@ -67,12 +56,10 @@ default:
6756 if let surl = args.popFirst() {
6857 outputUrl = URL(fileURLWithPath: surl)
6958 }
70− case "-b:s":
59+ case "-s":
7160 style = .square
72− case "-b:r":
61+ case "-r":
7362 style = .round
74− case "-b:l":
75− style = .line
7663 default:
7764 return
7865 }
@@ -87,6 +74,7 @@ enum ElementStyle: String {
8774 case italic = "italic"
8875 case boldItalic = "bold-italic"
8976}
77+let styleCharecters = CharacterSet.init(charactersIn: "_*")
9078extension String.SubSequence {
9179 var style: ElementStyle {
9280 let num = self.prefix(while: {styleCharecters.contains($0.unicodeScalars.first!)}).count
@@ -105,209 +93,38 @@ extension String.SubSequence {
10593 return self.trimmingCharacters(in: styleCharecters)
10694 }
10795}
108−
109−func process(element: Element) -> String {
110− var out = ""
111−
112− var inMatrix = false
113− var first = false
114− var seperated = false
115− var afterSeparator: [Substring] = []
116−
117− var small = false
118−
119− let arrows = CharacterSet.init(charactersIn: "⟺⟷⟼⟻⟶⟹⟵⟸")
120−
121− let nEl = element.map { (el) -> String in
122− switch el {
123− case let l where l.last == ">" && l.first == "<" && l.dropLast().dropFirst().filter({$0 == "="}).count > 0:
124− small = true
125− return "⟺"
126− case let l where l.last == ">" && l.first == "<" && l.dropLast().dropFirst().filter({$0 == "-"}).count > 0:
127− small = true
128− return "⟷"
129− case let l where l.last == ">" && l.first == "|" && l.dropLast().dropFirst().filter({$0 == "-"}).count > 0:
130− small = true
131− return "⟼"
132− case let l where l.last == "|" && l.first == "<" && l.dropLast().dropFirst().filter({$0 == "-"}).count > 0:
133− small = true
134− return "⟻"
135− case let l where l.last == ">" && l.dropLast().filter({$0 == "-"}).count > 0:
136− small = true
137− return "⟶"
138− case let l where l.last == ">" && l.dropLast().filter({$0 == "="}).count > 0:
139− small = true
140− return "⟹"
141− case let l where l.first == "<" && l.dropFirst().filter({$0 == "-"}).count > 0:
142− small = true
143− return "⟵"
144− case let l where l.first == "<" && l.dropFirst().filter({$0 == "="}).count > 0:
145− small = true
146− return "⟸"
147− default:
148− return el
149− }
150− }
96+func process(mth: String) -> String {
97+ let whitespace = CharacterSet.whitespaces
15198
152− func process(lineElement: Substring, withAttributes attributes: String = "", style: ElementStyle = .none) -> Substring {
153− func extractNextElement(from line: Substring) -> (element: Substring, left: Substring) {
154− if line.first != "(" {
155− var i = line.startIndex
156− var el: Substring = ""
157− while i < line.endIndex && CharacterSet.alphanumerics.contains(line[i].unicodeScalars.first!) {
158− el.append(line[i])
159− i = line.index(after: i)
160− }
161− return (el, line[i...])
162− } else {
163− var brackets = 0
164− var i = line.startIndex
165− var el: Substring = ""
166− while i < line.endIndex {
167− switch el[i] {
168− case "(":
169− brackets += 1
170− case ")":
171− brackets -= 1
172− default:
173− break
174− }
175− i = line.index(after: i)
176− if brackets == 0 {
177− break
178− }
179− el.append(el[i])
180− }
181− if brackets != 0 {
182− print("Mismatched brackets")
183− exit(0)
184− }
185− return (el.dropFirst(), line[i...])
99+ var out = "<math>"
100+ let lines = mth.split(separator: "\n", omittingEmptySubsequences: false)
101+ .map {$0.trimmingCharacters(in: .whitespaces)}
102+ var insideMatrix = false
103+ for line in lines {
104+ switch line {
105+ case "":
106+ if insideMatrix {
107+ out.append("</mtable><mo>\(style.closing)</mo></mrow>")
108+ insideMatrix = false
186109 }
187− }
188− var i = lineElement.startIndex
189− while i < lineElement.endIndex {
190− switch lineElement[i] {
191− case "^":
192− let parts = extractNextElement(from: lineElement[lineElement.index(after: i)...])
193− return "<mo mathvariant=\"\(style.rawValue)\" \(attributes)>\(lineElement[..<i].filter({$0 != "\\"}))</mo>" + "<msup><mo></mo><mn>\(parts.element)</mn></msup>" + process(lineElement: parts.left, withAttributes: attributes, style: style)
194− case "!":
195− let parts = extractNextElement(from: lineElement[lineElement.index(after: i)...])
196− return "<mo mathvariant=\"\(style.rawValue)\" \(attributes)>\(lineElement[..<i].filter({$0 != "\\"}))</mo>" + "<mover accent=\"true\"><mrow><mo>\(parts.element)</mo></mrow><mo>_</mo></mover>" + process(lineElement: parts.left, withAttributes: attributes, style: style)
197− case "\\":
198− i = lineElement.index(after: i)
199− case "/":
200− let parts = extractNextElement(from: lineElement[lineElement.index(after: i)...])
201− return "<mo mathvariant=\"\(style.rawValue)\" \(attributes)>\(lineElement[..<i].filter({$0 != "\\"}))</mo>" + "<msub><mo></mo><mn>\(parts.element)</mn></msub>" + process(lineElement: parts.left, withAttributes: attributes, style: style)
202− default:
203− break
110+ default:
111+ if !insideMatrix {
112+ out.append("<mrow><mo>\(style.opening)</mo><mtable>")
113+ insideMatrix = true
204114 }
205− i = lineElement.index(after: i)
206− }
207− return Substring("<mo mathvariant=\"\(style.rawValue)\" \(attributes)>\(lineElement.filter({$0 != "\\"}))</mo>")
208− }
209− func process(line: Substring) {
210− out.append("<mtr>")
211− for element in line.split(
212− whereSeparator: {c in CharacterSet.whitespaces.contains(c.unicodeScalars.first!)}) {
213− switch element {
214− case "_":
215− out.append("<mtd><mspace height=\"0.8em\"/></mtd>")
216− default:
115+ out.append("<mtr>")
116+ for element in line.split(
117+ whereSeparator: {c in whitespace.contains(c.unicodeScalars.first!)}) {
217118 let eStyle = element.style
218− out.append("<mtd>\(process(lineElement: Substring(element.trimmingStyleCharecters()), withAttributes: "height=\"0.8em\"", style: eStyle))</mtd>")
219− }
220− }
221− out.append("</mtr>")
222− }
223− func process(comment: String) {
224− if comment.hasPrefix("#") {
225− out.append("<!-- \(comment.trimmingCharacters(in: commentChars).trimmingCharacters(in: .whitespaces)) -->")
226− }
227− }
228−
229− for line in nEl {
230− if inMatrix {
231− if first && line.contains("|") {
232− seperated = true
233− }
234− switch line {
235− case "]":
236− if seperated {
237− out.append("</mtable><mo stretchy=\"true\">|</mo><mtable>")
238− for line in afterSeparator {
239− process(line: line)
240− }
241− }
242− out.append("</mtable><mo stretchy=\"true\">\(style.closing)</mo></mrow></mtd></mtr>")
243− inMatrix = false
244− seperated = false
245− afterSeparator = []
246− default:
247− if seperated {
248− let split = line.split(separator: "|", maxSplits: 1, omittingEmptySubsequences: false)
249− if split.count != 2 {
250− print("Inconsistent syntax. The `|` seperator isn't consistent within a matrix.")
251− exit(0)
252− }
253− process(line: split[0])
254− afterSeparator.append(split[1])
255− } else {
256− process(line: Substring(line))
257− }
258− }
259− } else {
260− switch line {
261− case let l where l.hasPrefix("//"):
262− break
263− case let l where l.hasPrefix("#"):
264− out.append("</mtable></math>\n\n")
265− process(comment: l)
266− out.append("\n\n<math><mtable>")
267− break // TODO: Figure out what to do
268− case "[":
269− out.append("<mtr><mtd><mrow><mo stretchy=\"true\">\(style.opening)</mo><mtable>")
270− inMatrix = true
271− first = true
272− continue
273− case "":
274− if !first {
275− out.append("</mtable><mtable>")
276− }
277− first = true
278− continue
279− case let l where arrows.contains(l.first!.unicodeScalars.first!):
280− out.append("<mtr><mtd><mo>\(line)</mo></mtd></mtr>")
281− default:
282− out.append("<mtr><mtd>\(small ? "<mstyle scriptlevel=\"1\">" : "")\(process(lineElement: Substring(line)))\(small ? "</mstyle>" : "")</mtd></mtr>")
119+ out.append("<mtd><mn mathvariant=\"\(eStyle.rawValue)\">\(element.trimmingStyleCharecters())</mn></mtd>")
283120 }
121+ out.append("</mtr>")
284122 }
285− first = false
286123 }
287− return out
288−}
289−
290−func process(mth: String) -> String {
291− let elements = mth
292− .split(separator: "\n", omittingEmptySubsequences: false)
293− .map({$0.trimmingCharacters(in: .whitespaces)})
294− .map({ l in
295− var i = l.startIndex
296− for u in 0..<max(0, l.count - 1) {
297− if l[i] == "/" && l[l.index(after: i)] == "/" {
298− return String(l.dropLast(l.count - u))
299− }
300− i = l.index(after: i)
301− }
302− return l
303− })
304− .split(separator: "")
305− var out = "<math><mtable>"
306− for el in elements {
307− out.append(process(element: Array(el)))
308− out.append("</mtable><mtable>")
124+ if insideMatrix {
125+ out.append("</mtable><mo>\(style.closing)</mo></mrow>")
309126 }
310− out.append("</mtable></math>")
127+ out.append("</math>")
311128 return out
312129}
313130
README.md+11−52
@@ -3,67 +3,26 @@ A lightweight syntax for matrices.
33Outputs [MathML](https://en.wikipedia.org/wiki/MathML) format.
44
55## Syntax
6−```
7−[
8−1 2 3
9−3 2 8
10−]
11−```
12−![](images/mat1.png)
6+`1 2 3
7+3 2 8`
8+produces
9+![](images/mat1.png | width=400)
1310
1411You can also use [Markdown](https://en.wikipedia.org/wiki/Markdown)-style text emphasis
1512- `_<text>_` or `*<text>*` for _italic_
1613- `__<text>__` or `**<text>**` for __bold__
1714- `___<text>___` or `***<text>***` for ___italic and bold___
1815
19−```
20−[
21−***1*** 2 __3__
22− 3 _2_ 8
23−]
24−```
25−![](images/mat2.png)
26−
27−You can use `_` to leave an empty space in the matrix
28−
29−```
30−[
31−***1*** 2 __3__ | _
32− _ _2_ 8 | 4
33−]
34−```
35−![](images/mat3.png)
36−
37−Newlines separate `elements` of your expressions.
38−`//` denotes the start of a normal comment. It is not present in the output.
39−
40−```
41−[
42−***1*** 2 __3__ | _ // This is a normal comment
43−_ _2_ 8 | 4
44−]
45−
46−1⊕=0
47−->
48−a=2b
49−
50−// This is also a normal comment
51−
52−[
53−1 2
54−5 3
55−]
56−```
57−![](images/mat4.png)
58−
59−`#` is used to make a `separator` comment. It separates your expressions into different `<math>` elements and is converted to an `xml` comment in the output document.
16+`***1*** 2 __3__
17+3 _2_ 8`
18+produces
19+![](images/mat2.png width=400)
6020
6121## Usage
62−`mathdown -b:r -i input.mth -o output.xml`
22+`mathdown -i input.mth -o output.xml`
6323
6424### Parameters
6525- `-i <file path>` Specifies the input path
6626- `-o <file path>` Specifies the output pathfile
67−- `-b:s` Uses square brackets
68−- `-b:r` Uses round brackets
69−- `-b:l` Uses line brackets
27+- `-s` Uses square brackets
28+- `-r` Uses round brackets
images/mat1.png

Binary file not shown.

images/mat2.png

Binary file not shown.

images/mat3.pngdeleted

Binary file not shown.

images/mat4.pngdeleted

Binary file not shown.