Skip to content

Commit

Permalink
Merge pull request #24 from prolificinteractive/feature/links-and-esc…
Browse files Browse the repository at this point in the history
…aping

Added Markdown link and backslash escape support
  • Loading branch information
htinlinn authored Nov 8, 2017
2 parents 276a830 + 31dad97 commit 3cb8bd7
Show file tree
Hide file tree
Showing 27 changed files with 915 additions and 202 deletions.
4 changes: 2 additions & 2 deletions Example/Podfile.lock
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
PODS:
- Marker (1.0.0)
- Marker (1.1.0)

DEPENDENCIES:
- Marker (from `../`)
Expand All @@ -9,7 +9,7 @@ EXTERNAL SOURCES:
:path: ../

SPEC CHECKSUMS:
Marker: a298cccb34f84d81beb9206ad618cd8f114f524b
Marker: ef3ead037c66a1340eec2fd9f79b27cb36dcbec3

PODFILE CHECKSUM: 2d22b0ce73bebf9f2dee7cbf15b441cc137adc5e

Expand Down
2 changes: 1 addition & 1 deletion Marker.podspec
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@

Pod::Spec.new do |s|
s.name = "Marker"
s.version = "1.0.0"
s.version = "1.1.0"
s.summary = "A light wrapper around NSAttributedString."
s.description = <<-DESC
TODO: Add long description of the pod here.
Expand Down
56 changes: 48 additions & 8 deletions Marker/Marker.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
271C85C31ED4E2B700F8BBBB /* TagParser.swift in Sources */ = {isa = PBXBuildFile; fileRef = 271C85B21ED4E2B700F8BBBB /* TagParser.swift */; };
271C85C51ED4E2B700F8BBBB /* TextStyle.swift in Sources */ = {isa = PBXBuildFile; fileRef = 271C85B41ED4E2B700F8BBBB /* TextStyle.swift */; };
271C85C61ED4E2B700F8BBBB /* TextTransform.swift in Sources */ = {isa = PBXBuildFile; fileRef = 271C85B51ED4E2B700F8BBBB /* TextTransform.swift */; };
271C85C91ED4E37700F8BBBB /* ParserTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 271C85C81ED4E37700F8BBBB /* ParserTests.swift */; };
271C85C91ED4E37700F8BBBB /* MarkdownParserTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 271C85C81ED4E37700F8BBBB /* MarkdownParserTests.swift */; };
27C4E5D01ED5ED2400DDE387 /* Marker.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 27C4E5C71ED5ED2400DDE387 /* Marker.framework */; };
27C4E5EC1ED5ED3100DDE387 /* Marker.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 27C4E5E31ED5ED3000DDE387 /* Marker.framework */; };
27C4E5FA1ED5ED6400DDE387 /* Marker.swift in Sources */ = {isa = PBXBuildFile; fileRef = 271C85A41ED4E2B700F8BBBB /* Marker.swift */; };
Expand Down Expand Up @@ -50,8 +50,23 @@
27C4E61B1ED5ED6500DDE387 /* TextTransform.swift in Sources */ = {isa = PBXBuildFile; fileRef = 271C85B51ED4E2B700F8BBBB /* TextTransform.swift */; };
27C4E61C1ED5ED6900DDE387 /* Marker.h in Headers */ = {isa = PBXBuildFile; fileRef = 271C858D1ED4E2A000F8BBBB /* Marker.h */; settings = {ATTRIBUTES = (Public, ); }; };
27C4E61D1ED5ED6C00DDE387 /* Marker.h in Headers */ = {isa = PBXBuildFile; fileRef = 271C858D1ED4E2A000F8BBBB /* Marker.h */; settings = {ATTRIBUTES = (Public, ); }; };
480C7A5F1F15832A0094E4EA /* ParserTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 271C85C81ED4E37700F8BBBB /* ParserTests.swift */; };
480C7A601F15832A0094E4EA /* ParserTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 271C85C81ED4E37700F8BBBB /* ParserTests.swift */; };
480104771FA1355F00F20FF8 /* Rule.swift in Sources */ = {isa = PBXBuildFile; fileRef = 480104741FA1355F00F20FF8 /* Rule.swift */; };
480104781FA1355F00F20FF8 /* Rule.swift in Sources */ = {isa = PBXBuildFile; fileRef = 480104741FA1355F00F20FF8 /* Rule.swift */; };
480104791FA1355F00F20FF8 /* Rule.swift in Sources */ = {isa = PBXBuildFile; fileRef = 480104741FA1355F00F20FF8 /* Rule.swift */; };
4801047A1FA1355F00F20FF8 /* TokenParser.swift in Sources */ = {isa = PBXBuildFile; fileRef = 480104751FA1355F00F20FF8 /* TokenParser.swift */; };
4801047B1FA1355F00F20FF8 /* TokenParser.swift in Sources */ = {isa = PBXBuildFile; fileRef = 480104751FA1355F00F20FF8 /* TokenParser.swift */; };
4801047C1FA1355F00F20FF8 /* TokenParser.swift in Sources */ = {isa = PBXBuildFile; fileRef = 480104751FA1355F00F20FF8 /* TokenParser.swift */; };
4801047D1FA1355F00F20FF8 /* Token.swift in Sources */ = {isa = PBXBuildFile; fileRef = 480104761FA1355F00F20FF8 /* Token.swift */; };
4801047E1FA1355F00F20FF8 /* Token.swift in Sources */ = {isa = PBXBuildFile; fileRef = 480104761FA1355F00F20FF8 /* Token.swift */; };
4801047F1FA1355F00F20FF8 /* Token.swift in Sources */ = {isa = PBXBuildFile; fileRef = 480104761FA1355F00F20FF8 /* Token.swift */; };
480C7A5F1F15832A0094E4EA /* MarkdownParserTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 271C85C81ED4E37700F8BBBB /* MarkdownParserTests.swift */; };
480C7A601F15832A0094E4EA /* MarkdownParserTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 271C85C81ED4E37700F8BBBB /* MarkdownParserTests.swift */; };
481303A01FA3BA7C001F1DF1 /* String+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4813039F1FA3BA7C001F1DF1 /* String+Extensions.swift */; };
481303A11FA3BC64001F1DF1 /* String+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4813039F1FA3BA7C001F1DF1 /* String+Extensions.swift */; };
481303A21FA3BC65001F1DF1 /* String+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4813039F1FA3BA7C001F1DF1 /* String+Extensions.swift */; };
481B0A771FA9143800CB651C /* ElementParserTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 481B0A751FA9142D00CB651C /* ElementParserTests.swift */; };
481B0A781FA9143800CB651C /* ElementParserTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 481B0A751FA9142D00CB651C /* ElementParserTests.swift */; };
481B0A791FA9143900CB651C /* ElementParserTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 481B0A751FA9142D00CB651C /* ElementParserTests.swift */; };
484053B21F72EA6000626C55 /* UIButtonExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 484053A21F72EA4F00626C55 /* UIButtonExtension.swift */; };
484053B31F72EA6000626C55 /* Color.swift in Sources */ = {isa = PBXBuildFile; fileRef = 484053A41F72EA4F00626C55 /* Color.swift */; };
484053B41F72EA6000626C55 /* Font.swift in Sources */ = {isa = PBXBuildFile; fileRef = 484053A61F72EA4F00626C55 /* Font.swift */; };
Expand Down Expand Up @@ -135,11 +150,16 @@
271C85B41ED4E2B700F8BBBB /* TextStyle.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TextStyle.swift; sourceTree = "<group>"; };
271C85B51ED4E2B700F8BBBB /* TextTransform.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TextTransform.swift; sourceTree = "<group>"; };
271C85C71ED4E37600F8BBBB /* MarkerTests-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "MarkerTests-Bridging-Header.h"; sourceTree = "<group>"; };
271C85C81ED4E37700F8BBBB /* ParserTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ParserTests.swift; sourceTree = "<group>"; };
271C85C81ED4E37700F8BBBB /* MarkdownParserTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MarkdownParserTests.swift; sourceTree = "<group>"; };
27C4E5C71ED5ED2400DDE387 /* Marker.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Marker.framework; sourceTree = BUILT_PRODUCTS_DIR; };
27C4E5CF1ED5ED2400DDE387 /* Marker-tvOSTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = "Marker-tvOSTests.xctest"; sourceTree = BUILT_PRODUCTS_DIR; };
27C4E5E31ED5ED3000DDE387 /* Marker.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Marker.framework; sourceTree = BUILT_PRODUCTS_DIR; };
27C4E5EB1ED5ED3100DDE387 /* Marker-macOSTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = "Marker-macOSTests.xctest"; sourceTree = BUILT_PRODUCTS_DIR; };
480104741FA1355F00F20FF8 /* Rule.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Rule.swift; sourceTree = "<group>"; };
480104751FA1355F00F20FF8 /* TokenParser.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TokenParser.swift; sourceTree = "<group>"; };
480104761FA1355F00F20FF8 /* Token.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Token.swift; sourceTree = "<group>"; };
4813039F1FA3BA7C001F1DF1 /* String+Extensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "String+Extensions.swift"; sourceTree = "<group>"; };
481B0A751FA9142D00CB651C /* ElementParserTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ElementParserTests.swift; sourceTree = "<group>"; };
484053A11F72EA4F00626C55 /* NSButtonExtension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NSButtonExtension.swift; sourceTree = "<group>"; };
484053A21F72EA4F00626C55 /* UIButtonExtension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UIButtonExtension.swift; sourceTree = "<group>"; };
484053A41F72EA4F00626C55 /* Color.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Color.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -251,7 +271,8 @@
271C85971ED4E2A000F8BBBB /* MarkerTests */ = {
isa = PBXGroup;
children = (
271C85C81ED4E37700F8BBBB /* ParserTests.swift */,
481B0A751FA9142D00CB651C /* ElementParserTests.swift */,
271C85C81ED4E37700F8BBBB /* MarkdownParserTests.swift */,
48F232831F1FBD1300E86D5D /* TextStyleEquatableTests.swift */,
48F232871F1FC2F900E86D5D /* TextStyleFactoryFunctionTests.swift */,
48F232781F1FBA2200E86D5D /* TextTransformEquatableTests.swift */,
Expand All @@ -268,9 +289,13 @@
271C85AD1ED4E2B700F8BBBB /* ElementParser.swift */,
271C85AE1ED4E2B700F8BBBB /* MarkdownElement.swift */,
271C85AF1ED4E2B700F8BBBB /* MarkdownParser.swift */,
480104741FA1355F00F20FF8 /* Rule.swift */,
4813039F1FA3BA7C001F1DF1 /* String+Extensions.swift */,
271C85B01ED4E2B700F8BBBB /* Symbol.swift */,
271C85B11ED4E2B700F8BBBB /* Tag.swift */,
271C85B21ED4E2B700F8BBBB /* TagParser.swift */,
480104761FA1355F00F20FF8 /* Token.swift */,
480104751FA1355F00F20FF8 /* TokenParser.swift */,
);
path = Parser;
sourceTree = "<group>";
Expand Down Expand Up @@ -613,14 +638,18 @@
buildActionMask = 2147483647;
files = (
271C85C51ED4E2B700F8BBBB /* TextStyle.swift in Sources */,
4801047D1FA1355F00F20FF8 /* Token.swift in Sources */,
48F232751F1FB7B600E86D5D /* TextTransform+Extensions.swift in Sources */,
271C85C01ED4E2B700F8BBBB /* MarkdownParser.swift in Sources */,
484053B81F72EA6000626C55 /* UITextFieldExtension.swift in Sources */,
484053B31F72EA6000626C55 /* Color.swift in Sources */,
480104771FA1355F00F20FF8 /* Rule.swift in Sources */,
271C85BB1ED4E2B700F8BBBB /* Markup.swift in Sources */,
271C85BD1ED4E2B700F8BBBB /* Element.swift in Sources */,
271C85BF1ED4E2B700F8BBBB /* MarkdownElement.swift in Sources */,
271C85C31ED4E2B700F8BBBB /* TagParser.swift in Sources */,
4801047A1FA1355F00F20FF8 /* TokenParser.swift in Sources */,
481303A01FA3BA7C001F1DF1 /* String+Extensions.swift in Sources */,
48F232801F1FBA7800E86D5D /* TextStyle+Extensions.swift in Sources */,
484053B21F72EA6000626C55 /* UIButtonExtension.swift in Sources */,
484053BA1F72EA6000626C55 /* UITextViewExtension.swift in Sources */,
Expand All @@ -642,9 +671,10 @@
buildActionMask = 2147483647;
files = (
48F2327C1F1FBA4400E86D5D /* TextTransformEquatableTests.swift in Sources */,
481B0A771FA9143800CB651C /* ElementParserTests.swift in Sources */,
48F232881F1FC2F900E86D5D /* TextStyleFactoryFunctionTests.swift in Sources */,
48F232841F1FBD1300E86D5D /* TextStyleEquatableTests.swift in Sources */,
271C85C91ED4E37700F8BBBB /* ParserTests.swift in Sources */,
271C85C91ED4E37700F8BBBB /* MarkdownParserTests.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
Expand All @@ -653,16 +683,20 @@
buildActionMask = 2147483647;
files = (
27C4E6091ED5ED6400DDE387 /* TextStyle.swift in Sources */,
4801047E1FA1355F00F20FF8 /* Token.swift in Sources */,
48F232761F1FB7B600E86D5D /* TextTransform+Extensions.swift in Sources */,
27C4E6041ED5ED6400DDE387 /* MarkdownParser.swift in Sources */,
484053C21F72EA6000626C55 /* UITextFieldExtension.swift in Sources */,
484053BD1F72EA6000626C55 /* Color.swift in Sources */,
480104781FA1355F00F20FF8 /* Rule.swift in Sources */,
27C4E5FF1ED5ED6400DDE387 /* Markup.swift in Sources */,
484053CF1F72EA7A00626C55 /* UIButtonExtension.swift in Sources */,
27C4E6011ED5ED6400DDE387 /* Element.swift in Sources */,
27C4E6031ED5ED6400DDE387 /* MarkdownElement.swift in Sources */,
4801047B1FA1355F00F20FF8 /* TokenParser.swift in Sources */,
27C4E6071ED5ED6400DDE387 /* TagParser.swift in Sources */,
48F232811F1FBA7800E86D5D /* TextStyle+Extensions.swift in Sources */,
481303A11FA3BC64001F1DF1 /* String+Extensions.swift in Sources */,
484053C41F72EA6000626C55 /* UITextViewExtension.swift in Sources */,
484053C01F72EA6000626C55 /* LineBreakMode.swift in Sources */,
27C4E6051ED5ED6400DDE387 /* Symbol.swift in Sources */,
Expand All @@ -682,9 +716,10 @@
buildActionMask = 2147483647;
files = (
48F2327D1F1FBA4400E86D5D /* TextTransformEquatableTests.swift in Sources */,
481B0A781FA9143800CB651C /* ElementParserTests.swift in Sources */,
48F232891F1FC2F900E86D5D /* TextStyleFactoryFunctionTests.swift in Sources */,
48F232851F1FBD1300E86D5D /* TextStyleEquatableTests.swift in Sources */,
480C7A601F15832A0094E4EA /* ParserTests.swift in Sources */,
480C7A601F15832A0094E4EA /* MarkdownParserTests.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
Expand All @@ -695,6 +730,8 @@
27C4E61A1ED5ED6500DDE387 /* TextStyle.swift in Sources */,
484053C51F72EA6100626C55 /* NSButtonExtension.swift in Sources */,
48F232821F1FBA7800E86D5D /* TextStyle+Extensions.swift in Sources */,
4801047C1FA1355F00F20FF8 /* TokenParser.swift in Sources */,
480104791FA1355F00F20FF8 /* Rule.swift in Sources */,
27C4E6151ED5ED6500DDE387 /* MarkdownParser.swift in Sources */,
484053C71F72EA6100626C55 /* Color.swift in Sources */,
48F232771F1FB7B600E86D5D /* TextTransform+Extensions.swift in Sources */,
Expand All @@ -705,6 +742,8 @@
27C4E6141ED5ED6500DDE387 /* MarkdownElement.swift in Sources */,
27C4E6181ED5ED6500DDE387 /* TagParser.swift in Sources */,
484053CA1F72EA6100626C55 /* LineBreakMode.swift in Sources */,
481303A21FA3BC65001F1DF1 /* String+Extensions.swift in Sources */,
4801047F1FA1355F00F20FF8 /* Token.swift in Sources */,
27C4E6161ED5ED6500DDE387 /* Symbol.swift in Sources */,
27C4E6131ED5ED6500DDE387 /* ElementParser.swift in Sources */,
27C4E60B1ED5ED6500DDE387 /* Marker.swift in Sources */,
Expand All @@ -721,9 +760,10 @@
buildActionMask = 2147483647;
files = (
48F2327E1F1FBA4500E86D5D /* TextTransformEquatableTests.swift in Sources */,
481B0A791FA9143900CB651C /* ElementParserTests.swift in Sources */,
48F2328A1F1FC2F900E86D5D /* TextStyleFactoryFunctionTests.swift in Sources */,
48F232861F1FBD1300E86D5D /* TextStyleEquatableTests.swift in Sources */,
480C7A5F1F15832A0094E4EA /* ParserTests.swift in Sources */,
480C7A5F1F15832A0094E4EA /* MarkdownParserTests.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
Expand Down
71 changes: 41 additions & 30 deletions Marker/Marker/Marker.swift
Original file line number Diff line number Diff line change
Expand Up @@ -64,41 +64,46 @@ public func parsedMarkdownString(from markdownText: String,

elements.forEach { (element) in
var font: Font? = nil
var strikethroughStyle: NSUnderlineStyle? = nil
var underlineStyle: NSUnderlineStyle? = nil

switch element {
case .em(_):
case .em:
font = textStyle.emFont
case .strong(_):
case .strong:
font = textStyle.strongFont
case .strikethrough(_):
strikethroughStyle = textStyle.strikethroughStyle
case .underline(_):
underlineStyle = textStyle.underlineStyle
}

if let font = font {
attributedString.addAttributes([AttributedStringKey.font: font], range: NSRange(element.range, in: parsedString))
}

if let strikethroughStyle = strikethroughStyle {
attributedString.addAttributes([AttributedStringKey.strikethroughStyle: strikethroughStyle.rawValue],
range: NSRange(element.range, in: parsedString))

case .strikethrough(let range):
if let strikethroughStyle = textStyle.strikethroughStyle {
attributedString.addAttributes([AttributedStringKey.strikethroughStyle: strikethroughStyle.rawValue],
range: NSRange(range, in: parsedString))
}
if let strikethroughColor = textStyle.strikethroughColor {
attributedString.addAttributes([AttributedStringKey.strikethroughColor: strikethroughColor],
range: NSRange(element.range, in: parsedString))
range: NSRange(range, in: parsedString))
}
case .underline(let range):
if let underlineStyle = textStyle.underlineStyle {
attributedString.addAttributes([AttributedStringKey.underlineStyle: underlineStyle.rawValue],
range: NSRange(range, in: parsedString))
}
}

if let underlineStyle = underlineStyle {
attributedString.addAttributes([AttributedStringKey.underlineStyle: underlineStyle.rawValue], range: NSRange(element.range, in: parsedString))

if let underlineColor = textStyle.underlineColor {
attributedString.addAttributes([AttributedStringKey.underlineColor: underlineColor], range: NSRange(element.range, in: parsedString))
attributedString.addAttributes([AttributedStringKey.underlineColor: underlineColor],
range: NSRange(range, in: parsedString))
}
case .link(let range, let urlString):
attributedString.addAttribute(AttributedStringKey.link,
value: urlString,
range: NSRange(range, in: parsedString))

if let linkFont = textStyle.linkFont {
attributedString.addAttribute(AttributedStringKey.font,
value: linkFont,
range: NSRange(range, in: parsedString))
}
}

if let font = font {
attributedString.addAttributes([AttributedStringKey.font: font],
range: NSRange(element.range, in: parsedString))
}
}

return attributedString
Expand All @@ -119,17 +124,23 @@ public func parsedMarkupString(from text: String,
return NSAttributedString(string: text, textStyle: textStyle)
}

let (parsedString, elements) = try ElementParser.parse(text, for: markups.map { Symbol(character: $0.0) })

let markupRules = Dictionary(
uniqueKeysWithValues: markups.map { (key, value) in
return (Rule(symbol: Symbol(character: key)), value)
}
)

let (parsedString, elements) = try ElementParser.parse(text, using: Array(markupRules.keys))

let attributedString = NSMutableAttributedString(string: textStyle.textTransform.applied(to: parsedString))
attributedString.addAttributes(textStyle.attributes,
range: NSRange(location: 0, length: parsedString.count))

elements.forEach { (element) in
if let markup = markups[Character(element.symbol.rawValue)] {
if let markup = markupRules[element.rule] {
attributedString.addAttributes(markup.attributes, range: NSRange(element.range, in: parsedString))
}
}

return attributedString
}
2 changes: 1 addition & 1 deletion Marker/Marker/NSAttributedString+Extensions.swift
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
// Copyright © 2017 Prolific Interactive. All rights reserved.
//

internal extension NSAttributedString {
extension NSAttributedString {

/// Initializes `NSAttributedString` instance with given string and text style.
///
Expand Down
Loading

0 comments on commit 3cb8bd7

Please sign in to comment.