From 19c473e81d4bc7c4153760c206c5852e2cc8d5e2 Mon Sep 17 00:00:00 2001 From: Simon Fairbairn Date: Thu, 30 Jan 2020 11:46:12 +1300 Subject: [PATCH] Fixes #69 --- Gemfile.lock | 50 ++++++++++--------- SwiftyMarkdown.xcodeproj/project.pbxproj | 2 + SwiftyMarkdown/SwiftyLineProcessor.swift | 40 +++++++++++---- SwiftyMarkdown/SwiftyMarkdown+iOS.swift | 2 + SwiftyMarkdown/SwiftyMarkdown.swift | 9 ++-- SwiftyMarkdown/SwiftyTokeniser.swift | 8 ++- .../SwiftyMarkdownExample/example.md | 2 +- .../SwiftyMarkdownCharacterTests.swift | 21 ++++++-- .../SwiftyMarkdownLineTests.swift | 6 +++ SwiftyMarkdownTests/metadataTest.md | 14 ++++++ 10 files changed, 109 insertions(+), 45 deletions(-) create mode 100644 SwiftyMarkdownTests/metadataTest.md diff --git a/Gemfile.lock b/Gemfile.lock index 6bb013f..d6cba1f 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -63,8 +63,8 @@ GEM dotenv (2.7.5) emoji_regex (1.0.1) escape (0.0.4) - excon (0.71.1) - faraday (0.17.1) + excon (0.72.0) + faraday (0.17.3) multipart-post (>= 1.2, < 3) faraday-cookie_jar (0.0.6) faraday (>= 0.7.4) @@ -72,7 +72,7 @@ GEM faraday_middleware (0.13.1) faraday (>= 0.7.4, < 1.0) fastimage (2.1.7) - fastlane (2.138.0) + fastlane (2.140.0) CFPropertyList (>= 2.3, < 4.0.0) addressable (>= 2.3, < 3.0.0) babosa (>= 1.0.2, < 2.0.0) @@ -87,7 +87,7 @@ GEM faraday_middleware (~> 0.13.1) fastimage (>= 2.1.0, < 3.0.0) gh_inspector (>= 1.1.2, < 2.0.0) - google-api-client (>= 0.21.2, < 0.24.0) + google-api-client (>= 0.29.2, < 0.37.0) google-cloud-storage (>= 1.15.0, < 2.0.0) highline (>= 1.7.2, < 2.0.0) json (< 3.0.0) @@ -112,30 +112,34 @@ GEM fourflusher (2.3.1) fuzzy_match (2.0.4) gh_inspector (1.1.3) - google-api-client (0.23.9) + google-api-client (0.36.4) addressable (~> 2.5, >= 2.5.1) - googleauth (>= 0.5, < 0.7.0) + googleauth (~> 0.9) httpclient (>= 2.8.1, < 3.0) - mime-types (~> 3.0) + mini_mime (~> 1.0) representable (~> 3.0) retriable (>= 2.0, < 4.0) - signet (~> 0.9) - google-cloud-core (1.4.1) + signet (~> 0.12) + google-cloud-core (1.5.0) google-cloud-env (~> 1.0) + google-cloud-errors (~> 1.0) google-cloud-env (1.3.0) faraday (~> 0.11) - google-cloud-storage (1.16.0) + google-cloud-errors (1.0.0) + google-cloud-storage (1.25.1) + addressable (~> 2.5) digest-crc (~> 0.4) - google-api-client (~> 0.23) + google-api-client (~> 0.33) google-cloud-core (~> 1.2) - googleauth (>= 0.6.2, < 0.10.0) - googleauth (0.6.7) + googleauth (~> 0.9) + mini_mime (~> 1.0) + googleauth (0.10.0) faraday (~> 0.12) jwt (>= 1.4, < 3.0) memoist (~> 0.16) multi_json (~> 1.11) os (>= 0.9, < 2.0) - signet (~> 0.7) + signet (~> 0.12) highline (1.7.10) http-cookie (1.0.3) domain_name (~> 0.5) @@ -145,11 +149,9 @@ GEM json (2.3.0) jwt (2.1.0) memoist (0.16.2) - mime-types (3.3) - mime-types-data (~> 3.2015) - mime-types-data (3.2019.1009) - mini_magick (4.9.5) - minitest (5.13.0) + mini_magick (4.10.1) + mini_mime (1.0.2) + minitest (5.14.0) molinillo (0.6.6) multi_json (1.14.1) multi_xml (0.6.0) @@ -183,17 +185,17 @@ GEM terminal-table (1.8.0) unicode-display_width (~> 1.1, >= 1.1.1) thread_safe (0.3.6) - tty-cursor (0.7.0) + tty-cursor (0.7.1) tty-screen (0.7.0) - tty-spinner (0.9.2) + tty-spinner (0.9.3) tty-cursor (~> 0.7) - tzinfo (1.2.5) + tzinfo (1.2.6) thread_safe (~> 0.1) uber (0.1.0) unf (0.1.4) unf_ext unf_ext (0.0.7.6) - unicode-display_width (1.6.0) + unicode-display_width (1.6.1) word_wrap (1.0.0) xcodeproj (1.14.0) CFPropertyList (>= 2.3.3, < 4.0) @@ -214,4 +216,4 @@ DEPENDENCIES fastlane BUNDLED WITH - 2.0.2 + 2.1.4 diff --git a/SwiftyMarkdown.xcodeproj/project.pbxproj b/SwiftyMarkdown.xcodeproj/project.pbxproj index f06bb72..2ca03fc 100644 --- a/SwiftyMarkdown.xcodeproj/project.pbxproj +++ b/SwiftyMarkdown.xcodeproj/project.pbxproj @@ -56,6 +56,7 @@ F4CE98E61C8AF01300D735C1 /* LICENSE */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = LICENSE; sourceTree = ""; }; F4CE98E71C8AF01300D735C1 /* README.md */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = net.daringfireball.markdown; path = README.md; sourceTree = ""; }; F4CE98E81C8AF01300D735C1 /* SwiftyMarkdown.podspec */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = SwiftyMarkdown.podspec; sourceTree = ""; }; + F4FEF07423E13365007219EF /* metadataTest.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; path = metadataTest.md; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -117,6 +118,7 @@ isa = PBXGroup; children = ( F4A48ABA23A8518900713437 /* test.md */, + F4FEF07423E13365007219EF /* metadataTest.md */, F4CE98901C8A921300D735C1 /* SwiftyMarkdownLineTests.swift */, F40D3A7E23A807F60085CF6E /* SwiftyMarkdownCharacterTests.swift */, F4CE98921C8A921300D735C1 /* Info.plist */, diff --git a/SwiftyMarkdown/SwiftyLineProcessor.swift b/SwiftyMarkdown/SwiftyLineProcessor.swift index 753fe1f..9c36b13 100644 --- a/SwiftyMarkdown/SwiftyLineProcessor.swift +++ b/SwiftyMarkdown/SwiftyLineProcessor.swift @@ -38,6 +38,7 @@ public enum Remove { public enum ChangeApplication { case current case previous + case untilClose } public struct LineRule { @@ -58,6 +59,7 @@ public struct LineRule { public class SwiftyLineProcessor { + var closeToken : String? = nil let defaultType : LineStyling public var processEmptyStrings : LineStyling? let lineRules : [LineRule] @@ -87,24 +89,22 @@ public class SwiftyLineProcessor { return output } - func processLineLevelAttributes( _ text : String ) -> SwiftyLine { + func processLineLevelAttributes( _ text : String ) -> SwiftyLine? { if text.isEmpty, let style = processEmptyStrings { return SwiftyLine(line: "", lineStyle: style) } let previousLines = lineRules.filter({ $0.changeAppliesTo == .previous }) - for element in previousLines { - let output = (element.shouldTrim) ? text.trimmingCharacters(in: .whitespaces) : text - let charSet = CharacterSet(charactersIn: element.token ) - if output.unicodeScalars.allSatisfy({ charSet.contains($0) }) { - return SwiftyLine(line: "", lineStyle: element.type) - } - } + for element in lineRules { guard element.token.count > 0 else { continue } var output : String = (element.shouldTrim) ? text.trimmingCharacters(in: .whitespaces) : text let unprocessed = output + + if let hasToken = self.closeToken, unprocessed != hasToken { + return nil + } switch element.removeFrom { case .leading: @@ -114,6 +114,8 @@ public class SwiftyLineProcessor { case .both: output = findLeadingLineElement(element, in: output) output = findTrailingLineElement(element, in: output) + case .entireLine: + output = findLeadingLineElement(element, in: output) default: break } @@ -121,11 +123,26 @@ public class SwiftyLineProcessor { guard unprocessed != output else { continue } + if element.changeAppliesTo == .untilClose { + self.closeToken = (self.closeToken == nil) ? element.token : nil + return nil + } + + + output = (element.shouldTrim) ? output.trimmingCharacters(in: .whitespaces) : output return SwiftyLine(line: output, lineStyle: element.type) } + for element in previousLines { + let output = (element.shouldTrim) ? text.trimmingCharacters(in: .whitespaces) : text + let charSet = CharacterSet(charactersIn: element.token ) + if output.unicodeScalars.allSatisfy({ charSet.contains($0) }) { + return SwiftyLine(line: "", lineStyle: element.type) + } + } + return SwiftyLine(line: text.trimmingCharacters(in: .whitespaces), lineStyle: defaultType) } @@ -137,9 +154,10 @@ public class SwiftyLineProcessor { continue } - let input : SwiftyLine - input = processLineLevelAttributes(String(heading)) - + guard let input = processLineLevelAttributes(String(heading)) else { + continue + } + if let existentPrevious = input.lineStyle.styleIfFoundStyleAffectsPreviousLine(), foundAttributes.count > 0 { if let idx = foundAttributes.firstIndex(of: foundAttributes.last!) { let updatedPrevious = foundAttributes.last! diff --git a/SwiftyMarkdown/SwiftyMarkdown+iOS.swift b/SwiftyMarkdown/SwiftyMarkdown+iOS.swift index c33929f..5acee77 100644 --- a/SwiftyMarkdown/SwiftyMarkdown+iOS.swift +++ b/SwiftyMarkdown/SwiftyMarkdown+iOS.swift @@ -140,6 +140,8 @@ extension SwiftyMarkdown { func color( for line : SwiftyLine ) -> UIColor { // What type are we and is there a font name set? switch line.lineStyle as! MarkdownLineStyle { + case .yaml: + return body.color case .h1, .previousH1: return h1.color case .h2, .previousH2: diff --git a/SwiftyMarkdown/SwiftyMarkdown.swift b/SwiftyMarkdown/SwiftyMarkdown.swift index ab267d5..bd2833c 100644 --- a/SwiftyMarkdown/SwiftyMarkdown.swift +++ b/SwiftyMarkdown/SwiftyMarkdown.swift @@ -38,7 +38,7 @@ enum MarkdownLineStyle : LineStyling { } } - + case yaml case h1 case h2 case h3 @@ -125,6 +125,7 @@ If that is not set, then the system default will be used. /// A class that takes a [Markdown](https://daringfireball.net/projects/markdown/) string or file and returns an NSAttributedString with the applied styles. Supports Dynamic Type. @objc open class SwiftyMarkdown: NSObject { static public var lineRules = [ + LineRule(token: "=", type: MarkdownLineStyle.previousH1, removeFrom: .entireLine, changeAppliesTo: .previous), LineRule(token: "-", type: MarkdownLineStyle.previousH2, removeFrom: .entireLine, changeAppliesTo: .previous), LineRule(token: " ", type: MarkdownLineStyle.codeblock, removeFrom: .leading, shouldTrim: false), @@ -140,11 +141,11 @@ If that is not set, then the system default will be used. ] static public var characterRules = [ - CharacterRule(openTag: "![", intermediateTag: "](", closingTag: ")", escapeCharacter: "\\", styles: [1 : [CharacterStyle.image]], maxTags: 1), +// CharacterRule(openTag: "![", intermediateTag: "](", closingTag: ")", escapeCharacter: "\\", styles: [1 : [CharacterStyle.image]], maxTags: 1), CharacterRule(openTag: "[", intermediateTag: "](", closingTag: ")", escapeCharacter: "\\", styles: [1 : [CharacterStyle.link]], maxTags: 1), - CharacterRule(openTag: "`", intermediateTag: nil, closingTag: nil, escapeCharacter: "\\", styles: [1 : [CharacterStyle.code]], maxTags: 1, cancels: .allRemaining), +// CharacterRule(openTag: "`", intermediateTag: nil, closingTag: nil, escapeCharacter: "\\", styles: [1 : [CharacterStyle.code]], maxTags: 1, cancels: .allRemaining), CharacterRule(openTag: "*", intermediateTag: nil, closingTag: nil, escapeCharacter: "\\", styles: [1 : [CharacterStyle.italic], 2 : [CharacterStyle.bold], 3 : [CharacterStyle.bold, CharacterStyle.italic]], maxTags: 3), - CharacterRule(openTag: "_", intermediateTag: nil, closingTag: nil, escapeCharacter: "\\", styles: [1 : [CharacterStyle.italic], 2 : [CharacterStyle.bold], 3 : [CharacterStyle.bold, CharacterStyle.italic]], maxTags: 3) +// CharacterRule(openTag: "_", intermediateTag: nil, closingTag: nil, escapeCharacter: "\\", styles: [1 : [CharacterStyle.italic], 2 : [CharacterStyle.bold], 3 : [CharacterStyle.bold, CharacterStyle.italic]], maxTags: 3) ] let lineProcessor = SwiftyLineProcessor(rules: SwiftyMarkdown.lineRules, defaultRule: MarkdownLineStyle.body) diff --git a/SwiftyMarkdown/SwiftyTokeniser.swift b/SwiftyMarkdown/SwiftyTokeniser.swift index c38a64b..0900fdf 100644 --- a/SwiftyMarkdown/SwiftyTokeniser.swift +++ b/SwiftyMarkdown/SwiftyTokeniser.swift @@ -193,6 +193,7 @@ public class SwiftyTokeniser { continue } if let hasReplacement = self.replacements[token.inputString] { + os_log("Found replacement for %@", log: .tokenising, type: .info, token.inputString) for var repToken in hasReplacement { guard repToken.type == .string else { finalTokens.append(repToken) @@ -248,10 +249,13 @@ public class SwiftyTokeniser { var outputTokens : [Token] = [] let scanner = Scanner(string: stringToken.outputString) scanner.charactersToBeSkipped = nil - var repTokens = replacements + + // Remove any replacements that don't appear in the incoming string + var repTokens = replacements.filter({ stringToken.outputString.contains($0.inputString) }) + + var testString = "\n" while !scanner.isAtEnd { var outputString : String = "" - var testString = "\n" if repTokens.count > 0 { testString = repTokens.removeFirst().inputString } diff --git a/SwiftyMarkdownExample/SwiftyMarkdownExample/example.md b/SwiftyMarkdownExample/SwiftyMarkdownExample/example.md index c8449e6..3ea992d 100644 --- a/SwiftyMarkdownExample/SwiftyMarkdownExample/example.md +++ b/SwiftyMarkdownExample/SwiftyMarkdownExample/example.md @@ -4,7 +4,7 @@ SwiftyMarkdown is a Swift-based *Markdown* parser that converts *Markdown* files Show Images From Your App Bundle! --- -![Image](bubble) +![Image](bubble) There may be a problem with [Links](https://www.neverendingvoyage.com/). Customise fonts and colors easily in a Swift-like way: diff --git a/SwiftyMarkdownTests/SwiftyMarkdownCharacterTests.swift b/SwiftyMarkdownTests/SwiftyMarkdownCharacterTests.swift index 74437b0..df76450 100644 --- a/SwiftyMarkdownTests/SwiftyMarkdownCharacterTests.swift +++ b/SwiftyMarkdownTests/SwiftyMarkdownCharacterTests.swift @@ -13,9 +13,11 @@ import XCTest class SwiftyMarkdownCharacterTests: XCTestCase { func testIsolatedCase() { - let challenge = TokenTest(input: "[Link1](http://voyagetravelapps.com/) test, testing another link [Link2](http://voyagetravelapps.com/)", output: "Link1 test, testing another link Link2", tokens: [ + let challenge = TokenTest(input: "[Link1](http://voyagetravelapps.com/) **bold** [Link2](http://voyagetravelapps.com/)", output: "Link1 bold Link2", tokens: [ Token(type: .string, inputString: "Link1", characterStyles: [CharacterStyle.link]), - Token(type: .string, inputString: " test, testing another link ", characterStyles: []), + Token(type: .string, inputString: " ", characterStyles: []), + Token(type: .string, inputString: "bold", characterStyles: [CharacterStyle.bold]), + Token(type: .string, inputString: " ", characterStyles: []), Token(type: .string, inputString: "Link2", characterStyles: [CharacterStyle.link]) ]) let results = self.attempt(challenge) @@ -23,7 +25,7 @@ class SwiftyMarkdownCharacterTests: XCTestCase { XCTAssertEqual(results.tokens.map({ $0.outputString }).joined(), challenge.output) XCTAssertEqual(results.foundStyles, results.expectedStyles) XCTAssertEqual(results.attributedString.string, challenge.output) - + } @@ -489,6 +491,19 @@ class SwiftyMarkdownCharacterTests: XCTestCase { XCTAssertEqual(results.tokens.map({ $0.outputString }).joined(), challenge.output) XCTAssertEqual(results.foundStyles, results.expectedStyles) XCTAssertEqual(results.attributedString.string, challenge.output) + + challenge = TokenTest(input: "[Link1](http://voyagetravelapps.com/) **bold** [Link2](http://voyagetravelapps.com/)", output: "Link1 bold Link2", tokens: [ + Token(type: .string, inputString: "Link1", characterStyles: [CharacterStyle.link]), + Token(type: .string, inputString: " ", characterStyles: []), + Token(type: .string, inputString: "bold", characterStyles: [CharacterStyle.bold]), + Token(type: .string, inputString: " ", characterStyles: []), + Token(type: .string, inputString: "Link2", characterStyles: [CharacterStyle.link]) + ]) + results = self.attempt(challenge) + XCTAssertEqual(challenge.tokens.count, results.stringTokens.count) + XCTAssertEqual(results.tokens.map({ $0.outputString }).joined(), challenge.output) + XCTAssertEqual(results.foundStyles, results.expectedStyles) + XCTAssertEqual(results.attributedString.string, challenge.output) } diff --git a/SwiftyMarkdownTests/SwiftyMarkdownLineTests.swift b/SwiftyMarkdownTests/SwiftyMarkdownLineTests.swift index 51771b2..9580310 100644 --- a/SwiftyMarkdownTests/SwiftyMarkdownLineTests.swift +++ b/SwiftyMarkdownTests/SwiftyMarkdownLineTests.swift @@ -139,4 +139,10 @@ class SwiftyMarkdownTests: XCTestCase { XCTAssertEqual(output, expected) } + func testThatYAMLMetadataIsRemoved() { + let yaml = StringTest(input: "---\nlayout: page\ntitle: \"Trail Wallet FAQ\"\ndate: 2015-04-22 10:59\ncomments: true\nsharing: true\nliking: false\nfooter: true\nsidebar: false\n---\n# Finally some Markdown!", expectedOutput: "Finally some Markdown!") + let md = SwiftyMarkdown(string: yaml.input) + XCTAssertEqual(md.attributedString().string, yaml.expectedOutput) + } + } diff --git a/SwiftyMarkdownTests/metadataTest.md b/SwiftyMarkdownTests/metadataTest.md new file mode 100644 index 0000000..6d182c0 --- /dev/null +++ b/SwiftyMarkdownTests/metadataTest.md @@ -0,0 +1,14 @@ +--- +layout: page +title: "Trail Wallet FAQ" +date: 2015-04-22 10:59 +comments: true +sharing: true +liking: false +footer: true +sidebar: false +--- + +# Good Day To You, Walleteer! + +We are Erin and Simon from [Never Ending Voyage][1] and we want to thank you for trying out our app. We have been travelling non-stop for seven years and part of how we support ourselves is through Trail Wallet.