Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added Markdown link and backslash escape support #24

Merged
merged 7 commits into from
Nov 8, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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