on master help sign in
9 files changed+685
since splitsnapshots
unifiedsplit
.gitignore+8 Mathdown/Mathdown.xcodeproj/project.pbxproj+284 Mathdown/Mathdown.xcodeproj/project.xcworkspace/contents.xcworkspacedata+7 Mathdown/Mathdown/main.swift+319 README.md+67 images/mat1.png images/mat2.png images/mat3.png images/mat4.png
.gitignore+8
@@ -65,3 +65,11 @@ fastlane/report.xml
6565fastlane/Preview.html
6666fastlane/screenshots
6767fastlane/test_output
68+
69+
70+# Custom
71+.DS_Store
72+Source/Application.h
73+*.xcodeproj/*
74+!*.xcodeproj/project.pbxproj
75+!*.xcodeproj/xcshareddata
Mathdown/Mathdown.xcodeproj/project.pbxprojnew file+284
@@ -0,0 +1,284 @@
1+// !$*UTF8*$!
2+{
3+ archiveVersion = 1;
4+ classes = {
5+ };
6+ objectVersion = 48;
7+ objects = {
8+
9+/* Begin PBXBuildFile section */
10+ 09ED4FDB1F6995E200289153 /* main.swift in Sources */ = {isa = PBXBuildFile; fileRef = 09ED4FDA1F6995E200289153 /* main.swift */; };
11+/* End PBXBuildFile section */
12+
13+/* Begin PBXCopyFilesBuildPhase section */
14+ 09ED4FD51F6995E200289153 /* CopyFiles */ = {
15+ isa = PBXCopyFilesBuildPhase;
16+ buildActionMask = 2147483647;
17+ dstPath = /usr/share/man/man1/;
18+ dstSubfolderSpec = 0;
19+ files = (
20+ );
21+ runOnlyForDeploymentPostprocessing = 1;
22+ };
23+/* End PBXCopyFilesBuildPhase section */
24+
25+/* Begin PBXFileReference section */
26+ 09ED4FD71F6995E200289153 /* Mathdown */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = Mathdown; sourceTree = BUILT_PRODUCTS_DIR; };
27+ 09ED4FDA1F6995E200289153 /* main.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = main.swift; sourceTree = "<group>"; };
28+ 09ED4FE11F69AD3800289153 /* README.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; name = README.md; path = ../README.md; sourceTree = "<group>"; };
29+ 09ED4FE21F69B1B300289153 /* .gitignore */ = {isa = PBXFileReference; lastKnownFileType = text; name = .gitignore; path = ../.gitignore; sourceTree = "<group>"; };
30+/* End PBXFileReference section */
31+
32+/* Begin PBXFrameworksBuildPhase section */
33+ 09ED4FD41F6995E200289153 /* Frameworks */ = {
34+ isa = PBXFrameworksBuildPhase;
35+ buildActionMask = 2147483647;
36+ files = (
37+ );
38+ runOnlyForDeploymentPostprocessing = 0;
39+ };
40+/* End PBXFrameworksBuildPhase section */
41+
42+/* Begin PBXGroup section */
43+ 09ED4FCE1F6995E200289153 = {
44+ isa = PBXGroup;
45+ children = (
46+ 09ED4FE21F69B1B300289153 /* .gitignore */,
47+ 09ED4FE11F69AD3800289153 /* README.md */,
48+ 09ED4FD91F6995E200289153 /* Mathdown */,
49+ 09ED4FD81F6995E200289153 /* Products */,
50+ );
51+ sourceTree = "<group>";
52+ };
53+ 09ED4FD81F6995E200289153 /* Products */ = {
54+ isa = PBXGroup;
55+ children = (
56+ 09ED4FD71F6995E200289153 /* Mathdown */,
57+ );
58+ name = Products;
59+ sourceTree = "<group>";
60+ };
61+ 09ED4FD91F6995E200289153 /* Mathdown */ = {
62+ isa = PBXGroup;
63+ children = (
64+ 09ED4FDA1F6995E200289153 /* main.swift */,
65+ );
66+ path = Mathdown;
67+ sourceTree = "<group>";
68+ };
69+/* End PBXGroup section */
70+
71+/* Begin PBXNativeTarget section */
72+ 09ED4FD61F6995E200289153 /* Mathdown */ = {
73+ isa = PBXNativeTarget;
74+ buildConfigurationList = 09ED4FDE1F6995E200289153 /* Build configuration list for PBXNativeTarget "Mathdown" */;
75+ buildPhases = (
76+ 09ED4FD31F6995E200289153 /* Sources */,
77+ 09ED4FD41F6995E200289153 /* Frameworks */,
78+ 09ED4FD51F6995E200289153 /* CopyFiles */,
79+ );
80+ buildRules = (
81+ );
82+ dependencies = (
83+ );
84+ name = Mathdown;
85+ productName = Mathdown;
86+ productReference = 09ED4FD71F6995E200289153 /* Mathdown */;
87+ productType = "com.apple.product-type.tool";
88+ };
89+/* End PBXNativeTarget section */
90+
91+/* Begin PBXProject section */
92+ 09ED4FCF1F6995E200289153 /* Project object */ = {
93+ isa = PBXProject;
94+ attributes = {
95+ LastSwiftUpdateCheck = 0900;
96+ LastUpgradeCheck = 0900;
97+ ORGANIZATIONNAME = "Ilya Kos";
98+ TargetAttributes = {
99+ 09ED4FD61F6995E200289153 = {
100+ CreatedOnToolsVersion = 9.0;
101+ ProvisioningStyle = Automatic;
102+ };
103+ };
104+ };
105+ buildConfigurationList = 09ED4FD21F6995E200289153 /* Build configuration list for PBXProject "Mathdown" */;
106+ compatibilityVersion = "Xcode 8.0";
107+ developmentRegion = en;
108+ hasScannedForEncodings = 0;
109+ knownRegions = (
110+ en,
111+ );
112+ mainGroup = 09ED4FCE1F6995E200289153;
113+ productRefGroup = 09ED4FD81F6995E200289153 /* Products */;
114+ projectDirPath = "";
115+ projectRoot = "";
116+ targets = (
117+ 09ED4FD61F6995E200289153 /* Mathdown */,
118+ );
119+ };
120+/* End PBXProject section */
121+
122+/* Begin PBXSourcesBuildPhase section */
123+ 09ED4FD31F6995E200289153 /* Sources */ = {
124+ isa = PBXSourcesBuildPhase;
125+ buildActionMask = 2147483647;
126+ files = (
127+ 09ED4FDB1F6995E200289153 /* main.swift in Sources */,
128+ );
129+ runOnlyForDeploymentPostprocessing = 0;
130+ };
131+/* End PBXSourcesBuildPhase section */
132+
133+/* Begin XCBuildConfiguration section */
134+ 09ED4FDC1F6995E200289153 /* Debug */ = {
135+ isa = XCBuildConfiguration;
136+ buildSettings = {
137+ ALWAYS_SEARCH_USER_PATHS = NO;
138+ CLANG_ANALYZER_NONNULL = YES;
139+ CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
140+ CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
141+ CLANG_CXX_LIBRARY = "libc++";
142+ CLANG_ENABLE_MODULES = YES;
143+ CLANG_ENABLE_OBJC_ARC = YES;
144+ CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
145+ CLANG_WARN_BOOL_CONVERSION = YES;
146+ CLANG_WARN_COMMA = YES;
147+ CLANG_WARN_CONSTANT_CONVERSION = YES;
148+ CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
149+ CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
150+ CLANG_WARN_EMPTY_BODY = YES;
151+ CLANG_WARN_ENUM_CONVERSION = YES;
152+ CLANG_WARN_INFINITE_RECURSION = YES;
153+ CLANG_WARN_INT_CONVERSION = YES;
154+ CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
155+ CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
156+ CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
157+ CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
158+ CLANG_WARN_STRICT_PROTOTYPES = YES;
159+ CLANG_WARN_SUSPICIOUS_MOVE = YES;
160+ CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
161+ CLANG_WARN_UNREACHABLE_CODE = YES;
162+ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
163+ CODE_SIGN_IDENTITY = "Mac Developer";
164+ COPY_PHASE_STRIP = NO;
165+ DEBUG_INFORMATION_FORMAT = dwarf;
166+ ENABLE_STRICT_OBJC_MSGSEND = YES;
167+ ENABLE_TESTABILITY = YES;
168+ GCC_C_LANGUAGE_STANDARD = gnu11;
169+ GCC_DYNAMIC_NO_PIC = NO;
170+ GCC_NO_COMMON_BLOCKS = YES;
171+ GCC_OPTIMIZATION_LEVEL = 0;
172+ GCC_PREPROCESSOR_DEFINITIONS = (
173+ "DEBUG=1",
174+ "$(inherited)",
175+ );
176+ GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
177+ GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
178+ GCC_WARN_UNDECLARED_SELECTOR = YES;
179+ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
180+ GCC_WARN_UNUSED_FUNCTION = YES;
181+ GCC_WARN_UNUSED_VARIABLE = YES;
182+ MACOSX_DEPLOYMENT_TARGET = 10.12;
183+ MTL_ENABLE_DEBUG_INFO = YES;
184+ ONLY_ACTIVE_ARCH = YES;
185+ SDKROOT = macosx;
186+ SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;
187+ SWIFT_OPTIMIZATION_LEVEL = "-Onone";
188+ };
189+ name = Debug;
190+ };
191+ 09ED4FDD1F6995E200289153 /* Release */ = {
192+ isa = XCBuildConfiguration;
193+ buildSettings = {
194+ ALWAYS_SEARCH_USER_PATHS = NO;
195+ CLANG_ANALYZER_NONNULL = YES;
196+ CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
197+ CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
198+ CLANG_CXX_LIBRARY = "libc++";
199+ CLANG_ENABLE_MODULES = YES;
200+ CLANG_ENABLE_OBJC_ARC = YES;
201+ CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
202+ CLANG_WARN_BOOL_CONVERSION = YES;
203+ CLANG_WARN_COMMA = YES;
204+ CLANG_WARN_CONSTANT_CONVERSION = YES;
205+ CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
206+ CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
207+ CLANG_WARN_EMPTY_BODY = YES;
208+ CLANG_WARN_ENUM_CONVERSION = YES;
209+ CLANG_WARN_INFINITE_RECURSION = YES;
210+ CLANG_WARN_INT_CONVERSION = YES;
211+ CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
212+ CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
213+ CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
214+ CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
215+ CLANG_WARN_STRICT_PROTOTYPES = YES;
216+ CLANG_WARN_SUSPICIOUS_MOVE = YES;
217+ CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
218+ CLANG_WARN_UNREACHABLE_CODE = YES;
219+ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
220+ CODE_SIGN_IDENTITY = "Mac Developer";
221+ COPY_PHASE_STRIP = NO;
222+ DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
223+ ENABLE_NS_ASSERTIONS = NO;
224+ ENABLE_STRICT_OBJC_MSGSEND = YES;
225+ GCC_C_LANGUAGE_STANDARD = gnu11;
226+ GCC_NO_COMMON_BLOCKS = YES;
227+ GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
228+ GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
229+ GCC_WARN_UNDECLARED_SELECTOR = YES;
230+ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
231+ GCC_WARN_UNUSED_FUNCTION = YES;
232+ GCC_WARN_UNUSED_VARIABLE = YES;
233+ MACOSX_DEPLOYMENT_TARGET = 10.12;
234+ MTL_ENABLE_DEBUG_INFO = NO;
235+ SDKROOT = macosx;
236+ SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule";
237+ };
238+ name = Release;
239+ };
240+ 09ED4FDF1F6995E200289153 /* Debug */ = {
241+ isa = XCBuildConfiguration;
242+ buildSettings = {
243+ CODE_SIGN_STYLE = Automatic;
244+ DEVELOPMENT_TEAM = 8J63JZYYHZ;
245+ PRODUCT_NAME = "$(TARGET_NAME)";
246+ SWIFT_VERSION = 4.0;
247+ };
248+ name = Debug;
249+ };
250+ 09ED4FE01F6995E200289153 /* Release */ = {
251+ isa = XCBuildConfiguration;
252+ buildSettings = {
253+ CODE_SIGN_STYLE = Automatic;
254+ DEVELOPMENT_TEAM = 8J63JZYYHZ;
255+ PRODUCT_NAME = "$(TARGET_NAME)";
256+ SWIFT_VERSION = 4.0;
257+ };
258+ name = Release;
259+ };
260+/* End XCBuildConfiguration section */
261+
262+/* Begin XCConfigurationList section */
263+ 09ED4FD21F6995E200289153 /* Build configuration list for PBXProject "Mathdown" */ = {
264+ isa = XCConfigurationList;
265+ buildConfigurations = (
266+ 09ED4FDC1F6995E200289153 /* Debug */,
267+ 09ED4FDD1F6995E200289153 /* Release */,
268+ );
269+ defaultConfigurationIsVisible = 0;
270+ defaultConfigurationName = Release;
271+ };
272+ 09ED4FDE1F6995E200289153 /* Build configuration list for PBXNativeTarget "Mathdown" */ = {
273+ isa = XCConfigurationList;
274+ buildConfigurations = (
275+ 09ED4FDF1F6995E200289153 /* Debug */,
276+ 09ED4FE01F6995E200289153 /* Release */,
277+ );
278+ defaultConfigurationIsVisible = 0;
279+ defaultConfigurationName = Release;
280+ };
281+/* End XCConfigurationList section */
282+ };
283+ rootObject = 09ED4FCF1F6995E200289153 /* Project object */;
284+}
Mathdown/Mathdown.xcodeproj/project.xcworkspace/contents.xcworkspacedatanew file+7
@@ -0,0 +1,7 @@
1+<?xml version="1.0" encoding="UTF-8"?>
2+<Workspace
3+ version = "1.0">
4+ <FileRef
5+ location = "self:Mathdown.xcodeproj">
6+ </FileRef>
7+</Workspace>
Mathdown/Mathdown/main.swiftnew file+319
@@ -0,0 +1,319 @@
1+//
2+// main.swift
3+// Mathdown
4+//
5+// Created by Ilya Kos on 9/13/17.
6+// Copyright © 2017 Ilya Kos. All rights reserved.
7+//
8+
9+import Foundation
10+
11+typealias Lines = [String]
12+typealias Element = [String]
13+let commentChars = CharacterSet.init(charactersIn: "#/")
14+let styleCharecters = CharacterSet.init(charactersIn: "_*")
15+
16+
17+enum BracketStyle {
18+ case square
19+ case round
20+ case line
21+ var opening: Character {
22+ switch self {
23+ case .round:
24+ return "("
25+ case .square:
26+ return "["
27+ case .line:
28+ return "|"
29+ }
30+ }
31+ var closing: Character {
32+ switch self {
33+ case .round:
34+ return ")"
35+ case .square:
36+ return "]"
37+ case .line:
38+ return "|"
39+ }
40+ }
41+}
42+
43+var style: BracketStyle = .round
44+var outputUrl: URL!
45+var inputUrl: URL! {
46+ didSet {
47+ outputUrl = outputUrl ?? inputUrl.deletingPathExtension().appendingPathExtension("xml")
48+ }
49+}
50+
51+var args = CommandLine.arguments.dropFirst()
52+switch args.count {
53+case 0:
54+ print("You didn't provide an input file")
55+ exit(0)
56+case 1:
57+ inputUrl = URL(fileURLWithPath: args.first!)
58+default:
59+ func processArgs() {
60+ if let arg = args.popFirst() {
61+ switch arg {
62+ case "-i":
63+ if let surl = args.popFirst() {
64+ inputUrl = URL(fileURLWithPath: surl)
65+ }
66+ case "-o":
67+ if let surl = args.popFirst() {
68+ outputUrl = URL(fileURLWithPath: surl)
69+ }
70+ case "-b:s":
71+ style = .square
72+ case "-b:r":
73+ style = .round
74+ case "-b:l":
75+ style = .line
76+ default:
77+ return
78+ }
79+ processArgs()
80+ }
81+ }
82+ processArgs()
83+}
84+enum ElementStyle: String {
85+ case none = ""
86+ case bold = "bold"
87+ case italic = "italic"
88+ case boldItalic = "bold-italic"
89+}
90+extension String.SubSequence {
91+ var style: ElementStyle {
92+ let num = self.prefix(while: {styleCharecters.contains($0.unicodeScalars.first!)}).count
93+ switch num {
94+ case 0:
95+ return .none
96+ case 1:
97+ return .italic
98+ case 2:
99+ return .bold
100+ default:
101+ return .boldItalic
102+ }
103+ }
104+ func trimmingStyleCharecters() -> String {
105+ return self.trimmingCharacters(in: styleCharecters)
106+ }
107+}
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+ }
151+
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...])
186+ }
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
204+ }
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:
217+ 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>")
283+ }
284+ }
285+ first = false
286+ }
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>")
309+ }
310+ out.append("</mtable></math>")
311+ return out
312+}
313+
314+do {
315+ let inp = try String.init(contentsOf: inputUrl)
316+ try process(mth: inp).write(to: outputUrl, atomically: true, encoding: .utf8)
317+} catch {
318+ print("Invalid file")
319+}
README.md+67
@@ -1,2 +1,69 @@
11# Mathdown
22A lightweight syntax for matrices.
3+Outputs [MathML](https://en.wikipedia.org/wiki/MathML) format.
4+
5+## Syntax
6+```
7+[
8+1 2 3
9+3 2 8
10+]
11+```
12+![](images/mat1.png)
13+
14+You can also use [Markdown](https://en.wikipedia.org/wiki/Markdown)-style text emphasis
15+- `_<text>_` or `*<text>*` for _italic_
16+- `__<text>__` or `**<text>**` for __bold__
17+- `___<text>___` or `***<text>***` for ___italic and bold___
18+
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.
60+
61+## Usage
62+`mathdown -b:r -i input.mth -o output.xml`
63+
64+### Parameters
65+- `-i <file path>` Specifies the input path
66+- `-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
images/mat1.pngnew file

Binary file not shown.

images/mat2.pngnew file

Binary file not shown.

images/mat3.pngnew file

Binary file not shown.

images/mat4.pngnew file

Binary file not shown.