├── MarkNoteParser
├── MarkNoteParser.xcodeproj
│ ├── project.pbxproj
│ ├── project.xcworkspace
│ │ ├── contents.xcworkspacedata
│ │ ├── xcshareddata
│ │ │ └── MarkNoteParser.xccheckout
│ │ └── xcuserdata
│ │ │ └── bill.xcuserdatad
│ │ │ └── UserInterfaceState.xcuserstate
│ └── xcuserdata
│ │ └── bill.xcuserdatad
│ │ ├── xcdebugger
│ │ └── Breakpoints_v2.xcbkptlist
│ │ └── xcschemes
│ │ ├── MarkNoteParser.xcscheme
│ │ └── xcschememanagement.plist
├── MarkNoteParser
│ ├── AppDelegate.swift
│ ├── Base.lproj
│ │ ├── LaunchScreen.xib
│ │ └── Main.storyboard
│ ├── Images.xcassets
│ │ └── AppIcon.appiconset
│ │ │ └── Contents.json
│ ├── Info.plist
│ ├── MarkNoteParser.swift
│ ├── ViewController.swift
│ └── util
│ │ └── StringExtensions.swift
└── MarkNoteParserTests
│ ├── Info.plist
│ └── MarkNoteParserTests.swift
└── README.md
/MarkNoteParser/MarkNoteParser.xcodeproj/project.pbxproj:
--------------------------------------------------------------------------------
1 | // !$*UTF8*$!
2 | {
3 | archiveVersion = 1;
4 | classes = {
5 | };
6 | objectVersion = 46;
7 | objects = {
8 |
9 | /* Begin PBXBuildFile section */
10 | A9983A841B6A642D00B0AB99 /* MarkNoteParser.swift in Sources */ = {isa = PBXBuildFile; fileRef = A9983A831B6A642D00B0AB99 /* MarkNoteParser.swift */; };
11 | A9C1B7441B63295C00A89EFD /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = A9C1B7431B63295C00A89EFD /* AppDelegate.swift */; };
12 | A9C1B7461B63295C00A89EFD /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = A9C1B7451B63295C00A89EFD /* ViewController.swift */; };
13 | A9C1B7491B63295C00A89EFD /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = A9C1B7471B63295C00A89EFD /* Main.storyboard */; };
14 | A9C1B74B1B63295C00A89EFD /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = A9C1B74A1B63295C00A89EFD /* Images.xcassets */; };
15 | A9C1B74E1B63295C00A89EFD /* LaunchScreen.xib in Resources */ = {isa = PBXBuildFile; fileRef = A9C1B74C1B63295C00A89EFD /* LaunchScreen.xib */; };
16 | A9C1B75A1B63295C00A89EFD /* MarkNoteParserTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = A9C1B7591B63295C00A89EFD /* MarkNoteParserTests.swift */; };
17 | A9C1B7671B63899E00A89EFD /* StringExtensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = A9C1B7661B63899E00A89EFD /* StringExtensions.swift */; };
18 | /* End PBXBuildFile section */
19 |
20 | /* Begin PBXContainerItemProxy section */
21 | A9C1B7541B63295C00A89EFD /* PBXContainerItemProxy */ = {
22 | isa = PBXContainerItemProxy;
23 | containerPortal = A9C1B7361B63295C00A89EFD /* Project object */;
24 | proxyType = 1;
25 | remoteGlobalIDString = A9C1B73D1B63295C00A89EFD;
26 | remoteInfo = MarkNoteParser;
27 | };
28 | /* End PBXContainerItemProxy section */
29 |
30 | /* Begin PBXFileReference section */
31 | A9983A831B6A642D00B0AB99 /* MarkNoteParser.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MarkNoteParser.swift; sourceTree = ""; };
32 | A9C1B73E1B63295C00A89EFD /* MarkNoteParser.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = MarkNoteParser.app; sourceTree = BUILT_PRODUCTS_DIR; };
33 | A9C1B7421B63295C00A89EFD /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; };
34 | A9C1B7431B63295C00A89EFD /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; };
35 | A9C1B7451B63295C00A89EFD /* ViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewController.swift; sourceTree = ""; };
36 | A9C1B7481B63295C00A89EFD /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; };
37 | A9C1B74A1B63295C00A89EFD /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Images.xcassets; sourceTree = ""; };
38 | A9C1B74D1B63295C00A89EFD /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/LaunchScreen.xib; sourceTree = ""; };
39 | A9C1B7531B63295C00A89EFD /* MarkNoteParserTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = MarkNoteParserTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
40 | A9C1B7581B63295C00A89EFD /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; };
41 | A9C1B7591B63295C00A89EFD /* MarkNoteParserTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MarkNoteParserTests.swift; sourceTree = ""; };
42 | A9C1B7661B63899E00A89EFD /* StringExtensions.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = StringExtensions.swift; path = util/StringExtensions.swift; sourceTree = ""; };
43 | /* End PBXFileReference section */
44 |
45 | /* Begin PBXFrameworksBuildPhase section */
46 | A9C1B73B1B63295C00A89EFD /* Frameworks */ = {
47 | isa = PBXFrameworksBuildPhase;
48 | buildActionMask = 2147483647;
49 | files = (
50 | );
51 | runOnlyForDeploymentPostprocessing = 0;
52 | };
53 | A9C1B7501B63295C00A89EFD /* Frameworks */ = {
54 | isa = PBXFrameworksBuildPhase;
55 | buildActionMask = 2147483647;
56 | files = (
57 | );
58 | runOnlyForDeploymentPostprocessing = 0;
59 | };
60 | /* End PBXFrameworksBuildPhase section */
61 |
62 | /* Begin PBXGroup section */
63 | A9C1B7351B63295C00A89EFD = {
64 | isa = PBXGroup;
65 | children = (
66 | A9C1B7401B63295C00A89EFD /* MarkNoteParser */,
67 | A9C1B7561B63295C00A89EFD /* MarkNoteParserTests */,
68 | A9C1B73F1B63295C00A89EFD /* Products */,
69 | );
70 | sourceTree = "";
71 | };
72 | A9C1B73F1B63295C00A89EFD /* Products */ = {
73 | isa = PBXGroup;
74 | children = (
75 | A9C1B73E1B63295C00A89EFD /* MarkNoteParser.app */,
76 | A9C1B7531B63295C00A89EFD /* MarkNoteParserTests.xctest */,
77 | );
78 | name = Products;
79 | sourceTree = "";
80 | };
81 | A9C1B7401B63295C00A89EFD /* MarkNoteParser */ = {
82 | isa = PBXGroup;
83 | children = (
84 | A9C1B7661B63899E00A89EFD /* StringExtensions.swift */,
85 | A9983A831B6A642D00B0AB99 /* MarkNoteParser.swift */,
86 | A9C1B7431B63295C00A89EFD /* AppDelegate.swift */,
87 | A9C1B7451B63295C00A89EFD /* ViewController.swift */,
88 | A9C1B7471B63295C00A89EFD /* Main.storyboard */,
89 | A9C1B74A1B63295C00A89EFD /* Images.xcassets */,
90 | A9C1B74C1B63295C00A89EFD /* LaunchScreen.xib */,
91 | A9C1B7411B63295C00A89EFD /* Supporting Files */,
92 | );
93 | path = MarkNoteParser;
94 | sourceTree = "";
95 | };
96 | A9C1B7411B63295C00A89EFD /* Supporting Files */ = {
97 | isa = PBXGroup;
98 | children = (
99 | A9C1B7421B63295C00A89EFD /* Info.plist */,
100 | );
101 | name = "Supporting Files";
102 | sourceTree = "";
103 | };
104 | A9C1B7561B63295C00A89EFD /* MarkNoteParserTests */ = {
105 | isa = PBXGroup;
106 | children = (
107 | A9C1B7591B63295C00A89EFD /* MarkNoteParserTests.swift */,
108 | A9C1B7571B63295C00A89EFD /* Supporting Files */,
109 | );
110 | path = MarkNoteParserTests;
111 | sourceTree = "";
112 | };
113 | A9C1B7571B63295C00A89EFD /* Supporting Files */ = {
114 | isa = PBXGroup;
115 | children = (
116 | A9C1B7581B63295C00A89EFD /* Info.plist */,
117 | );
118 | name = "Supporting Files";
119 | sourceTree = "";
120 | };
121 | /* End PBXGroup section */
122 |
123 | /* Begin PBXNativeTarget section */
124 | A9C1B73D1B63295C00A89EFD /* MarkNoteParser */ = {
125 | isa = PBXNativeTarget;
126 | buildConfigurationList = A9C1B75D1B63295C00A89EFD /* Build configuration list for PBXNativeTarget "MarkNoteParser" */;
127 | buildPhases = (
128 | A9C1B73A1B63295C00A89EFD /* Sources */,
129 | A9C1B73B1B63295C00A89EFD /* Frameworks */,
130 | A9C1B73C1B63295C00A89EFD /* Resources */,
131 | );
132 | buildRules = (
133 | );
134 | dependencies = (
135 | );
136 | name = MarkNoteParser;
137 | productName = MarkNoteParser;
138 | productReference = A9C1B73E1B63295C00A89EFD /* MarkNoteParser.app */;
139 | productType = "com.apple.product-type.application";
140 | };
141 | A9C1B7521B63295C00A89EFD /* MarkNoteParserTests */ = {
142 | isa = PBXNativeTarget;
143 | buildConfigurationList = A9C1B7601B63295C00A89EFD /* Build configuration list for PBXNativeTarget "MarkNoteParserTests" */;
144 | buildPhases = (
145 | A9C1B74F1B63295C00A89EFD /* Sources */,
146 | A9C1B7501B63295C00A89EFD /* Frameworks */,
147 | A9C1B7511B63295C00A89EFD /* Resources */,
148 | );
149 | buildRules = (
150 | );
151 | dependencies = (
152 | A9C1B7551B63295C00A89EFD /* PBXTargetDependency */,
153 | );
154 | name = MarkNoteParserTests;
155 | productName = MarkNoteParserTests;
156 | productReference = A9C1B7531B63295C00A89EFD /* MarkNoteParserTests.xctest */;
157 | productType = "com.apple.product-type.bundle.unit-test";
158 | };
159 | /* End PBXNativeTarget section */
160 |
161 | /* Begin PBXProject section */
162 | A9C1B7361B63295C00A89EFD /* Project object */ = {
163 | isa = PBXProject;
164 | attributes = {
165 | LastSwiftUpdateCheck = 0700;
166 | LastUpgradeCheck = 0640;
167 | ORGANIZATIONNAME = MarkNote;
168 | TargetAttributes = {
169 | A9C1B73D1B63295C00A89EFD = {
170 | CreatedOnToolsVersion = 6.4;
171 | };
172 | A9C1B7521B63295C00A89EFD = {
173 | CreatedOnToolsVersion = 6.4;
174 | TestTargetID = A9C1B73D1B63295C00A89EFD;
175 | };
176 | };
177 | };
178 | buildConfigurationList = A9C1B7391B63295C00A89EFD /* Build configuration list for PBXProject "MarkNoteParser" */;
179 | compatibilityVersion = "Xcode 3.2";
180 | developmentRegion = English;
181 | hasScannedForEncodings = 0;
182 | knownRegions = (
183 | en,
184 | Base,
185 | );
186 | mainGroup = A9C1B7351B63295C00A89EFD;
187 | productRefGroup = A9C1B73F1B63295C00A89EFD /* Products */;
188 | projectDirPath = "";
189 | projectRoot = "";
190 | targets = (
191 | A9C1B73D1B63295C00A89EFD /* MarkNoteParser */,
192 | A9C1B7521B63295C00A89EFD /* MarkNoteParserTests */,
193 | );
194 | };
195 | /* End PBXProject section */
196 |
197 | /* Begin PBXResourcesBuildPhase section */
198 | A9C1B73C1B63295C00A89EFD /* Resources */ = {
199 | isa = PBXResourcesBuildPhase;
200 | buildActionMask = 2147483647;
201 | files = (
202 | A9C1B7491B63295C00A89EFD /* Main.storyboard in Resources */,
203 | A9C1B74E1B63295C00A89EFD /* LaunchScreen.xib in Resources */,
204 | A9C1B74B1B63295C00A89EFD /* Images.xcassets in Resources */,
205 | );
206 | runOnlyForDeploymentPostprocessing = 0;
207 | };
208 | A9C1B7511B63295C00A89EFD /* Resources */ = {
209 | isa = PBXResourcesBuildPhase;
210 | buildActionMask = 2147483647;
211 | files = (
212 | );
213 | runOnlyForDeploymentPostprocessing = 0;
214 | };
215 | /* End PBXResourcesBuildPhase section */
216 |
217 | /* Begin PBXSourcesBuildPhase section */
218 | A9C1B73A1B63295C00A89EFD /* Sources */ = {
219 | isa = PBXSourcesBuildPhase;
220 | buildActionMask = 2147483647;
221 | files = (
222 | A9C1B7671B63899E00A89EFD /* StringExtensions.swift in Sources */,
223 | A9983A841B6A642D00B0AB99 /* MarkNoteParser.swift in Sources */,
224 | A9C1B7461B63295C00A89EFD /* ViewController.swift in Sources */,
225 | A9C1B7441B63295C00A89EFD /* AppDelegate.swift in Sources */,
226 | );
227 | runOnlyForDeploymentPostprocessing = 0;
228 | };
229 | A9C1B74F1B63295C00A89EFD /* Sources */ = {
230 | isa = PBXSourcesBuildPhase;
231 | buildActionMask = 2147483647;
232 | files = (
233 | A9C1B75A1B63295C00A89EFD /* MarkNoteParserTests.swift in Sources */,
234 | );
235 | runOnlyForDeploymentPostprocessing = 0;
236 | };
237 | /* End PBXSourcesBuildPhase section */
238 |
239 | /* Begin PBXTargetDependency section */
240 | A9C1B7551B63295C00A89EFD /* PBXTargetDependency */ = {
241 | isa = PBXTargetDependency;
242 | target = A9C1B73D1B63295C00A89EFD /* MarkNoteParser */;
243 | targetProxy = A9C1B7541B63295C00A89EFD /* PBXContainerItemProxy */;
244 | };
245 | /* End PBXTargetDependency section */
246 |
247 | /* Begin PBXVariantGroup section */
248 | A9C1B7471B63295C00A89EFD /* Main.storyboard */ = {
249 | isa = PBXVariantGroup;
250 | children = (
251 | A9C1B7481B63295C00A89EFD /* Base */,
252 | );
253 | name = Main.storyboard;
254 | sourceTree = "";
255 | };
256 | A9C1B74C1B63295C00A89EFD /* LaunchScreen.xib */ = {
257 | isa = PBXVariantGroup;
258 | children = (
259 | A9C1B74D1B63295C00A89EFD /* Base */,
260 | );
261 | name = LaunchScreen.xib;
262 | sourceTree = "";
263 | };
264 | /* End PBXVariantGroup section */
265 |
266 | /* Begin XCBuildConfiguration section */
267 | A9C1B75B1B63295C00A89EFD /* Debug */ = {
268 | isa = XCBuildConfiguration;
269 | buildSettings = {
270 | ALWAYS_SEARCH_USER_PATHS = NO;
271 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
272 | CLANG_CXX_LIBRARY = "libc++";
273 | CLANG_ENABLE_MODULES = YES;
274 | CLANG_ENABLE_OBJC_ARC = YES;
275 | CLANG_WARN_BOOL_CONVERSION = YES;
276 | CLANG_WARN_CONSTANT_CONVERSION = YES;
277 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
278 | CLANG_WARN_EMPTY_BODY = YES;
279 | CLANG_WARN_ENUM_CONVERSION = YES;
280 | CLANG_WARN_INT_CONVERSION = YES;
281 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
282 | CLANG_WARN_UNREACHABLE_CODE = YES;
283 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
284 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
285 | COPY_PHASE_STRIP = NO;
286 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
287 | ENABLE_STRICT_OBJC_MSGSEND = YES;
288 | GCC_C_LANGUAGE_STANDARD = gnu99;
289 | GCC_DYNAMIC_NO_PIC = NO;
290 | GCC_NO_COMMON_BLOCKS = YES;
291 | GCC_OPTIMIZATION_LEVEL = 0;
292 | GCC_PREPROCESSOR_DEFINITIONS = (
293 | "DEBUG=1",
294 | "$(inherited)",
295 | );
296 | GCC_SYMBOLS_PRIVATE_EXTERN = NO;
297 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
298 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
299 | GCC_WARN_UNDECLARED_SELECTOR = YES;
300 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
301 | GCC_WARN_UNUSED_FUNCTION = YES;
302 | GCC_WARN_UNUSED_VARIABLE = YES;
303 | IPHONEOS_DEPLOYMENT_TARGET = 8.4;
304 | MTL_ENABLE_DEBUG_INFO = YES;
305 | ONLY_ACTIVE_ARCH = YES;
306 | SDKROOT = iphoneos;
307 | SWIFT_OPTIMIZATION_LEVEL = "-Onone";
308 | };
309 | name = Debug;
310 | };
311 | A9C1B75C1B63295C00A89EFD /* Release */ = {
312 | isa = XCBuildConfiguration;
313 | buildSettings = {
314 | ALWAYS_SEARCH_USER_PATHS = NO;
315 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
316 | CLANG_CXX_LIBRARY = "libc++";
317 | CLANG_ENABLE_MODULES = YES;
318 | CLANG_ENABLE_OBJC_ARC = YES;
319 | CLANG_WARN_BOOL_CONVERSION = YES;
320 | CLANG_WARN_CONSTANT_CONVERSION = YES;
321 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
322 | CLANG_WARN_EMPTY_BODY = YES;
323 | CLANG_WARN_ENUM_CONVERSION = YES;
324 | CLANG_WARN_INT_CONVERSION = YES;
325 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
326 | CLANG_WARN_UNREACHABLE_CODE = YES;
327 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
328 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
329 | COPY_PHASE_STRIP = NO;
330 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
331 | ENABLE_NS_ASSERTIONS = NO;
332 | ENABLE_STRICT_OBJC_MSGSEND = YES;
333 | GCC_C_LANGUAGE_STANDARD = gnu99;
334 | GCC_NO_COMMON_BLOCKS = YES;
335 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
336 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
337 | GCC_WARN_UNDECLARED_SELECTOR = YES;
338 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
339 | GCC_WARN_UNUSED_FUNCTION = YES;
340 | GCC_WARN_UNUSED_VARIABLE = YES;
341 | IPHONEOS_DEPLOYMENT_TARGET = 8.4;
342 | MTL_ENABLE_DEBUG_INFO = NO;
343 | SDKROOT = iphoneos;
344 | VALIDATE_PRODUCT = YES;
345 | };
346 | name = Release;
347 | };
348 | A9C1B75E1B63295C00A89EFD /* Debug */ = {
349 | isa = XCBuildConfiguration;
350 | buildSettings = {
351 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
352 | INFOPLIST_FILE = MarkNoteParser/Info.plist;
353 | IPHONEOS_DEPLOYMENT_TARGET = 7.1;
354 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
355 | PRODUCT_NAME = "$(TARGET_NAME)";
356 | };
357 | name = Debug;
358 | };
359 | A9C1B75F1B63295C00A89EFD /* Release */ = {
360 | isa = XCBuildConfiguration;
361 | buildSettings = {
362 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
363 | INFOPLIST_FILE = MarkNoteParser/Info.plist;
364 | IPHONEOS_DEPLOYMENT_TARGET = 7.1;
365 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
366 | PRODUCT_NAME = "$(TARGET_NAME)";
367 | };
368 | name = Release;
369 | };
370 | A9C1B7611B63295C00A89EFD /* Debug */ = {
371 | isa = XCBuildConfiguration;
372 | buildSettings = {
373 | BUNDLE_LOADER = "$(TEST_HOST)";
374 | FRAMEWORK_SEARCH_PATHS = (
375 | "$(SDKROOT)/Developer/Library/Frameworks",
376 | "$(inherited)",
377 | );
378 | GCC_PREPROCESSOR_DEFINITIONS = (
379 | "DEBUG=1",
380 | "$(inherited)",
381 | );
382 | INFOPLIST_FILE = MarkNoteParserTests/Info.plist;
383 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
384 | PRODUCT_NAME = "$(TARGET_NAME)";
385 | TEST_HOST = "$(BUILT_PRODUCTS_DIR)/MarkNoteParser.app/MarkNoteParser";
386 | };
387 | name = Debug;
388 | };
389 | A9C1B7621B63295C00A89EFD /* Release */ = {
390 | isa = XCBuildConfiguration;
391 | buildSettings = {
392 | BUNDLE_LOADER = "$(TEST_HOST)";
393 | FRAMEWORK_SEARCH_PATHS = (
394 | "$(SDKROOT)/Developer/Library/Frameworks",
395 | "$(inherited)",
396 | );
397 | INFOPLIST_FILE = MarkNoteParserTests/Info.plist;
398 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
399 | PRODUCT_NAME = "$(TARGET_NAME)";
400 | TEST_HOST = "$(BUILT_PRODUCTS_DIR)/MarkNoteParser.app/MarkNoteParser";
401 | };
402 | name = Release;
403 | };
404 | /* End XCBuildConfiguration section */
405 |
406 | /* Begin XCConfigurationList section */
407 | A9C1B7391B63295C00A89EFD /* Build configuration list for PBXProject "MarkNoteParser" */ = {
408 | isa = XCConfigurationList;
409 | buildConfigurations = (
410 | A9C1B75B1B63295C00A89EFD /* Debug */,
411 | A9C1B75C1B63295C00A89EFD /* Release */,
412 | );
413 | defaultConfigurationIsVisible = 0;
414 | defaultConfigurationName = Release;
415 | };
416 | A9C1B75D1B63295C00A89EFD /* Build configuration list for PBXNativeTarget "MarkNoteParser" */ = {
417 | isa = XCConfigurationList;
418 | buildConfigurations = (
419 | A9C1B75E1B63295C00A89EFD /* Debug */,
420 | A9C1B75F1B63295C00A89EFD /* Release */,
421 | );
422 | defaultConfigurationIsVisible = 0;
423 | defaultConfigurationName = Release;
424 | };
425 | A9C1B7601B63295C00A89EFD /* Build configuration list for PBXNativeTarget "MarkNoteParserTests" */ = {
426 | isa = XCConfigurationList;
427 | buildConfigurations = (
428 | A9C1B7611B63295C00A89EFD /* Debug */,
429 | A9C1B7621B63295C00A89EFD /* Release */,
430 | );
431 | defaultConfigurationIsVisible = 0;
432 | defaultConfigurationName = Release;
433 | };
434 | /* End XCConfigurationList section */
435 | };
436 | rootObject = A9C1B7361B63295C00A89EFD /* Project object */;
437 | }
438 |
--------------------------------------------------------------------------------
/MarkNoteParser/MarkNoteParser.xcodeproj/project.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/MarkNoteParser/MarkNoteParser.xcodeproj/project.xcworkspace/xcshareddata/MarkNoteParser.xccheckout:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | IDESourceControlProjectFavoriteDictionaryKey
6 |
7 | IDESourceControlProjectIdentifier
8 | E5FACBFE-E429-4C26-A35F-8ADB1FD92F92
9 | IDESourceControlProjectName
10 | MarkNoteParser
11 | IDESourceControlProjectOriginsDictionary
12 |
13 | 13482B32E7921A09FAE3E7576EA70FE0A3EF5154
14 | https://marknote%2540aliyun.com:ylbylb%254020YLB@github.com/marknote/MarknoteParser.git
15 |
16 | IDESourceControlProjectPath
17 | MarkNoteParser/MarkNoteParser.xcodeproj
18 | IDESourceControlProjectRelativeInstallPathDictionary
19 |
20 | 13482B32E7921A09FAE3E7576EA70FE0A3EF5154
21 | ../../..
22 |
23 | IDESourceControlProjectURL
24 | https://marknote%2540aliyun.com:ylbylb%254020YLB@github.com/marknote/MarknoteParser.git
25 | IDESourceControlProjectVersion
26 | 111
27 | IDESourceControlProjectWCCIdentifier
28 | 13482B32E7921A09FAE3E7576EA70FE0A3EF5154
29 | IDESourceControlProjectWCConfigurations
30 |
31 |
32 | IDESourceControlRepositoryExtensionIdentifierKey
33 | public.vcs.git
34 | IDESourceControlWCCIdentifierKey
35 | 13482B32E7921A09FAE3E7576EA70FE0A3EF5154
36 | IDESourceControlWCCName
37 | MarkNoteParser
38 |
39 |
40 |
41 |
42 |
--------------------------------------------------------------------------------
/MarkNoteParser/MarkNoteParser.xcodeproj/project.xcworkspace/xcuserdata/bill.xcuserdatad/UserInterfaceState.xcuserstate:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/marknote/MarknoteParser/3897f14b98d2eb4a28921dde5ea3a3d38f0e9729/MarkNoteParser/MarkNoteParser.xcodeproj/project.xcworkspace/xcuserdata/bill.xcuserdatad/UserInterfaceState.xcuserstate
--------------------------------------------------------------------------------
/MarkNoteParser/MarkNoteParser.xcodeproj/xcuserdata/bill.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
--------------------------------------------------------------------------------
/MarkNoteParser/MarkNoteParser.xcodeproj/xcuserdata/bill.xcuserdatad/xcschemes/MarkNoteParser.xcscheme:
--------------------------------------------------------------------------------
1 |
2 |
5 |
8 |
9 |
15 |
21 |
22 |
23 |
29 |
35 |
36 |
37 |
38 |
39 |
44 |
45 |
47 |
53 |
54 |
55 |
56 |
57 |
63 |
64 |
65 |
66 |
75 |
77 |
83 |
84 |
85 |
86 |
87 |
88 |
94 |
96 |
102 |
103 |
104 |
105 |
107 |
108 |
111 |
112 |
113 |
--------------------------------------------------------------------------------
/MarkNoteParser/MarkNoteParser.xcodeproj/xcuserdata/bill.xcuserdatad/xcschemes/xcschememanagement.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | SchemeUserState
6 |
7 | MarkNoteParser.xcscheme
8 |
9 | orderHint
10 | 0
11 |
12 |
13 | SuppressBuildableAutocreation
14 |
15 | A9C1B73D1B63295C00A89EFD
16 |
17 | primary
18 |
19 |
20 | A9C1B7521B63295C00A89EFD
21 |
22 | primary
23 |
24 |
25 |
26 |
27 |
28 |
--------------------------------------------------------------------------------
/MarkNoteParser/MarkNoteParser/AppDelegate.swift:
--------------------------------------------------------------------------------
1 | /**
2 | * MarknoteParser- a markdown parser
3 | * Copyright (c) 2015, MarkNote. (MIT Licensed)
4 | * https://github.com/marknote/MarknoteParser
5 | */
6 |
7 | import UIKit
8 |
9 | @UIApplicationMain
10 | class AppDelegate: UIResponder, UIApplicationDelegate {
11 |
12 | var window: UIWindow?
13 |
14 |
15 | func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
16 | // Override point for customization after application launch.
17 | return true
18 | }
19 |
20 | func applicationWillResignActive(application: UIApplication) {
21 | // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state.
22 | // Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game.
23 | }
24 |
25 | func applicationDidEnterBackground(application: UIApplication) {
26 | // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later.
27 | // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits.
28 | }
29 |
30 | func applicationWillEnterForeground(application: UIApplication) {
31 | // Called as part of the transition from the background to the inactive state; here you can undo many of the changes made on entering the background.
32 | }
33 |
34 | func applicationDidBecomeActive(application: UIApplication) {
35 | // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface.
36 | }
37 |
38 | func applicationWillTerminate(application: UIApplication) {
39 | // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.
40 | }
41 |
42 |
43 | }
44 |
45 |
--------------------------------------------------------------------------------
/MarkNoteParser/MarkNoteParser/Base.lproj/LaunchScreen.xib:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
--------------------------------------------------------------------------------
/MarkNoteParser/MarkNoteParser/Base.lproj/Main.storyboard:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
--------------------------------------------------------------------------------
/MarkNoteParser/MarkNoteParser/Images.xcassets/AppIcon.appiconset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "iphone",
5 | "size" : "29x29",
6 | "scale" : "2x"
7 | },
8 | {
9 | "idiom" : "iphone",
10 | "size" : "29x29",
11 | "scale" : "3x"
12 | },
13 | {
14 | "idiom" : "iphone",
15 | "size" : "40x40",
16 | "scale" : "2x"
17 | },
18 | {
19 | "idiom" : "iphone",
20 | "size" : "40x40",
21 | "scale" : "3x"
22 | },
23 | {
24 | "idiom" : "iphone",
25 | "size" : "60x60",
26 | "scale" : "2x"
27 | },
28 | {
29 | "idiom" : "iphone",
30 | "size" : "60x60",
31 | "scale" : "3x"
32 | }
33 | ],
34 | "info" : {
35 | "version" : 1,
36 | "author" : "xcode"
37 | }
38 | }
--------------------------------------------------------------------------------
/MarkNoteParser/MarkNoteParser/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | en
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIdentifier
10 | MarkNote.$(PRODUCT_NAME:rfc1034identifier)
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | $(PRODUCT_NAME)
15 | CFBundlePackageType
16 | APPL
17 | CFBundleShortVersionString
18 | 1.0
19 | CFBundleSignature
20 | ????
21 | CFBundleVersion
22 | 1
23 | LSRequiresIPhoneOS
24 |
25 | UILaunchStoryboardName
26 | LaunchScreen
27 | UIMainStoryboardFile
28 | Main
29 | UIRequiredDeviceCapabilities
30 |
31 | armv7
32 |
33 | UISupportedInterfaceOrientations
34 |
35 | UIInterfaceOrientationPortrait
36 | UIInterfaceOrientationLandscapeLeft
37 | UIInterfaceOrientationLandscapeRight
38 |
39 |
40 |
41 |
--------------------------------------------------------------------------------
/MarkNoteParser/MarkNoteParser/MarkNoteParser.swift:
--------------------------------------------------------------------------------
1 | /**
2 | * MarknoteParser- a markdown parser
3 | * Copyright (c) 2015, MarkNote. (MIT Licensed)
4 | * https://github.com/marknote/MarknoteParser
5 | */
6 |
7 | import Foundation
8 |
9 | public class MarkNoteParser: NSObject {
10 |
11 | //var nOldBulletLevel = 0
12 | var nCurrentBulletLevel = 0
13 | var bInTable = false
14 | var output = ""
15 | var isInParagraph = false
16 | var isAfterEmptyLine = false
17 | var tableColsAlignment = [String]()
18 | let headerChar:Character = "#"
19 | var blockEndTags = [String]()
20 | var isCurrentLineNeedBr = true
21 | var arrReferenceInfo = [ReferenceDefinition]()
22 | var arrReferenceUsage = [ReferenceUsageInfo]()
23 |
24 | public static func toHtml(input:String) -> String{
25 | let instance = MarkNoteParser()
26 | instance.output = ""
27 | instance.parse(input)
28 | return instance.output
29 | }
30 |
31 |
32 | func parse (input:String){
33 | proceedHTMLTags(input)
34 | proceedReference()
35 | }
36 |
37 | func proceedReference(){
38 | for refer in self.arrReferenceUsage {
39 | let hitted = arrReferenceInfo.filter{ $0.key.lowercaseString == refer.key.lowercaseString }
40 | if hitted.count > 0 {
41 | let found = hitted[0]
42 | var actual = ""
43 | switch refer.type {
44 | case .Link:
45 | if found.url._title.length > 0 {
46 | actual = "\(refer.title) "
47 | } else {
48 | actual = "\(refer.title) "
49 | }
50 | case .Image:
51 | if found.url._title.length > 0 {
52 | actual = " "
53 |
54 | } else {
55 | actual = " "
56 | }
57 | }
58 | output = output.replaceAll(refer.placeHolder(), toStr: actual)
59 | }
60 | }
61 | }
62 |
63 |
64 | func proceedHTMLTags(input:String){
65 | var currentPos = 0
66 | let tagBegin = input.indexOf("<")
67 | if tagBegin >= 0 {
68 | if tagBegin >= 1 {
69 | proceedNoHtml(input.substring(currentPos, end: tagBegin - 1))
70 | }
71 | //currentPos = tagBegin
72 | if tagBegin < input.length - 1 {
73 | var left = input.substring(tagBegin, end: input.length - 1)
74 | var endTag = left.indexOf(">")
75 | if endTag > 0 {
76 | // found
77 | if left[endTag - 1] == "/" {
78 | //auto close:
79 | self.output += left.substringToIndex(left.startIndex.advancedBy( endTag + 1))
80 | if endTag < left.length - 2 {
81 | proceedHTMLTags(left.substringFromIndex(left.startIndex.advancedBy( endTag + 1 )))
82 | }
83 | } else {
84 | // there is a close tag
85 | currentPos = endTag
86 | if endTag <= left.length - 1 {
87 | left = left.substringFromIndex(left.startIndex.advancedBy( endTag + 1 ))
88 | endTag = left.indexOf(">")
89 | if endTag > 0 {
90 | self.output += input.substring(tagBegin, end: tagBegin + endTag + currentPos + 1) //+ left.substringToIndex(advance(left.startIndex,endTag ))
91 | if endTag < left.length - 1 {
92 | left = left.substringFromIndex(left.startIndex.advancedBy( endTag + 1 ))
93 | proceedHTMLTags(left)
94 | return
95 | }
96 | } else {
97 | proceedNoHtml(input)
98 | return
99 | }
100 | } else {
101 | output += input
102 | return
103 | }
104 | }
105 | }else {
106 | // not found
107 | proceedNoHtml(left)
108 | }
109 | }
110 | }else {
111 | proceedNoHtml(input)
112 | }
113 | }
114 | func proceedNoHtml (input:String){
115 | let preProceeded = input.replaceAll("\r\n", toStr: "\n").replaceAll("\n", toStr:" \n")
116 |
117 |
118 | //let lines = split(preProceeded){$0 == "\n"}
119 | let lines = preProceeded.componentsSeparatedByString("\n")
120 | var isInCodeBlock:Bool = false
121 |
122 |
123 | //for rawline in lines {
124 | for var i = 0; i < lines.count; i++ {
125 | isCurrentLineNeedBr = true
126 |
127 | let line = lines[i].trim()
128 |
129 | if isInCodeBlock {
130 | if line.indexOf("```") >= 0 {
131 | isInCodeBlock = false
132 | output += "\n"
133 | isCurrentLineNeedBr = false
134 | continue
135 | }else {
136 | output += line.replaceAll("\"", toStr:""") + "\n"
137 | }
138 | } else if bInTable && line.length > 0 {
139 | handleTableLine(line, isHead:false)
140 | } else {
141 | // not in block
142 | if line.length == 0 {
143 | // empty line
144 | closeTags()
145 | closeParagraph()
146 | closeTable()
147 | isAfterEmptyLine = true
148 | isCurrentLineNeedBr = false
149 | continue
150 | }else {
151 | isAfterEmptyLine = false
152 | }
153 |
154 | if line.indexOf("- ") == 0
155 | || line.indexOf("* ") == 0
156 | || line.indexOf("+ ") == 0 {
157 | if self.nCurrentBulletLevel == 0 {
158 | output += "\n"
159 | blockEndTags.append(" \n")
160 | self.nCurrentBulletLevel = 1
161 | isCurrentLineNeedBr = false
162 |
163 | }
164 | output += ""
165 | let newline = line.substring("- ".length, end: line.length - 1)
166 | handleLine(newline)
167 | output += " \n"
168 | continue
169 | } else {
170 | if self.nCurrentBulletLevel > 0 {
171 | self.nCurrentBulletLevel = 0
172 | output += "\n"
173 | }
174 | }
175 |
176 | if line.indexOf("```") == 0 {
177 | isInCodeBlock = true
178 | var cssClass = "no-highlight"
179 | if line.length > "```".length {
180 | //prettyprint javascript prettyprinted
181 | let remaining = line.substringFromIndex(line.startIndex.advancedBy( "```".length))
182 | cssClass = "prettyprint lang-\(remaining)"
183 | }
184 | output += "\n"
185 | continue // ignor current line
186 | }
187 |
188 | if i + 1 <= lines.count - 1 {
189 | let nextLine = lines[i + 1].trim()
190 | if nextLine.contains3PlusandOnlyChars("="){
191 | output += "" + line + " \n"
192 | i++
193 | continue
194 | } else if nextLine.contains3PlusandOnlyChars("-"){
195 | output += "" + line + " \n"
196 | i++
197 | continue
198 | } else if nextLine.indexOf("|") >= 0
199 | && line.indexOf("|") >= 0
200 | && nextLine.replaceAll("|", toStr: "").replaceAll("-", toStr: "").replaceAll(":", toStr: "").replaceAll(" ", toStr: "").length == 0
201 | {
202 |
203 | beginTable(nextLine)
204 | handleTableLine(line, isHead:true)
205 | i++
206 | continue
207 | }
208 | }
209 |
210 |
211 | handleLine(line)
212 | if isCurrentLineNeedBr
213 | && lines[i].length >= 2
214 | && lines[i].substringFromIndex(lines[i].startIndex.advancedBy( lines[i].length - 2)) == " " {
215 | output += " "
216 | }
217 |
218 | //output += "
"
219 | }
220 | }//end for
221 | closeTags()
222 | closeParagraph()
223 |
224 | }
225 |
226 | func handleTableLine(rawline:String, isHead:Bool) {
227 |
228 | let cols = rawline.characters.split{$0 == "|"}.map { String($0) }
229 | output += ""
230 | var i = 0
231 |
232 | for col in cols {
233 | let colAlign = self.tableColsAlignment[i]
234 | if isHead {
235 | output += colAlign.length > 0 ? "" : " "
236 | parseInLine(col)
237 | output += " "
238 | } else {
239 | output += colAlign.length > 0 ? "" : " "
240 | parseInLine(col)
241 | output += " "
242 | }
243 | i++
244 | }
245 | output += " "
246 | }
247 |
248 | func beginTable(alignmentLine: String){
249 | if !bInTable {
250 | bInTable = true
251 | output += ""
252 | self.tableColsAlignment.removeAll(keepCapacity: false)
253 | let arr = alignmentLine.trim().componentsSeparatedByString("|")
254 | for col in arr {
255 | if col.indexOf(":-") >= 0 && col.indexOf("-:") > 0 {
256 | self.tableColsAlignment.append("style=\"text-align: center;\"")
257 | }else if col.indexOf("-:") > 0{
258 | self.tableColsAlignment.append("style=\"text-align: right;\"")
259 | }else {
260 | self.tableColsAlignment.append("")
261 | }
262 | }
263 | }
264 | }
265 | func closeTable(){
266 | if bInTable {
267 | bInTable = false
268 | output += "
"
269 | }
270 | }
271 | func closeTags(){
272 | for var i = blockEndTags.count - 1; i >= 0; i-- {
273 | output += blockEndTags[i]
274 | //blockEndTags.removeAtIndex(i)
275 | }
276 | blockEndTags.removeAll(keepCapacity: false)
277 | }
278 |
279 | func closeParagraph () {
280 | if isInParagraph {
281 | isInParagraph = false
282 | output += "\n"
283 | }
284 | }
285 |
286 | func beginParagraph(){
287 | if !isInParagraph {
288 | isInParagraph = true
289 | output += ""
290 | }
291 | }
292 |
293 |
294 |
295 | func calculateHeadLevel(line:String)->Int{
296 | var nFindHead = 0
297 | var pos: String.Index = line.startIndex
298 | for var i = 0; i <= 6 && i < line.characters.count; i++ {
299 | pos = line.startIndex.advancedBy( i)
300 | if line[pos] == headerChar {
301 | nFindHead = i + 1
302 | } else {
303 | break;
304 | }
305 | }
306 | return nFindHead
307 | }
308 |
309 | func handleLine(rawline:String) {
310 |
311 | if rawline.contains3PlusandOnlyChars("-")
312 | || rawline.contains3PlusandOnlyChars("*")
313 | || rawline.contains3PlusandOnlyChars("_"){
314 | closeParagraph()
315 | output += "
\n"
316 | return
317 | }
318 | var line = rawline
319 | var endTags = [String]()
320 |
321 | var pos: String.Index = line.startIndex
322 |
323 | if line[0] == ">" {
324 | output += ""
325 | line = line.substringFromIndex(line.startIndex.advancedBy( ">".length))
326 | endTags.append(" ")
327 | }
328 |
329 | let nFindHead = calculateHeadLevel(line)
330 | if (nFindHead > 0) {
331 | isCurrentLineNeedBr = false
332 |
333 | output += ""
334 | endTags.append(" ")
335 | pos = pos.advancedBy( nFindHead)
336 | } else {
337 | beginParagraph()
338 | }
339 |
340 | //line = this.handleImage(line, sb)
341 |
342 | let remaining = line.substringFromIndex(pos).trim()
343 | parseInLine(remaining)
344 | //output += "\n"
345 |
346 | for var i = endTags.count - 1; i >= 0; i-- {
347 | output += endTags[i]
348 | }
349 |
350 | //output += "\n"
351 |
352 | }
353 |
354 | func parseInLine(line: String) {
355 | let len = line.length
356 | let start = line.startIndex
357 | for var i = 0; i < len ; i++ {
358 | let ch:Character = line[start.advancedBy( i)]
359 |
360 | switch ch {
361 | case "*","_","~":
362 | if (i + 1 > len - 1) {
363 | output.append(ch)
364 | return
365 | }
366 | var strong = "strong"
367 | if ch == "~" {
368 | strong = "del"
369 | }
370 | if line[start.advancedBy( i + 1)] == ch {
371 | //possible **
372 | let remaining = line.substringFromIndex(start.advancedBy( i + 2))
373 | i += scanClosedChar(MarkNoteParser.charArray(ch, len: 2),inStr: remaining,tag: strong) + 1
374 | } else {
375 | let remaining = line.substringFromIndex(start.advancedBy( i + 1))
376 | i += scanClosedChar("\(ch)",inStr: remaining,tag: "em")
377 | }
378 | case "`":
379 | let remaining = line.substringFromIndex(start.advancedBy( i + 1))
380 | i += scanClosedChar("`",inStr: remaining,tag: "code")
381 | isCurrentLineNeedBr = false
382 |
383 | case "!":
384 | if i >= line.length - 1 || line[start.advancedBy( i + 1)] != "[" {
385 | output.append(ch)
386 | continue
387 | }
388 | i++
389 | let remaining = line.substringFromIndex(start.advancedBy( i + 1))
390 | let posArray = MarkNoteParser.detectPositions(["]","(",")"],inStr: remaining)
391 | if posArray.count == 3 {
392 | let img = ImageTag()
393 | img.alt = line.substring(i + 1, end: i + 1 + posArray[0] - 1)
394 | img.url = URLTag(url: line.substring( i + 1 + posArray[1] + 1, end: i + 1 + posArray[2] - 1)
395 | )
396 | output += img.toHtml()
397 | i += posArray[2] + 1
398 | }else {
399 | // check image reference defintion
400 | let posArray2 = MarkNoteParser.detectPositions(["]","[","]"],inStr: remaining)
401 | if posArray2.count == 3 {
402 | //is reference usage
403 | let title = line.substring(i + 1, end: i + 1 + posArray2[0] - 1)
404 | let url = line.substring( i + 1 + posArray2[1] + 1, end: i + 1 + posArray2[2] - 1)
405 | let refer = ReferenceUsageInfo()
406 | refer.type = .Image
407 | refer.key = url.lowercaseString
408 | refer.title = title
409 | self.arrReferenceUsage.append(refer)
410 | output += refer.placeHolder()
411 | i += posArray2[2] + 1 + 1
412 | }
413 | }
414 |
415 | case "[":
416 | let remaining = line.substringFromIndex(start.advancedBy( i + 1))
417 | let posArray = MarkNoteParser.detectPositions(["]","(",")"],inStr: remaining)
418 | if posArray.count == 3 {
419 | let link = LinkTag()
420 | link.text = line.substring(i + 1, end: i + 1 + posArray[0] - 1)
421 | link.url = URLTag(url: line.substring( i + 1 + posArray[1] + 1, end: i + 1 + posArray[2] - 1))
422 | output += link.toHtml()
423 | i += posArray[2] + 1
424 | }else {
425 | // check reference defintion
426 | let pos = remaining.indexOf("]:")
427 | if pos > 0 && pos < remaining.length - "]:".length {
428 | // is reference definition
429 | let info = ReferenceDefinition()
430 | info.key = remaining.substringToIndex(remaining.startIndex.advancedBy( pos ))
431 | let remaining2 = remaining.substringFromIndex(remaining.startIndex.advancedBy( pos + "]:".length ))
432 | info.url = URLTag(url: remaining2)
433 | self.arrReferenceInfo.append(info)
434 | i += pos + "]:".length + remaining2.length
435 | } else {
436 | let posArray2 = MarkNoteParser.detectPositions(["]","[","]"],inStr: remaining)
437 | if posArray2.count == 3 {
438 | //is reference usage
439 | let title = line.substring(i + 1, end: i + 1 + posArray2[0] - 1)
440 | let url = line.substring( i + 1 + posArray2[1] + 1, end: i + 1 + posArray2[2] - 1)
441 | let refer = ReferenceUsageInfo()
442 | refer.type = .Link
443 | refer.key = url.lowercaseString
444 | refer.title = title
445 | self.arrReferenceUsage.append(refer)
446 | output += refer.placeHolder()
447 | i += pos + posArray2[2] + 1 + 1
448 | }
449 | }
450 | }
451 | case "\"":
452 | output += """
453 | default:
454 | //do nothing
455 | output.append(ch)
456 | }
457 | }
458 | }
459 |
460 | public static func charArray(ch:Character, len:Int)->String{
461 | var str = ""
462 | for var i = 0 ; i < len ; i++ {
463 | str.append(ch)
464 | }
465 | return str
466 | }
467 |
468 | public static func detectPositions(toFind:[String],inStr:String )->[Int]{
469 | var posArray = [Int]()
470 | let count = toFind.count
471 | var lastPos = 0
472 | for var i = 0; i < count ; i++ {
473 | let pos = inStr.substringFromIndex(inStr.startIndex.advancedBy( lastPos)).indexOf(toFind[i])
474 | lastPos += pos
475 | if pos >= 0 {
476 | posArray.append(lastPos)
477 | }else {
478 | return posArray
479 | }
480 | }
481 | return posArray
482 | }
483 |
484 | func scanClosedChar(ch:String, inStr:String,tag:String) -> Int {
485 | let pos = inStr.indexOf(ch)
486 | if pos > 0 {
487 | output += "<\(tag)>" + inStr.substringToIndex(inStr.startIndex.advancedBy( pos )) + "\(tag)>"
488 | } else {
489 | output += ch
490 | }
491 | return pos + ch.length
492 | }
493 | public class func splitStringWithMidSpace(input: String) -> [String]{
494 | var array = [String]()
495 | let trimmed = input.trim()
496 | let pos = trimmed.indexOf(" ")
497 | if pos > 0 {
498 | array.append(trimmed.substringToIndex(trimmed.startIndex.advancedBy( pos)))
499 | array.append(trimmed.substringFromIndex(trimmed.startIndex.advancedBy( pos + 1)))
500 | } else {
501 | array.append(trimmed)
502 | }
503 | return array
504 | }
505 |
506 | }
507 | enum ReferenceType{
508 | case Link
509 | case Image
510 | }
511 |
512 | class URLTag: NSObject {
513 | var _url = ""
514 | var _title = ""
515 | init(url:String){
516 | let trimmed = url.trim()
517 | //let posSpace = trimmed.indexOf(" ")
518 | let arr = MarkNoteParser.splitStringWithMidSpace(trimmed)
519 | if arr.count > 1 {
520 | _url = arr[0].lowercaseString
521 | _title = arr[1].replaceAll("\"", toStr: "")
522 | } else {
523 | _url = arr[0].lowercaseString
524 | }
525 |
526 | }
527 | override var description: String {
528 | return _url
529 | }
530 | }
531 |
532 | class LinkTag {
533 | var text = ""
534 | var url = URLTag(url:"")
535 | func toHtml()-> String{
536 | if url._title.length > 0 {
537 | return "" + text + " "
538 | } else {
539 | return "" + text + " "
540 | }
541 | }
542 | }
543 |
544 | class ImageTag{
545 |
546 | var alt = ""
547 | var url = URLTag(url:"")
548 | func toHtml()-> String{
549 | if url._title.length > 0 {
550 | return " "
551 | } else {
552 | return " "
553 | }
554 | }
555 | }
556 |
557 | class ReferenceDefinition {
558 | var key = ""
559 | var url = URLTag(url:"")
560 | }
561 | class ReferenceUsageInfo{
562 | var title = ""
563 | var key = ""
564 | var type = ReferenceType.Link
565 | func placeHolder() -> String{
566 | return "ReferenceUsageInfo\(key)\(title)"
567 | }
568 | }
569 |
--------------------------------------------------------------------------------
/MarkNoteParser/MarkNoteParser/ViewController.swift:
--------------------------------------------------------------------------------
1 | /**
2 | * MarknoteParser- a markdown parser
3 | * Copyright (c) 2015, MarkNote. (MIT Licensed)
4 | * https://github.com/marknote/MarknoteParser
5 | */
6 |
7 | import UIKit
8 |
9 | class ViewController: UIViewController {
10 |
11 | override func viewDidLoad() {
12 | super.viewDidLoad()
13 | // Do any additional setup after loading the view, typically from a nib.
14 | }
15 |
16 | override func didReceiveMemoryWarning() {
17 | super.didReceiveMemoryWarning()
18 | // Dispose of any resources that can be recreated.
19 | }
20 |
21 |
22 | }
23 |
24 |
--------------------------------------------------------------------------------
/MarkNoteParser/MarkNoteParser/util/StringExtensions.swift:
--------------------------------------------------------------------------------
1 |
2 |
3 | import Foundation
4 |
5 | extension String {
6 |
7 | //MARK: Helper methods
8 |
9 | /**
10 | Returns the length of the string.
11 |
12 | :returns: Int length of the string.
13 | */
14 |
15 | var length: Int {
16 | return self.characters.count//count(self)
17 | }
18 |
19 |
20 |
21 | //MARK: - Linguistics
22 |
23 | /**
24 | Returns the langauge of a String
25 |
26 | NOTE: String has to be at least 4 characters, otherwise the method will return nil.
27 |
28 | :returns: String! Returns a string representing the langague of the string (e.g. en, fr, or und for undefined).
29 | */
30 | func detectLanguage() -> String? {
31 | if self.length > 4 {
32 | let tagger = NSLinguisticTagger(tagSchemes:[NSLinguisticTagSchemeLanguage], options: 0)
33 | tagger.string = self
34 | return tagger.tagAtIndex(0, scheme: NSLinguisticTagSchemeLanguage, tokenRange: nil, sentenceRange: nil)
35 | }
36 | return nil
37 | }
38 |
39 | /**
40 | Returns the script of a String
41 |
42 | :returns: String! returns a string representing the script of the String (e.g. Latn, Hans).
43 | */
44 | func detectScript() -> String? {
45 | if self.length > 1 {
46 | let tagger = NSLinguisticTagger(tagSchemes:[NSLinguisticTagSchemeScript], options: 0)
47 | tagger.string = self
48 | return tagger.tagAtIndex(0, scheme: NSLinguisticTagSchemeScript, tokenRange: nil, sentenceRange: nil)
49 | }
50 | return nil
51 | }
52 |
53 | /**
54 | Check the text direction of a given String.
55 |
56 | NOTE: String has to be at least 4 characters, otherwise the method will return false.
57 |
58 | :returns: Bool The Bool will return true if the string was writting in a right to left langague (e.g. Arabic, Hebrew)
59 |
60 | */
61 | var isRightToLeft : Bool {
62 | let language = self.detectLanguage()
63 | return (language == "ar" || language == "he")
64 | }
65 |
66 |
67 | //MARK: - Usablity & Social
68 |
69 | /**
70 | Check that a String is only made of white spaces, and new line characters.
71 |
72 | :returns: Bool
73 | */
74 | func isOnlyEmptySpacesAndNewLineCharacters() -> Bool {
75 | return self.stringByTrimmingCharactersInSet(NSCharacterSet.whitespaceAndNewlineCharacterSet()).length == 0
76 | }
77 |
78 |
79 |
80 |
81 | /**
82 | :returns: Base64 encoded string
83 | */
84 | func encodeToBase64Encoding() -> String {
85 | let utf8str = self.dataUsingEncoding(NSUTF8StringEncoding, allowLossyConversion: false)!
86 | return utf8str.base64EncodedStringWithOptions(NSDataBase64EncodingOptions.Encoding64CharacterLineLength)
87 | }
88 |
89 | /**
90 | :returns: Decoded Base64 string
91 | */
92 | func decodeFromBase64Encoding() -> String {
93 | /*let base64data = NSData(base64EncodedString: self, options: NSDataBase64DecodingOptions.IgnoreUnknownCharacters)
94 | return NSString(data: base64data!, encoding: NSUTF8StringEncoding)! as String*/
95 | /*let base64Decoded = NSData(base64EncodedString: self, options: NSDataBase64DecodingOptions(rawValue: 0))
96 | .map({ NSString(data: $0, encoding: NSUTF8StringEncoding) })
97 | return base64Decoded as! String*/
98 |
99 | let decodedData = NSData(base64EncodedString: self, options: NSDataBase64DecodingOptions(rawValue: 0))
100 | return NSString(data: decodedData!, encoding: NSUTF8StringEncoding)! as String
101 |
102 | }
103 |
104 | func contains (substring:String)->Bool{
105 | return self.rangeOfString(substring) != nil
106 | }
107 |
108 |
109 |
110 | // MARK: Subscript Methods
111 |
112 | /*subscript (i: Int) -> String {
113 | //return String(Array(self)[i])
114 | return self[advance(self.startIndex, i)]
115 | }*/
116 | subscript (i: Int) -> Character {
117 | return self[self.startIndex.advancedBy( i)]
118 | }
119 |
120 | subscript (i: Int) -> String {
121 | return String(self[i] as Character)
122 | }
123 |
124 | subscript (r: Range) -> String {
125 | return substringWithRange(
126 | Range(start: startIndex.advancedBy( r.startIndex),
127 | end: startIndex.advancedBy( r.endIndex)
128 | )
129 | )
130 | }
131 |
132 |
133 |
134 | subscript (range: NSRange) -> String {
135 | let end = range.location + range.length
136 | return self[Range(start: range.location, end: end)]
137 | }
138 |
139 | subscript (substring: String) -> Range? {
140 | return rangeOfString(substring, options: NSStringCompareOptions.LiteralSearch, range: Range(start: startIndex, end: endIndex), locale: NSLocale.currentLocale())
141 | }
142 |
143 | func substring(begin:Int, end:Int)->String{
144 | let range:NSRange = NSMakeRange(begin, end - begin + 1 )
145 | return self[range]
146 | }
147 |
148 |
149 | func stringByDecodingURLFormat() ->String {
150 | return self.stringByReplacingOccurrencesOfString("+", withString: " ", options: NSStringCompareOptions.LiteralSearch, range: nil)
151 | .stringByRemovingPercentEncoding!
152 | //.stringByReplacingPercentEscapesUsingEncoding(NSUTF8StringEncoding)!
153 |
154 | }
155 |
156 | func toBool() -> Bool? {
157 | switch self {
158 | case "True", "true", "yes", "1":
159 | return true
160 | case "False", "false", "no", "0":
161 | return false
162 | default:
163 | return nil
164 | }
165 | }
166 |
167 | func trim() ->String{
168 | return self.stringByTrimmingCharactersInSet(NSCharacterSet.whitespaceCharacterSet())
169 |
170 | }
171 |
172 | func indexOf(toFind:String)->Int{
173 |
174 | if let range = self.rangeOfString(toFind){
175 |
176 | return self.startIndex.distanceTo( range.startIndex)
177 | } else {
178 | return -1
179 | }
180 | }
181 |
182 | func contains3PlusandOnlyChars( char:String)-> Bool{
183 | return self.length >= 3
184 | && self.indexOf(char) == 0
185 | && self.stringByReplacingOccurrencesOfString(char, withString: "", options: NSStringCompareOptions.LiteralSearch, range: nil).length == 0
186 | }
187 |
188 | func replaceAll(target:String, toStr: String)->String{
189 | return self.stringByReplacingOccurrencesOfString(target, withString: toStr, options: NSStringCompareOptions.LiteralSearch, range: nil)
190 | }
191 | }
--------------------------------------------------------------------------------
/MarkNoteParser/MarkNoteParserTests/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | en
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIdentifier
10 | MarkNote.$(PRODUCT_NAME:rfc1034identifier)
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | $(PRODUCT_NAME)
15 | CFBundlePackageType
16 | BNDL
17 | CFBundleShortVersionString
18 | 1.0
19 | CFBundleSignature
20 | ????
21 | CFBundleVersion
22 | 1
23 |
24 |
25 |
--------------------------------------------------------------------------------
/MarkNoteParser/MarkNoteParserTests/MarkNoteParserTests.swift:
--------------------------------------------------------------------------------
1 | /**
2 | * MarknoteParser- a markdown parser
3 | * Copyright (c) 2015, MarkNote. (MIT Licensed)
4 | * https://github.com/marknote/MarknoteParser
5 | */
6 |
7 | import UIKit
8 | import XCTest
9 | import MarkNoteParser
10 |
11 | class MarkNoteParserTests: XCTestCase {
12 |
13 | override func setUp() {
14 | super.setUp()
15 | // Put setup code here. This method is called before the invocation of each test method in the class.
16 | }
17 |
18 | override func tearDown() {
19 | // Put teardown code here. This method is called after the invocation of each test method in the class.
20 | super.tearDown()
21 | }
22 |
23 | func markdown(input :String)->String{
24 | let result = MarkNoteParser.toHtml(input)
25 | print("input: \(input) result:\(result)")
26 | return result
27 | }
28 |
29 | /*func assertHtmlEauql(expected:String, actual:String){
30 | return assertHtmlEauql(expected, actual,"")
31 | }*/
32 |
33 | func assertHtmlEauql(expected:String, _ actual:String, _ message:String = ""){
34 | return XCTAssertEqual(expected.stringByReplacingOccurrencesOfString("\n", withString: "", options: NSStringCompareOptions.LiteralSearch, range: nil),
35 | actual.stringByReplacingOccurrencesOfString("\n", withString: "", options: NSStringCompareOptions.LiteralSearch, range: nil),
36 | message)
37 | }
38 |
39 | func testHeading() {
40 | assertHtmlEauql("Hello ", markdown("# Hello"), "H1 Heading Pass")
41 | assertHtmlEauql("Hello ", markdown("## Hello"), "H2 Heading Pass")
42 | assertHtmlEauql("Hello ", markdown("### Hello"), "H3 Heading Pass")
43 | assertHtmlEauql("Hello ", markdown("#### Hello"), "H4 Heading Pass")
44 | assertHtmlEauql("Hello ", markdown("##### Hello"), "H5 Heading Pass")
45 | assertHtmlEauql("Hello ", markdown("###### Hello"), "H6 Heading Pass")
46 | }
47 |
48 |
49 | func testFencedCode() {
50 | assertHtmlEauql("println("Hello")\n \n", markdown("```swift\nprintln(\"Hello\")\n```"), "Fenced Code Pass")
51 | }
52 |
53 | func testDefLinks() {
54 | assertHtmlEauql("Title
", markdown("[Title][Google]\n [Google]:www.google.com\n"), "Deflink no title Pass")
55 | assertHtmlEauql("text
", markdown("[text][Google]\n[Google]:www.google.com \"GoogleSearch\"\n"), "Deflink no title Pass")
56 | }
57 |
58 | func testDefImages() {
59 | assertHtmlEauql("
", markdown("![Title][image]\n [image]:aaa\n"), "Deflink no title Pass")
60 | assertHtmlEauql("
", markdown("![text][image]\n[image]:aaa \"TTTT\"\n"), "Deflink no title Pass")
61 | assertHtmlEauql("
", markdown("![alt text][logo]\n[logo]: https://github.com/adam-p/markdown-here/raw/master/src/common/images/icon48.png \"Logo Title Text\""), "Deflink no title Pass")
62 | }
63 |
64 |
65 |
66 | func testInlineLinks() {
67 | assertHtmlEauql("Google
\n", markdown("[Google](www.google.com)"), "inline link Pass")
68 | assertHtmlEauql("Google
\n", markdown("[Google](www.google.com \"googlehome\")"), "inline link Pass")
69 |
70 | }
71 |
72 | func testInlineImages() {
73 | assertHtmlEauql("
\n", markdown(""), "inline image Pass")
74 |
75 | }
76 |
77 | func testInlineImages2() {
78 | assertHtmlEauql("!
\n", markdown("!"), "inline image Pass")
79 |
80 | }
81 |
82 | func testHRule() {
83 | assertHtmlEauql(" \n", markdown("-----"), "HRule dashes Pass")
84 | assertHtmlEauql(" \n", markdown("***"), "HRule asterisks Pass")
85 | assertHtmlEauql(" \n", markdown("___"), "HRule underscope Pass")
86 | }
87 |
88 | func testLHeading() {
89 | assertHtmlEauql("Hello \n", markdown("Hello\n====="), "H1 LHeading Pass")
90 | assertHtmlEauql("Hello \n", markdown("Hello\n-----"), "H2 LHeading Pass")
91 | }
92 |
93 | func testBlockQuote() {
94 | assertHtmlEauql("Hello ", markdown(">### Hello"), "HRule dashes Pass")
95 | }
96 |
97 | func testInlineCode() {
98 | assertHtmlEauql("Hello
\n", markdown("`Hello`\n"), "InlineCode Pass")
99 | }
100 |
101 | func testBlockCode() {
102 | assertHtmlEauql("\nHello\n \n", markdown("``` \r\nHello\r\n```\n"), "BlockCode Pass")
103 | }
104 |
105 | func testDoubleEmphasis() {
106 | assertHtmlEauql("Hello
\n", markdown("**Hello**"), "Double Emphasis Asterisk Pass")
107 | assertHtmlEauql("World
\n", markdown("__World__"), "Double Emphasis Underscope Pass")
108 | assertHtmlEauql("Hello
\n", markdown("~~Hello~~"), "Double Emphasis Asterisk Pass")
109 |
110 | }
111 |
112 | func testDoubleEmphasis2() {
113 | assertHtmlEauql("123Hello 456
\n", markdown("123**Hello**456"), "Double Emphasis Asterisk Pass")
114 | assertHtmlEauql("123World 456
\n", markdown("123__World__456"), "Double Emphasis Underscope Pass")
115 | }
116 |
117 |
118 | func testEmphasis() {
119 | assertHtmlEauql("Hello
\n", markdown("*Hello*"), "Emphasis Asterisk Pass")
120 | assertHtmlEauql("World
\n", markdown("_World_"), "Emphasis Underscope Pass")
121 | assertHtmlEauql("123Hello 456
\n", markdown("123*Hello*456"), "Emphasis Asterisk Pass")
122 | assertHtmlEauql("123World 456
\n", markdown("123_World_456"), "Emphasis Underscope Pass")
123 | assertHtmlEauql("123Hello 456123world 456
\n", markdown("123*Hello*456123*world*456"), "Emphasis Asterisk Pass")
124 | assertHtmlEauql("123World 456123world 456
\n", markdown("123_World_456123*world*456"), "Emphasis Underscope Pass")
125 | }
126 |
127 | func testBulletList()
128 | {
129 | let input = "A bulleted list:\n- a\n- b\n- c\n"
130 | let expected = "A bulleted list:
"
131 | let actual = markdown(input).stringByReplacingOccurrencesOfString("\n", withString: "", options: NSStringCompareOptions.LiteralSearch, range: nil)
132 | assertHtmlEauql(expected, actual)
133 | }
134 |
135 |
136 | func testDetectPositions() {
137 | let expected = [1,2,3]
138 | let actual = MarkNoteParser.detectPositions(["1","2","3"],inStr:"0123")
139 | XCTAssertEqual(expected, actual)
140 |
141 | }
142 |
143 | func testDetectPositions2() {
144 | let expected = [2,4,5]
145 | let actual = MarkNoteParser.detectPositions(["2","4","5"],inStr:"012345")
146 | XCTAssertEqual(expected, actual)
147 |
148 | }
149 |
150 | func testHTMLTag(){
151 |
152 | let input = ""
153 | let expected = " "
154 | let actual = markdown(input).stringByReplacingOccurrencesOfString("\n", withString: "", options: NSStringCompareOptions.LiteralSearch, range: nil)
155 | assertHtmlEauql(expected, actual)
156 | }
157 |
158 | func testMixedHTMLTag(){
159 |
160 | let input = " \n## Inline HTML\nYou can also use raw HTML in your Markdown"
161 | let expected = " Inline HTML You can also use raw HTML in your Markdown
"
162 | let actual = markdown(input).stringByReplacingOccurrencesOfString("\n", withString: "", options: NSStringCompareOptions.LiteralSearch, range: nil)
163 | assertHtmlEauql(expected, actual)
164 | }
165 |
166 | func testHTMLTag2(){
167 |
168 | let input = "111123 222"
169 | let expected = "111
123 222
"
170 | let actual = markdown(input).stringByReplacingOccurrencesOfString("\n", withString: "", options: NSStringCompareOptions.LiteralSearch, range: nil)
171 | assertHtmlEauql(expected, actual)
172 | }
173 |
174 | func testEmbeddedHTML(){
175 | let input = "Don't modify this note. Your changes will be overrided. "
176 | let expected = "Don't modify this note. Your changes will be overrided. "
177 | let actual = markdown(input).stringByReplacingOccurrencesOfString("\n", withString: "", options: NSStringCompareOptions.LiteralSearch, range: nil)
178 | assertHtmlEauql(expected, actual)
179 |
180 | }
181 |
182 | func testHTMLInCode(){
183 |
184 | let input = "```\n<html>\n```\n"
185 | let expected = "<html> "
186 | let actual = markdown(input).stringByReplacingOccurrencesOfString("\n", withString: "", options: NSStringCompareOptions.LiteralSearch, range: nil)
187 | assertHtmlEauql(expected, actual)
188 | }
189 |
190 | func testNewLine(){
191 |
192 | let input = "abc \n123"
193 | let expected = "abc 123
"
194 | let actual = markdown(input)
195 | assertHtmlEauql(expected, actual)
196 | }
197 |
198 | func testTable(){
199 |
200 | let input = "|a|b|c|\n|------|-----|-----|\n|1|2|3|\n\n\n"
201 | let expected = ""
202 | let actual = markdown(input)
203 | assertHtmlEauql(expected, actual)
204 | }
205 |
206 | func testTableWithoutOuterPipe(){
207 |
208 | let input = "a|b|c\n------|-----|-----\n1|2|3\n\n\n"
209 | let expected = ""
210 | let actual = markdown(input)
211 | assertHtmlEauql(expected, actual)
212 | }
213 |
214 | func testTableWithColumnAignment(){
215 |
216 | let input = "a|b|c\n------|:-----:|-----:\n1|2|3\n\n\n"
217 | let expected = ""
218 | let actual = markdown(input)
219 | assertHtmlEauql(expected, actual)
220 | }
221 |
222 |
223 | func testSplitEmptyLiens(){
224 | XCTAssertEqual(["1","","3"],"1\n\n3".componentsSeparatedByString("\n"))
225 | XCTAssertEqual(["A bulleted list:","- a","- b","- c",""],"A bulleted list:\n- a\n- b\n- c\n".componentsSeparatedByString("\n"))
226 |
227 | }
228 |
229 | func testSplitStringWithMidSpace(){
230 | XCTAssertEqual(["1","2"], MarkNoteParser.splitStringWithMidSpace("1 2") )
231 | }
232 | }
233 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # MarkNote Parser
2 |
3 |
4 | Objective-C version: https://github.com/marknote/MarkNoteParserObjC
5 |
6 | Swift version: https://github.com/marknote/MarknoteParser
7 |
8 |
9 | A dead simple markdown parser implemented in both **Swift** and **Objective-C** with performance in mind, which can help you to transform markdown code into HTML.
10 | Most of markdown parsers highly depend on regular expression while MarkNote Parser avoids doing so.
11 |
12 | ## Purpose
13 |
14 | At the beginning my app [MarkNote](https://itunes.apple.com/us/app/marknote/id991297585?ls=1&mt=8) was using [marked](https://github.com/chjj/marked) to render markdown as HTML.
15 | After trying to find a relevant markdown parser in Swfit/Object-c while no luck, I decided to build my own.
16 |
17 |
18 | ## Usage
19 |
20 | ### Using swift version
21 | - Cope 2 files into your project:
22 | -- **StringExtensions.swift** , extension of String class;
23 | -- **MarkNoteParser.swift**, the parser class;
24 |
25 | - Use the method MarkNoteParser.toHtml to convert markdown text to HTML string, like this:
26 |
27 | ```swift
28 | func markdown(input :String)->String{
29 | let result = MarkNoteParser.toHtml(input)
30 | println("input: \(input) result:\(result)")
31 | return result
32 | }
33 | ```
34 | ### Using objetive-c version
35 | - Cope all files under "MarkNoteParserOC" folder into your project, and import the header file like this
36 |
37 | ```objective-c
38 | #import "MarkNoteParser.h"
39 | ```
40 | - Then you can call MarkNoteParser to parse your markdown document:
41 |
42 | ```objective-c
43 | NSString* result = [MarkNoteParser toHtml:input];
44 | return result;
45 | ```
46 |
47 | ## Features
48 |
49 | ### headers
50 |
51 | ```markdown
52 | # H1
53 | ## H2
54 | ### H3
55 | ```
56 | will be transformed into:
57 |
58 | ```html
59 | H1 H2 H3
60 | ```
61 |
62 | ### Emphasis
63 |
64 | ```markdown
65 | Emphasis, aka italics, with *asterisks* or _underscores_.
66 | Strong emphasis, aka bold, with **asterisks** or __underscores__.
67 | Strikethrough uses two tildes. ~~Scratch this.~~
68 | ```
69 | will be transformed into:
70 |
71 | ```html
72 | Emphasis, aka italics, with asterisks or underscores .
73 | Strong emphasis, aka bold, with asterisks or underscores .
74 | Strikethrough uses two tildes. Scratch this.
75 | ```
76 |
77 | ### Links
78 |
79 | ```markdown
80 | [I'm an inline-style link](https://www.google.com)
81 | [I'm an inline-style link with title](https://www.google.com "Google's Homepage")
82 | ```
83 |
84 | will be transformed into:
85 |
86 | ```html
87 | I'm an inline-style link
88 | I'm an inline-style link with title
89 | ```
90 | ### Images
91 |
92 | ```markdown
93 | 
94 | ```
95 | will be transformed into:
96 | ```html
97 |
98 | ```
99 | ### Code
100 |
101 |
102 | ```
103 | var s = "JavaScript syntax highlighting";
104 | alert(s);
105 | ```
106 |
107 |
108 | will be transformed into:
109 | ```html
110 |
111 | var s = "JavaScript syntax highlighting";
112 | alert(s);
113 |
114 | ```
115 |
116 | ### Table
117 |
118 | ```markdown
119 | | Tables | Are | Cool |
120 | | ------------- |:-------------:| -----:|
121 | | col 3 is | right-aligned | $1600 |
122 | | col 2 is | centered | $12 |
123 | | zebra stripes | are neat | $1 |
124 | ```
125 |
126 | will be transformed into:
127 |
128 | ```html
129 | Tables Are Cool col 3 is right-aligned $1600 col 2 is centered $12 zebra stripes are neat $1
The outer pipes (|) are optional, and you don't need to make the raw Markdown line up prettily. You can also use inline Markdown.
130 | ```
131 |
132 |
133 | ## Feedback
134 |
135 | If you have any suggestion or feedback, feel free to drop me a message or follow me on [twitter @markmarknote](https://twitter.com/markmarknote)
--------------------------------------------------------------------------------