Compare commits
95 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| db1c0f7902 | |||
| 9a2cd21b15 | |||
| fdbfbcda54 | |||
| 04b2f41c00 | |||
| 957ec2b442 | |||
| 3848d54e45 | |||
| 85b1a0b944 | |||
| 289925e34d | |||
| f8567bd974 | |||
| 10ed2abd88 | |||
| 0e7ede23c3 | |||
| d316d83848 | |||
| 3c149a65e7 | |||
| 7a00026c2d | |||
| 5f8a6ba7dd | |||
| 6797288c0e | |||
| 96e6ac313c | |||
| 76f76d8178 | |||
| ea0717903e | |||
| 845985236a | |||
| e3e89715f8 | |||
| b077d32f52 | |||
| fc9d8b2646 | |||
| 43f94723c8 | |||
| ea306673e8 | |||
| 15f2a353be | |||
| e9fed1ced9 | |||
| 67297197e8 | |||
| 6ee2001d43 | |||
| 4bd6bf498f | |||
| 1f5a6d4e50 | |||
| 04de344a43 | |||
| f386286a7e | |||
| 7c07c37f10 | |||
| 07e9cf69a4 | |||
| c86ae343f1 | |||
| 170e4b6fa2 | |||
| d62bf1dee9 | |||
| c8e6bc6b44 | |||
| 18a1f2922a | |||
| 6d1ec33196 | |||
| 63f489eebe | |||
| 01d153b3ca | |||
| 5148e8ad77 | |||
| 994af3ad6d | |||
| 2b7bfc81d7 | |||
| aaf8f3618a | |||
| a030f210b3 | |||
| be2eaf522c | |||
| d48d6b1f90 | |||
| 100bb3df20 | |||
| 29da129a24 | |||
| 9fcdddf484 | |||
| e653548441 | |||
| ff0fce7eb7 | |||
| 99726212be | |||
| 0bfeba8188 | |||
| 7985b57341 | |||
| cb0ecbd67d | |||
| 1d4fb92429 | |||
| 7f276de733 | |||
| 5870b838e7 | |||
| b2dc325510 | |||
| 195f1a5491 | |||
| cac0c00e0f | |||
| e211af53f5 | |||
| 15c6b77288 | |||
| 4c0a60faa0 | |||
| b0bcb587cb | |||
| 02837925b9 | |||
| cc2ea97b4c | |||
| 0ab154977a | |||
| ac99c2efba | |||
| 39073280de | |||
| 0bca66728f | |||
| 38e2c0d733 | |||
| f4f7c7bd55 | |||
| cd30189674 | |||
| b51f13054c | |||
| 6487a98d90 | |||
| b9a01c7f87 | |||
| c70c5671c8 | |||
| 7bdd5d35ad | |||
| 76b27f4571 | |||
| c27ff1d9a5 | |||
| 0ff9fe8c1c | |||
| eb63a4ea5e | |||
| aa01b6bc58 | |||
| 37f08f09ae | |||
| c96f17edd0 | |||
| 6288214d26 | |||
| 66f5db3d74 | |||
| 057cf6a4e9 | |||
| 1a4cfe06aa | |||
| 455a844912 |
@@ -61,3 +61,6 @@ Carthage/Build
|
||||
|
||||
fastlane/report.xml
|
||||
fastlane/screenshots
|
||||
|
||||
# OS X
|
||||
.DS_Store
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
4.0
|
||||
@@ -0,0 +1,7 @@
|
||||
# frozen_string_literal: true
|
||||
# A sample Gemfile
|
||||
source "https://rubygems.org"
|
||||
|
||||
# gem "rails"
|
||||
gem "cocoapods"
|
||||
gem 'fastlane'
|
||||
+190
@@ -0,0 +1,190 @@
|
||||
GEM
|
||||
remote: https://rubygems.org/
|
||||
specs:
|
||||
CFPropertyList (2.3.5)
|
||||
activesupport (4.2.9)
|
||||
i18n (~> 0.7)
|
||||
minitest (~> 5.1)
|
||||
thread_safe (~> 0.3, >= 0.3.4)
|
||||
tzinfo (~> 1.1)
|
||||
addressable (2.5.2)
|
||||
public_suffix (>= 2.0.2, < 4.0)
|
||||
babosa (1.0.2)
|
||||
claide (1.0.2)
|
||||
cocoapods (1.3.1)
|
||||
activesupport (>= 4.0.2, < 5)
|
||||
claide (>= 1.0.2, < 2.0)
|
||||
cocoapods-core (= 1.3.1)
|
||||
cocoapods-deintegrate (>= 1.0.1, < 2.0)
|
||||
cocoapods-downloader (>= 1.1.3, < 2.0)
|
||||
cocoapods-plugins (>= 1.0.0, < 2.0)
|
||||
cocoapods-search (>= 1.0.0, < 2.0)
|
||||
cocoapods-stats (>= 1.0.0, < 2.0)
|
||||
cocoapods-trunk (>= 1.2.0, < 2.0)
|
||||
cocoapods-try (>= 1.1.0, < 2.0)
|
||||
colored2 (~> 3.1)
|
||||
escape (~> 0.0.4)
|
||||
fourflusher (~> 2.0.1)
|
||||
gh_inspector (~> 1.0)
|
||||
molinillo (~> 0.5.7)
|
||||
nap (~> 1.0)
|
||||
ruby-macho (~> 1.1)
|
||||
xcodeproj (>= 1.5.1, < 2.0)
|
||||
cocoapods-core (1.3.1)
|
||||
activesupport (>= 4.0.2, < 6)
|
||||
fuzzy_match (~> 2.0.4)
|
||||
nap (~> 1.0)
|
||||
cocoapods-deintegrate (1.0.1)
|
||||
cocoapods-downloader (1.1.3)
|
||||
cocoapods-plugins (1.0.0)
|
||||
nap
|
||||
cocoapods-search (1.0.0)
|
||||
cocoapods-stats (1.0.0)
|
||||
cocoapods-trunk (1.2.0)
|
||||
nap (>= 0.8, < 2.0)
|
||||
netrc (= 0.7.8)
|
||||
cocoapods-try (1.1.0)
|
||||
colored (1.2)
|
||||
colored2 (3.1.2)
|
||||
commander-fastlane (4.4.5)
|
||||
highline (~> 1.7.2)
|
||||
declarative (0.0.10)
|
||||
declarative-option (0.1.0)
|
||||
domain_name (0.5.20170404)
|
||||
unf (>= 0.0.5, < 1.0.0)
|
||||
dotenv (2.2.1)
|
||||
escape (0.0.4)
|
||||
excon (0.59.0)
|
||||
faraday (0.13.1)
|
||||
multipart-post (>= 1.2, < 3)
|
||||
faraday-cookie_jar (0.0.6)
|
||||
faraday (>= 0.7.4)
|
||||
http-cookie (~> 1.0.0)
|
||||
faraday_middleware (0.12.2)
|
||||
faraday (>= 0.7.4, < 1.0)
|
||||
fastimage (2.1.0)
|
||||
fastlane (2.58.0)
|
||||
CFPropertyList (>= 2.3, < 3.0.0)
|
||||
addressable (>= 2.3, < 3.0.0)
|
||||
babosa (>= 1.0.2, < 2.0.0)
|
||||
bundler (>= 1.12.0, < 2.0.0)
|
||||
colored
|
||||
commander-fastlane (>= 4.4.5, < 5.0.0)
|
||||
dotenv (>= 2.1.1, < 3.0.0)
|
||||
excon (>= 0.45.0, < 1.0.0)
|
||||
faraday (~> 0.9)
|
||||
faraday-cookie_jar (~> 0.0.6)
|
||||
faraday_middleware (~> 0.9)
|
||||
fastimage (>= 2.1.0, < 3.0.0)
|
||||
gh_inspector (>= 1.0.1, < 2.0.0)
|
||||
google-api-client (>= 0.13.1, < 0.14.0)
|
||||
highline (>= 1.7.2, < 2.0.0)
|
||||
json (< 3.0.0)
|
||||
mini_magick (~> 4.5.1)
|
||||
multi_json
|
||||
multi_xml (~> 0.5)
|
||||
multipart-post (~> 2.0.0)
|
||||
plist (>= 3.1.0, < 4.0.0)
|
||||
public_suffix (~> 2.0.0)
|
||||
rubyzip (>= 1.1.0, < 2.0.0)
|
||||
security (= 0.1.3)
|
||||
slack-notifier (>= 1.3, < 2.0.0)
|
||||
terminal-notifier (>= 1.6.2, < 2.0.0)
|
||||
terminal-table (>= 1.4.5, < 2.0.0)
|
||||
tty-screen (~> 0.5.0)
|
||||
word_wrap (~> 1.0.0)
|
||||
xcodeproj (>= 1.5.0, < 2.0.0)
|
||||
xcpretty (>= 0.2.4, < 1.0.0)
|
||||
xcpretty-travis-formatter (>= 0.0.3)
|
||||
fourflusher (2.0.1)
|
||||
fuzzy_match (2.0.4)
|
||||
gh_inspector (1.0.3)
|
||||
google-api-client (0.13.6)
|
||||
addressable (~> 2.5, >= 2.5.1)
|
||||
googleauth (~> 0.5)
|
||||
httpclient (>= 2.8.1, < 3.0)
|
||||
mime-types (~> 3.0)
|
||||
representable (~> 3.0)
|
||||
retriable (>= 2.0, < 4.0)
|
||||
googleauth (0.5.3)
|
||||
faraday (~> 0.12)
|
||||
jwt (~> 1.4)
|
||||
logging (~> 2.0)
|
||||
memoist (~> 0.12)
|
||||
multi_json (~> 1.11)
|
||||
os (~> 0.9)
|
||||
signet (~> 0.7)
|
||||
highline (1.7.8)
|
||||
http-cookie (1.0.3)
|
||||
domain_name (~> 0.5)
|
||||
httpclient (2.8.3)
|
||||
i18n (0.8.6)
|
||||
json (2.1.0)
|
||||
jwt (1.5.6)
|
||||
little-plugger (1.1.4)
|
||||
logging (2.2.2)
|
||||
little-plugger (~> 1.1)
|
||||
multi_json (~> 1.10)
|
||||
memoist (0.16.0)
|
||||
mime-types (3.1)
|
||||
mime-types-data (~> 3.2015)
|
||||
mime-types-data (3.2016.0521)
|
||||
mini_magick (4.5.1)
|
||||
minitest (5.10.3)
|
||||
molinillo (0.5.7)
|
||||
multi_json (1.12.2)
|
||||
multi_xml (0.6.0)
|
||||
multipart-post (2.0.0)
|
||||
nanaimo (0.2.3)
|
||||
nap (1.1.0)
|
||||
netrc (0.7.8)
|
||||
os (0.9.6)
|
||||
plist (3.3.0)
|
||||
public_suffix (2.0.5)
|
||||
representable (3.0.4)
|
||||
declarative (< 0.1.0)
|
||||
declarative-option (< 0.2.0)
|
||||
uber (< 0.2.0)
|
||||
retriable (3.1.1)
|
||||
rouge (2.0.7)
|
||||
ruby-macho (1.1.0)
|
||||
rubyzip (1.2.2)
|
||||
security (0.1.3)
|
||||
signet (0.7.3)
|
||||
addressable (~> 2.3)
|
||||
faraday (~> 0.9)
|
||||
jwt (~> 1.5)
|
||||
multi_json (~> 1.10)
|
||||
slack-notifier (1.5.1)
|
||||
terminal-notifier (1.8.0)
|
||||
terminal-table (1.8.0)
|
||||
unicode-display_width (~> 1.1, >= 1.1.1)
|
||||
thread_safe (0.3.6)
|
||||
tty-screen (0.5.0)
|
||||
tzinfo (1.2.3)
|
||||
thread_safe (~> 0.1)
|
||||
uber (0.1.0)
|
||||
unf (0.1.4)
|
||||
unf_ext
|
||||
unf_ext (0.0.7.4)
|
||||
unicode-display_width (1.3.0)
|
||||
word_wrap (1.0.0)
|
||||
xcodeproj (1.5.1)
|
||||
CFPropertyList (~> 2.3.3)
|
||||
claide (>= 1.0.2, < 2.0)
|
||||
colored2 (~> 3.1)
|
||||
nanaimo (~> 0.2.3)
|
||||
xcpretty (0.2.8)
|
||||
rouge (~> 2.0.7)
|
||||
xcpretty-travis-formatter (0.0.4)
|
||||
xcpretty (~> 0.2, >= 0.0.7)
|
||||
|
||||
PLATFORMS
|
||||
ruby
|
||||
|
||||
DEPENDENCIES
|
||||
cocoapods
|
||||
fastlane
|
||||
|
||||
BUNDLED WITH
|
||||
1.14.5
|
||||
@@ -2,28 +2,54 @@
|
||||
|
||||
SwiftyMarkdown converts Markdown files and strings into NSAttributedString using sensible defaults and a Swift-style syntax. It uses dynamic type to set the font size correctly with whatever font you'd like to use
|
||||
|
||||
## Installation
|
||||
|
||||
CocoaPods:
|
||||
|
||||
`pod 'SwiftyMarkdown'`
|
||||
|
||||
## Usage
|
||||
|
||||
Text string
|
||||
|
||||
let md = SwiftyMarkdown(string: "# Heading\nMy *Markdown* string")
|
||||
md.attributedString()
|
||||
```swift
|
||||
let md = SwiftyMarkdown(string: "# Heading\nMy *Markdown* string")
|
||||
md.attributedString()
|
||||
```
|
||||
|
||||
URL
|
||||
```swift
|
||||
if let url = Bundle.main.url(forResource: "file", withExtension: "md"), md = SwiftyMarkdown(url: url ) {
|
||||
md.attributedString()
|
||||
}
|
||||
```
|
||||
|
||||
if let url = NSBundle.mainBundle().URLForResource("file", withExtension: "md"), md = SwiftyMarkdown(url: url ) {
|
||||
md.attributedString()
|
||||
}
|
||||
## Supported Features
|
||||
|
||||
*italics* or _italics_
|
||||
**bold** or __bold__
|
||||
|
||||
# Header 1
|
||||
## Header 2
|
||||
### Header 3
|
||||
#### Header 4
|
||||
##### Header 5
|
||||
###### Header 6
|
||||
|
||||
`code`
|
||||
[Links](http://voyagetravelapps.com/)
|
||||
|
||||
## Customisation
|
||||
```swift
|
||||
md.body.fontName = "AvenirNextCondensed-Medium"
|
||||
|
||||
md.body.fontName = "AvenirNextCondensed-Medium"
|
||||
|
||||
md.h1.color = UIColor.redColor()
|
||||
md.h1.fontName = "AvenirNextCondensed-Bold"
|
||||
|
||||
md.h1.color = UIColor.redColor()
|
||||
md.h1.fontName = "AvenirNextCondensed-Bold"
|
||||
md.h1.fontSize = 16
|
||||
```
|
||||
md.italic.color = UIColor.blueColor()
|
||||
|
||||
## Screenshot
|
||||
|
||||

|
||||

|
||||
|
||||
|
||||
|
||||
@@ -1,313 +1,322 @@
|
||||
//: Playground - noun: a place where people can play
|
||||
|
||||
import UIKit
|
||||
import XCPlayground
|
||||
import PlaygroundSupport
|
||||
|
||||
let containerView = UIView(frame: CGRect(x: 0.0, y: 0.0, width: 400.0, height: 600))
|
||||
|
||||
XCPlaygroundPage.currentPage.liveView = containerView
|
||||
PlaygroundPage.current.liveView = containerView
|
||||
let label = UITextView(frame: containerView.frame)
|
||||
containerView.addSubview(label)
|
||||
|
||||
|
||||
public protocol FontProperties {
|
||||
var fontName : String { get set }
|
||||
var color : UIColor { get set }
|
||||
var foundCharacters : String = ""
|
||||
var matchedCharacters : String = "\\Some string ''\\"
|
||||
if let hasRange = matchedCharacters.range(of: "\\") {
|
||||
|
||||
let newRange = hasRange.lowerBound..<hasRange.upperBound
|
||||
foundCharacters = foundCharacters + matchedCharacters[newRange]
|
||||
|
||||
matchedCharacters.removeSubrange(newRange)
|
||||
}
|
||||
|
||||
|
||||
public struct BasicStyles : FontProperties {
|
||||
public var fontName = UIFont.preferredFontForTextStyle(UIFontTextStyleBody).fontName
|
||||
public var color = UIColor.blackColor()
|
||||
}
|
||||
|
||||
enum LineType : Int {
|
||||
case H1, H2, H3, H4, H5, H6, Body, Italic, Bold, Code
|
||||
}
|
||||
|
||||
|
||||
public class SwiftyMarkdown {
|
||||
|
||||
public var h1 = BasicStyles()
|
||||
public var h2 = BasicStyles()
|
||||
public var h3 = BasicStyles()
|
||||
public var h4 = BasicStyles()
|
||||
public var h5 = BasicStyles()
|
||||
public var h6 = BasicStyles()
|
||||
|
||||
public var body = BasicStyles()
|
||||
public var link = BasicStyles()
|
||||
public var italic = BasicStyles()
|
||||
public var code = BasicStyles()
|
||||
public var bold = BasicStyles()
|
||||
|
||||
let string : String
|
||||
let instructionSet = NSCharacterSet(charactersInString: "\\*_`")
|
||||
|
||||
public init(string : String ) {
|
||||
self.string = string
|
||||
}
|
||||
|
||||
public init?(url : NSURL ) {
|
||||
|
||||
do {
|
||||
self.string = try NSString(contentsOfURL: url, encoding: NSUTF8StringEncoding) as String
|
||||
|
||||
} catch {
|
||||
self.string = ""
|
||||
fatalError("Couldn't read string")
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
public func attributedString() -> NSAttributedString {
|
||||
let attributedString = NSMutableAttributedString(string: "")
|
||||
|
||||
let lines = self.string.componentsSeparatedByCharactersInSet(NSCharacterSet.newlineCharacterSet())
|
||||
|
||||
var lineCount = 0
|
||||
|
||||
let headings = ["# ", "## ", "### ", "#### ", "##### ", "###### "]
|
||||
|
||||
|
||||
var skipLine = false
|
||||
for line in lines {
|
||||
lineCount++
|
||||
if skipLine {
|
||||
skipLine = false
|
||||
continue
|
||||
}
|
||||
var headingFound = false
|
||||
for heading in headings {
|
||||
|
||||
if let range = line.rangeOfString(heading) where range.startIndex == line.startIndex {
|
||||
|
||||
let startHeadingString = line.stringByReplacingCharactersInRange(range, withString: "")
|
||||
let endHeadingHash = " " + heading.stringByTrimmingCharactersInSet(NSCharacterSet.whitespaceAndNewlineCharacterSet())
|
||||
|
||||
let finalHeadingString = startHeadingString.stringByReplacingOccurrencesOfString(endHeadingHash, withString: "")
|
||||
|
||||
// Make Hx where x == current index
|
||||
let string = attributedStringFromString(finalHeadingString, withType: LineType(rawValue: headings.indexOf(heading)!)!)
|
||||
attributedString.appendAttributedString(string)
|
||||
headingFound = true
|
||||
}
|
||||
}
|
||||
if headingFound {
|
||||
continue
|
||||
}
|
||||
|
||||
|
||||
if lineCount < lines.count {
|
||||
let nextLine = lines[lineCount]
|
||||
|
||||
if let range = nextLine.rangeOfString("=") where range.startIndex == nextLine.startIndex {
|
||||
// Make H1
|
||||
let string = attributedStringFromString(line, withType: .H1)
|
||||
attributedString.appendAttributedString(string)
|
||||
skipLine = true
|
||||
continue
|
||||
}
|
||||
|
||||
if let range = nextLine.rangeOfString("-") where range.startIndex == nextLine.startIndex {
|
||||
|
||||
|
||||
// Make H1
|
||||
let string = attributedStringFromString(line, withType: .H2)
|
||||
attributedString.appendAttributedString(string)
|
||||
skipLine = true
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
if line.characters.count > 0 {
|
||||
|
||||
let scanner = NSScanner(string: line)
|
||||
|
||||
|
||||
scanner.charactersToBeSkipped = nil
|
||||
|
||||
while !scanner.atEnd {
|
||||
|
||||
var followingString : NSString?
|
||||
var string : NSString?
|
||||
// Get all the characters up to the ones we are interested in
|
||||
if scanner.scanUpToCharactersFromSet(instructionSet, intoString: &string) {
|
||||
if let hasString = string as? String {
|
||||
let bodyString = attributedStringFromString(hasString, withType: .Body)
|
||||
attributedString.appendAttributedString(bodyString)
|
||||
|
||||
var matchedCharacters = self.tagFromScanner(scanner)
|
||||
|
||||
|
||||
let location = scanner.scanLocation
|
||||
// If the next string after the characters is a space, then add it to the final string and continue
|
||||
if !scanner.scanUpToString(" ", intoString: nil) {
|
||||
|
||||
let charAtts = attributedStringFromString(matchedCharacters, withType: .Body)
|
||||
|
||||
attributedString.appendAttributedString(charAtts)
|
||||
} else {
|
||||
scanner.scanLocation = location
|
||||
scanner.scanUpToCharactersFromSet(instructionSet, intoString: &followingString)
|
||||
if let hasString = followingString as? String {
|
||||
let attString : NSAttributedString
|
||||
|
||||
if matchedCharacters.containsString("\\") {
|
||||
attString = attributedStringFromString(matchedCharacters + hasString, withType: .Body)
|
||||
} else if matchedCharacters == "**" || matchedCharacters == "__" {
|
||||
attString = attributedStringFromString(hasString, withType: .Bold)
|
||||
} else {
|
||||
attString = attributedStringFromString(hasString, withType: .Italic)
|
||||
}
|
||||
attributedString.appendAttributedString(attString)
|
||||
}
|
||||
matchedCharacters = self.tagFromScanner(scanner)
|
||||
|
||||
if matchedCharacters.containsString("\\") {
|
||||
let attString = attributedStringFromString(matchedCharacters, withType: .Body)
|
||||
|
||||
attributedString.appendAttributedString(attString)
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
} else {
|
||||
var matchedCharacters = self.tagFromScanner(scanner)
|
||||
|
||||
scanner.scanUpToCharactersFromSet(instructionSet, intoString: &followingString)
|
||||
if let hasString = followingString as? String {
|
||||
let attString : NSAttributedString
|
||||
|
||||
if matchedCharacters.containsString("\\") {
|
||||
attString = attributedStringFromString(matchedCharacters + hasString, withType: .Body)
|
||||
} else if matchedCharacters == "**" || matchedCharacters == "__" {
|
||||
attString = attributedStringFromString(hasString, withType: .Bold)
|
||||
} else {
|
||||
attString = attributedStringFromString(hasString, withType: .Italic)
|
||||
}
|
||||
attributedString.appendAttributedString(attString)
|
||||
}
|
||||
matchedCharacters = self.tagFromScanner(scanner)
|
||||
|
||||
if matchedCharacters.containsString("\\") {
|
||||
let attString = attributedStringFromString(matchedCharacters, withType: .Body)
|
||||
|
||||
attributedString.appendAttributedString(attString)
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
attributedString.appendAttributedString(NSAttributedString(string: "\n"))
|
||||
}
|
||||
|
||||
return attributedString
|
||||
}
|
||||
|
||||
func tagFromScanner( scanner : NSScanner ) -> String {
|
||||
var matchedCharacters : String = ""
|
||||
var tempCharacters : NSString?
|
||||
|
||||
// Scan the ones we are interested in
|
||||
while scanner.scanCharactersFromSet(instructionSet, intoString: &tempCharacters) {
|
||||
if let chars = tempCharacters as? String {
|
||||
matchedCharacters = matchedCharacters + chars
|
||||
}
|
||||
}
|
||||
return matchedCharacters
|
||||
}
|
||||
|
||||
|
||||
// Make H1
|
||||
|
||||
func attributedStringFromString(string : String, withType type : LineType ) -> NSAttributedString {
|
||||
var attributes : [String : AnyObject]
|
||||
let textStyle : String
|
||||
let fontName : String
|
||||
|
||||
var appendNewLine = true
|
||||
|
||||
switch type {
|
||||
case .H1:
|
||||
fontName = h1.fontName
|
||||
|
||||
if #available(iOS 9, *) {
|
||||
textStyle = UIFontTextStyleTitle1
|
||||
}
|
||||
attributes = [NSForegroundColorAttributeName : h1.color]
|
||||
case .H2:
|
||||
fontName = h2.fontName
|
||||
textStyle = UIFontTextStyleTitle2
|
||||
attributes = [NSForegroundColorAttributeName : h2.color]
|
||||
case .H3:
|
||||
fontName = h3.fontName
|
||||
textStyle = UIFontTextStyleTitle3
|
||||
attributes = [NSForegroundColorAttributeName : h3.color]
|
||||
case .H4:
|
||||
fontName = h4.fontName
|
||||
textStyle = UIFontTextStyleHeadline
|
||||
attributes = [NSForegroundColorAttributeName : h4.color]
|
||||
case .H5:
|
||||
fontName = h5.fontName
|
||||
textStyle = UIFontTextStyleSubheadline
|
||||
attributes = [NSForegroundColorAttributeName : h5.color]
|
||||
case .H6:
|
||||
fontName = h6.fontName
|
||||
textStyle = UIFontTextStyleFootnote
|
||||
attributes = [NSForegroundColorAttributeName : h6.color]
|
||||
case .Italic:
|
||||
fontName = italic.fontName
|
||||
attributes = [NSForegroundColorAttributeName : italic.color]
|
||||
textStyle = UIFontTextStyleBody
|
||||
appendNewLine = false
|
||||
case .Bold:
|
||||
fontName = bold.fontName
|
||||
attributes = [NSForegroundColorAttributeName : bold.color]
|
||||
appendNewLine = false
|
||||
textStyle = UIFontTextStyleBody
|
||||
default:
|
||||
appendNewLine = false
|
||||
fontName = body.fontName
|
||||
textStyle = UIFontTextStyleBody
|
||||
attributes = [NSForegroundColorAttributeName:body.color]
|
||||
break
|
||||
}
|
||||
|
||||
let font = UIFont.preferredFontForTextStyle(textStyle)
|
||||
let styleDescriptor = font.fontDescriptor()
|
||||
let styleSize = styleDescriptor.fontAttributes()[UIFontDescriptorSizeAttribute] as? CGFloat ?? CGFloat(14)
|
||||
|
||||
var finalFont : UIFont
|
||||
if let font = UIFont(name: fontName, size: styleSize) {
|
||||
finalFont = font
|
||||
} else {
|
||||
finalFont = UIFont.preferredFontForTextStyle(textStyle)
|
||||
}
|
||||
|
||||
let finalFontDescriptor = finalFont.fontDescriptor()
|
||||
if type == .Italic {
|
||||
let italicDescriptor = finalFontDescriptor.fontDescriptorWithSymbolicTraits(.TraitItalic)
|
||||
finalFont = UIFont(descriptor: italicDescriptor, size: styleSize)
|
||||
}
|
||||
if type == .Bold {
|
||||
let boldDescriptor = finalFontDescriptor.fontDescriptorWithSymbolicTraits(.TraitBold)
|
||||
finalFont = UIFont(descriptor: boldDescriptor, size: styleSize)
|
||||
}
|
||||
|
||||
|
||||
attributes[NSFontAttributeName] = finalFont
|
||||
|
||||
if appendNewLine {
|
||||
return NSAttributedString(string: string + "\n", attributes: attributes)
|
||||
} else {
|
||||
return NSAttributedString(string: string, attributes: attributes)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if let url = NSBundle.mainBundle().URLForResource("test", withExtension: "md"), md = SwiftyMarkdown(url: url) {
|
||||
|
||||
label.attributedText = md.attributedString()
|
||||
}
|
||||
|
||||
//
|
||||
//public protocol FontProperties {
|
||||
// var fontName : String { get set }
|
||||
// var color : UIColor { get set }
|
||||
//}
|
||||
//
|
||||
//
|
||||
//public struct BasicStyles : FontProperties {
|
||||
// public var fontName = UIFont.preferredFontForTextStyle(UIFontTextStyleBody).fontName
|
||||
// public var color = UIColor.blackColor()
|
||||
//}
|
||||
//
|
||||
//enum LineType : Int {
|
||||
// case H1, H2, H3, H4, H5, H6, Body, Italic, Bold, Code
|
||||
//}
|
||||
//
|
||||
//
|
||||
//public class SwiftyMarkdown {
|
||||
//
|
||||
// public var h1 = BasicStyles()
|
||||
// public var h2 = BasicStyles()
|
||||
// public var h3 = BasicStyles()
|
||||
// public var h4 = BasicStyles()
|
||||
// public var h5 = BasicStyles()
|
||||
// public var h6 = BasicStyles()
|
||||
//
|
||||
// public var body = BasicStyles()
|
||||
// public var link = BasicStyles()
|
||||
// public var italic = BasicStyles()
|
||||
// public var code = BasicStyles()
|
||||
// public var bold = BasicStyles()
|
||||
//
|
||||
// let string : String
|
||||
// let instructionSet = NSCharacterSet(charactersInString: "\\*_`")
|
||||
//
|
||||
// public init(string : String ) {
|
||||
// self.string = string
|
||||
// }
|
||||
//
|
||||
// public init?(url : NSURL ) {
|
||||
//
|
||||
// do {
|
||||
// self.string = try NSString(contentsOfURL: url, encoding: NSUTF8StringEncoding) as String
|
||||
//
|
||||
// } catch {
|
||||
// self.string = ""
|
||||
// fatalError("Couldn't read string")
|
||||
// return nil
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// public func attributedString() -> NSAttributedString {
|
||||
// let attributedString = NSMutableAttributedString(string: "")
|
||||
//
|
||||
// let lines = self.string.componentsSeparatedByCharactersInSet(NSCharacterSet.newlineCharacterSet())
|
||||
//
|
||||
// var lineCount = 0
|
||||
//
|
||||
// let headings = ["# ", "## ", "### ", "#### ", "##### ", "###### "]
|
||||
//
|
||||
//
|
||||
// var skipLine = false
|
||||
// for line in lines {
|
||||
// lineCount++
|
||||
// if skipLine {
|
||||
// skipLine = false
|
||||
// continue
|
||||
// }
|
||||
// var headingFound = false
|
||||
// for heading in headings {
|
||||
//
|
||||
// if let range = line.rangeOfString(heading) where range.startIndex == line.startIndex {
|
||||
//
|
||||
// let startHeadingString = line.stringByReplacingCharactersInRange(range, withString: "")
|
||||
// let endHeadingHash = " " + heading.stringByTrimmingCharactersInSet(NSCharacterSet.whitespaceAndNewlineCharacterSet())
|
||||
//
|
||||
// let finalHeadingString = startHeadingString.stringByReplacingOccurrencesOfString(endHeadingHash, withString: "")
|
||||
//
|
||||
// // Make Hx where x == current index
|
||||
// let string = attributedStringFromString(finalHeadingString, withType: LineType(rawValue: headings.indexOf(heading)!)!)
|
||||
// attributedString.appendAttributedString(string)
|
||||
// headingFound = true
|
||||
// }
|
||||
// }
|
||||
// if headingFound {
|
||||
// continue
|
||||
// }
|
||||
//
|
||||
//
|
||||
// if lineCount < lines.count {
|
||||
// let nextLine = lines[lineCount]
|
||||
//
|
||||
// if let range = nextLine.rangeOfString("=") where range.startIndex == nextLine.startIndex {
|
||||
// // Make H1
|
||||
// let string = attributedStringFromString(line, withType: .H1)
|
||||
// attributedString.appendAttributedString(string)
|
||||
// skipLine = true
|
||||
// continue
|
||||
// }
|
||||
//
|
||||
// if let range = nextLine.rangeOfString("-") where range.startIndex == nextLine.startIndex {
|
||||
//
|
||||
//
|
||||
// // Make H1
|
||||
// let string = attributedStringFromString(line, withType: .H2)
|
||||
// attributedString.appendAttributedString(string)
|
||||
// skipLine = true
|
||||
// continue
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// if line.characters.count > 0 {
|
||||
//
|
||||
// let scanner = NSScanner(string: line)
|
||||
//
|
||||
//
|
||||
// scanner.charactersToBeSkipped = nil
|
||||
//
|
||||
// while !scanner.atEnd {
|
||||
//
|
||||
// var followingString : NSString?
|
||||
// var string : NSString?
|
||||
// // Get all the characters up to the ones we are interested in
|
||||
// if scanner.scanUpToCharactersFromSet(instructionSet, intoString: &string) {
|
||||
// if let hasString = string as? String {
|
||||
// let bodyString = attributedStringFromString(hasString, withType: .Body)
|
||||
// attributedString.appendAttributedString(bodyString)
|
||||
//
|
||||
// var matchedCharacters = self.tagFromScanner(scanner)
|
||||
//
|
||||
//
|
||||
// let location = scanner.scanLocation
|
||||
// // If the next string after the characters is a space, then add it to the final string and continue
|
||||
// if !scanner.scanUpToString(" ", intoString: nil) {
|
||||
//
|
||||
// let charAtts = attributedStringFromString(matchedCharacters, withType: .Body)
|
||||
//
|
||||
// attributedString.appendAttributedString(charAtts)
|
||||
// } else {
|
||||
// scanner.scanLocation = location
|
||||
// scanner.scanUpToCharactersFromSet(instructionSet, intoString: &followingString)
|
||||
// if let hasString = followingString as? String {
|
||||
// let attString : NSAttributedString
|
||||
//
|
||||
// if matchedCharacters.containsString("\\") {
|
||||
// attString = attributedStringFromString(matchedCharacters + hasString, withType: .Body)
|
||||
// } else if matchedCharacters == "**" || matchedCharacters == "__" {
|
||||
// attString = attributedStringFromString(hasString, withType: .Bold)
|
||||
// } else {
|
||||
// attString = attributedStringFromString(hasString, withType: .Italic)
|
||||
// }
|
||||
// attributedString.appendAttributedString(attString)
|
||||
// }
|
||||
// matchedCharacters = self.tagFromScanner(scanner)
|
||||
//
|
||||
// if matchedCharacters.containsString("\\") {
|
||||
// let attString = attributedStringFromString(matchedCharacters, withType: .Body)
|
||||
//
|
||||
// attributedString.appendAttributedString(attString)
|
||||
// }
|
||||
//
|
||||
// }
|
||||
// }
|
||||
// } else {
|
||||
// var matchedCharacters = self.tagFromScanner(scanner)
|
||||
//
|
||||
// scanner.scanUpToCharactersFromSet(instructionSet, intoString: &followingString)
|
||||
// if let hasString = followingString as? String {
|
||||
// let attString : NSAttributedString
|
||||
//
|
||||
// if matchedCharacters.containsString("\\") {
|
||||
// attString = attributedStringFromString(matchedCharacters + hasString, withType: .Body)
|
||||
// } else if matchedCharacters == "**" || matchedCharacters == "__" {
|
||||
// attString = attributedStringFromString(hasString, withType: .Bold)
|
||||
// } else {
|
||||
// attString = attributedStringFromString(hasString, withType: .Italic)
|
||||
// }
|
||||
// attributedString.appendAttributedString(attString)
|
||||
// }
|
||||
// matchedCharacters = self.tagFromScanner(scanner)
|
||||
//
|
||||
// if matchedCharacters.containsString("\\") {
|
||||
// let attString = attributedStringFromString(matchedCharacters, withType: .Body)
|
||||
//
|
||||
// attributedString.appendAttributedString(attString)
|
||||
// }
|
||||
//
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// attributedString.appendAttributedString(NSAttributedString(string: "\n"))
|
||||
// }
|
||||
//
|
||||
// return attributedString
|
||||
// }
|
||||
//
|
||||
// func tagFromScanner( scanner : NSScanner ) -> String {
|
||||
// var matchedCharacters : String = ""
|
||||
// var tempCharacters : NSString?
|
||||
//
|
||||
// // Scan the ones we are interested in
|
||||
// while scanner.scanCharactersFromSet(instructionSet, intoString: &tempCharacters) {
|
||||
// if let chars = tempCharacters as? String {
|
||||
// matchedCharacters = matchedCharacters + chars
|
||||
// }
|
||||
// }
|
||||
// return matchedCharacters
|
||||
// }
|
||||
//
|
||||
//
|
||||
// // Make H1
|
||||
//
|
||||
// func attributedStringFromString(string : String, withType type : LineType ) -> NSAttributedString {
|
||||
// var attributes : [String : AnyObject]
|
||||
// let textStyle : String
|
||||
// let fontName : String
|
||||
//
|
||||
// var appendNewLine = true
|
||||
//
|
||||
// switch type {
|
||||
// case .H1:
|
||||
// fontName = h1.fontName
|
||||
//
|
||||
// if #available(iOS 9, *) {
|
||||
// textStyle = UIFontTextStyleTitle1
|
||||
// }
|
||||
// attributes = [NSForegroundColorAttributeName : h1.color]
|
||||
// case .H2:
|
||||
// fontName = h2.fontName
|
||||
// textStyle = UIFontTextStyleTitle2
|
||||
// attributes = [NSForegroundColorAttributeName : h2.color]
|
||||
// case .H3:
|
||||
// fontName = h3.fontName
|
||||
// textStyle = UIFontTextStyleTitle3
|
||||
// attributes = [NSForegroundColorAttributeName : h3.color]
|
||||
// case .H4:
|
||||
// fontName = h4.fontName
|
||||
// textStyle = UIFontTextStyleHeadline
|
||||
// attributes = [NSForegroundColorAttributeName : h4.color]
|
||||
// case .H5:
|
||||
// fontName = h5.fontName
|
||||
// textStyle = UIFontTextStyleSubheadline
|
||||
// attributes = [NSForegroundColorAttributeName : h5.color]
|
||||
// case .H6:
|
||||
// fontName = h6.fontName
|
||||
// textStyle = UIFontTextStyleFootnote
|
||||
// attributes = [NSForegroundColorAttributeName : h6.color]
|
||||
// case .Italic:
|
||||
// fontName = italic.fontName
|
||||
// attributes = [NSForegroundColorAttributeName : italic.color]
|
||||
// textStyle = UIFontTextStyleBody
|
||||
// appendNewLine = false
|
||||
// case .Bold:
|
||||
// fontName = bold.fontName
|
||||
// attributes = [NSForegroundColorAttributeName : bold.color]
|
||||
// appendNewLine = false
|
||||
// textStyle = UIFontTextStyleBody
|
||||
// default:
|
||||
// appendNewLine = false
|
||||
// fontName = body.fontName
|
||||
// textStyle = UIFontTextStyleBody
|
||||
// attributes = [NSForegroundColorAttributeName:body.color]
|
||||
// break
|
||||
// }
|
||||
//
|
||||
// let font = UIFont.preferredFontForTextStyle(textStyle)
|
||||
// let styleDescriptor = font.fontDescriptor()
|
||||
// let styleSize = styleDescriptor.fontAttributes()[UIFontDescriptorSizeAttribute] as? CGFloat ?? CGFloat(14)
|
||||
//
|
||||
// var finalFont : UIFont
|
||||
// if let font = UIFont(name: fontName, size: styleSize) {
|
||||
// finalFont = font
|
||||
// } else {
|
||||
// finalFont = UIFont.preferredFontForTextStyle(textStyle)
|
||||
// }
|
||||
//
|
||||
// let finalFontDescriptor = finalFont.fontDescriptor()
|
||||
// if type == .Italic {
|
||||
// let italicDescriptor = finalFontDescriptor.fontDescriptorWithSymbolicTraits(.TraitItalic)
|
||||
// finalFont = UIFont(descriptor: italicDescriptor, size: styleSize)
|
||||
// }
|
||||
// if type == .Bold {
|
||||
// let boldDescriptor = finalFontDescriptor.fontDescriptorWithSymbolicTraits(.TraitBold)
|
||||
// finalFont = UIFont(descriptor: boldDescriptor, size: styleSize)
|
||||
// }
|
||||
//
|
||||
//
|
||||
// attributes[NSFontAttributeName] = finalFont
|
||||
//
|
||||
// if appendNewLine {
|
||||
// return NSAttributedString(string: string + "\n", attributes: attributes)
|
||||
// } else {
|
||||
// return NSAttributedString(string: string, attributes: attributes)
|
||||
// }
|
||||
// }
|
||||
//}
|
||||
//
|
||||
//if let url = NSBundle.mainBundle().URLForResource("test", withExtension: "md"), md = SwiftyMarkdown(url: url) {
|
||||
//
|
||||
// label.attributedText = md.attributedString()
|
||||
//}
|
||||
//
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
||||
<playground version='5.0' target-platform='ios'>
|
||||
<playground version='5.0' target-platform='ios' last-migration='0900'>
|
||||
<timeline fileName='timeline.xctimeline'/>
|
||||
</playground>
|
||||
@@ -1,14 +1,15 @@
|
||||
Pod::Spec.new do |s|
|
||||
s.name = "SwiftyMarkdown"
|
||||
s.version = "0.2.2"
|
||||
s.version = "0.6.0"
|
||||
s.summary = "Converts Markdown to NSAttributed String"
|
||||
s.homepage = "https://github.com/SimonFairbairn/Stormcloud"
|
||||
s.homepage = "https://github.com/SimonFairbairn/SwiftyMarkdown"
|
||||
s.license = 'MIT'
|
||||
s.author = { "Simon Fairbairn" => "simon@voyagetravelapps.com" }
|
||||
s.source = { :git => "https://github.com/SimonFairbairn/SwiftyMarkdown.git", :tag => s.version }
|
||||
s.social_media_url = 'https://twitter.com/SimonFairbairn'
|
||||
|
||||
s.ios.deployment_target = '8.0'
|
||||
s.ios.deployment_target = "8.0"
|
||||
s.tvos.deployment_target = "9.0"
|
||||
s.requires_arc = true
|
||||
|
||||
s.source_files = 'SwiftyMarkdown/'
|
||||
|
||||
@@ -154,14 +154,17 @@
|
||||
isa = PBXProject;
|
||||
attributes = {
|
||||
LastSwiftUpdateCheck = 0720;
|
||||
LastUpgradeCheck = 0720;
|
||||
LastUpgradeCheck = 1000;
|
||||
ORGANIZATIONNAME = "Voyage Travel Apps";
|
||||
TargetAttributes = {
|
||||
F4CE98801C8A921300D735C1 = {
|
||||
CreatedOnToolsVersion = 7.2.1;
|
||||
LastSwiftMigration = 1000;
|
||||
};
|
||||
F4CE988A1C8A921300D735C1 = {
|
||||
CreatedOnToolsVersion = 7.2.1;
|
||||
DevelopmentTeam = 52T262DA8V;
|
||||
LastSwiftMigration = 1000;
|
||||
};
|
||||
};
|
||||
};
|
||||
@@ -238,18 +241,28 @@
|
||||
CLANG_CXX_LIBRARY = "libc++";
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CLANG_ENABLE_OBJC_ARC = YES;
|
||||
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
|
||||
CLANG_WARN_BOOL_CONVERSION = YES;
|
||||
CLANG_WARN_COMMA = YES;
|
||||
CLANG_WARN_CONSTANT_CONVERSION = YES;
|
||||
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
|
||||
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
|
||||
CLANG_WARN_EMPTY_BODY = YES;
|
||||
CLANG_WARN_ENUM_CONVERSION = YES;
|
||||
CLANG_WARN_INFINITE_RECURSION = YES;
|
||||
CLANG_WARN_INT_CONVERSION = YES;
|
||||
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
|
||||
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
|
||||
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
|
||||
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
|
||||
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
|
||||
CLANG_WARN_STRICT_PROTOTYPES = YES;
|
||||
CLANG_WARN_SUSPICIOUS_MOVE = YES;
|
||||
CLANG_WARN_UNREACHABLE_CODE = YES;
|
||||
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
|
||||
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
|
||||
COPY_PHASE_STRIP = NO;
|
||||
CURRENT_PROJECT_VERSION = 12;
|
||||
CURRENT_PROJECT_VERSION = 19;
|
||||
DEBUG_INFORMATION_FORMAT = dwarf;
|
||||
ENABLE_STRICT_OBJC_MSGSEND = YES;
|
||||
ENABLE_TESTABILITY = YES;
|
||||
@@ -286,18 +299,28 @@
|
||||
CLANG_CXX_LIBRARY = "libc++";
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CLANG_ENABLE_OBJC_ARC = YES;
|
||||
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
|
||||
CLANG_WARN_BOOL_CONVERSION = YES;
|
||||
CLANG_WARN_COMMA = YES;
|
||||
CLANG_WARN_CONSTANT_CONVERSION = YES;
|
||||
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
|
||||
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
|
||||
CLANG_WARN_EMPTY_BODY = YES;
|
||||
CLANG_WARN_ENUM_CONVERSION = YES;
|
||||
CLANG_WARN_INFINITE_RECURSION = YES;
|
||||
CLANG_WARN_INT_CONVERSION = YES;
|
||||
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
|
||||
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
|
||||
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
|
||||
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
|
||||
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
|
||||
CLANG_WARN_STRICT_PROTOTYPES = YES;
|
||||
CLANG_WARN_SUSPICIOUS_MOVE = YES;
|
||||
CLANG_WARN_UNREACHABLE_CODE = YES;
|
||||
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
|
||||
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
|
||||
COPY_PHASE_STRIP = NO;
|
||||
CURRENT_PROJECT_VERSION = 12;
|
||||
CURRENT_PROJECT_VERSION = 19;
|
||||
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
|
||||
ENABLE_NS_ASSERTIONS = NO;
|
||||
ENABLE_STRICT_OBJC_MSGSEND = YES;
|
||||
@@ -312,6 +335,7 @@
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 9.2;
|
||||
MTL_ENABLE_DEBUG_INFO = NO;
|
||||
SDKROOT = iphoneos;
|
||||
SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule";
|
||||
TARGETED_DEVICE_FAMILY = "1,2";
|
||||
VALIDATE_PRODUCT = YES;
|
||||
VERSIONING_SYSTEM = "apple-generic";
|
||||
@@ -322,57 +346,76 @@
|
||||
F4CE98961C8A921300D735C1 /* Debug */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
BITCODE_GENERATION_MODE = bitcode;
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CODE_SIGN_IDENTITY = "iPhone Developer";
|
||||
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "";
|
||||
DEFINES_MODULE = YES;
|
||||
DYLIB_COMPATIBILITY_VERSION = 1;
|
||||
DYLIB_CURRENT_VERSION = 12;
|
||||
DYLIB_CURRENT_VERSION = 19;
|
||||
DYLIB_INSTALL_NAME_BASE = "@rpath";
|
||||
INFOPLIST_FILE = SwiftyMarkdown/Info.plist;
|
||||
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 8.0;
|
||||
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
|
||||
OTHER_CFLAGS = "-fembed-bitcode";
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.voyagetravelapps.SwiftyMarkdown;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SKIP_INSTALL = YES;
|
||||
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
|
||||
SWIFT_SWIFT3_OBJC_INFERENCE = Default;
|
||||
SWIFT_VERSION = 4.2;
|
||||
};
|
||||
name = Debug;
|
||||
};
|
||||
F4CE98971C8A921300D735C1 /* Release */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
BITCODE_GENERATION_MODE = bitcode;
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CODE_SIGN_IDENTITY = "iPhone Developer";
|
||||
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "";
|
||||
DEFINES_MODULE = YES;
|
||||
DYLIB_COMPATIBILITY_VERSION = 1;
|
||||
DYLIB_CURRENT_VERSION = 12;
|
||||
DYLIB_CURRENT_VERSION = 19;
|
||||
DYLIB_INSTALL_NAME_BASE = "@rpath";
|
||||
INFOPLIST_FILE = SwiftyMarkdown/Info.plist;
|
||||
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 8.0;
|
||||
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
|
||||
OTHER_CFLAGS = "-fembed-bitcode";
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.voyagetravelapps.SwiftyMarkdown;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SKIP_INSTALL = YES;
|
||||
SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule";
|
||||
SWIFT_SWIFT3_OBJC_INFERENCE = Default;
|
||||
SWIFT_VERSION = 4.2;
|
||||
};
|
||||
name = Release;
|
||||
};
|
||||
F4CE98991C8A921300D735C1 /* Debug */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
DEVELOPMENT_TEAM = 52T262DA8V;
|
||||
INFOPLIST_FILE = SwiftyMarkdownTests/Info.plist;
|
||||
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.voyagetravelapps.SwiftyMarkdownTests;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SWIFT_SWIFT3_OBJC_INFERENCE = Default;
|
||||
SWIFT_VERSION = 4.2;
|
||||
};
|
||||
name = Debug;
|
||||
};
|
||||
F4CE989A1C8A921300D735C1 /* Release */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
DEVELOPMENT_TEAM = 52T262DA8V;
|
||||
INFOPLIST_FILE = SwiftyMarkdownTests/Info.plist;
|
||||
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.voyagetravelapps.SwiftyMarkdownTests;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SWIFT_SWIFT3_OBJC_INFERENCE = Default;
|
||||
SWIFT_VERSION = 4.2;
|
||||
};
|
||||
name = Release;
|
||||
};
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Workspace
|
||||
version = "1.0">
|
||||
<FileRef
|
||||
location = "self:">
|
||||
</FileRef>
|
||||
</Workspace>
|
||||
@@ -0,0 +1,99 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Scheme
|
||||
LastUpgradeVersion = "1000"
|
||||
version = "1.3">
|
||||
<BuildAction
|
||||
parallelizeBuildables = "YES"
|
||||
buildImplicitDependencies = "YES">
|
||||
<BuildActionEntries>
|
||||
<BuildActionEntry
|
||||
buildForTesting = "YES"
|
||||
buildForRunning = "YES"
|
||||
buildForProfiling = "YES"
|
||||
buildForArchiving = "YES"
|
||||
buildForAnalyzing = "YES">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "F4CE98801C8A921300D735C1"
|
||||
BuildableName = "SwiftyMarkdown.framework"
|
||||
BlueprintName = "SwiftyMarkdown"
|
||||
ReferencedContainer = "container:SwiftyMarkdown.xcodeproj">
|
||||
</BuildableReference>
|
||||
</BuildActionEntry>
|
||||
</BuildActionEntries>
|
||||
</BuildAction>
|
||||
<TestAction
|
||||
buildConfiguration = "Debug"
|
||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||
shouldUseLaunchSchemeArgsEnv = "YES">
|
||||
<Testables>
|
||||
<TestableReference
|
||||
skipped = "NO">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "F4CE988A1C8A921300D735C1"
|
||||
BuildableName = "SwiftyMarkdownTests.xctest"
|
||||
BlueprintName = "SwiftyMarkdownTests"
|
||||
ReferencedContainer = "container:SwiftyMarkdown.xcodeproj">
|
||||
</BuildableReference>
|
||||
</TestableReference>
|
||||
</Testables>
|
||||
<MacroExpansion>
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "F4CE98801C8A921300D735C1"
|
||||
BuildableName = "SwiftyMarkdown.framework"
|
||||
BlueprintName = "SwiftyMarkdown"
|
||||
ReferencedContainer = "container:SwiftyMarkdown.xcodeproj">
|
||||
</BuildableReference>
|
||||
</MacroExpansion>
|
||||
<AdditionalOptions>
|
||||
</AdditionalOptions>
|
||||
</TestAction>
|
||||
<LaunchAction
|
||||
buildConfiguration = "Debug"
|
||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||
launchStyle = "0"
|
||||
useCustomWorkingDirectory = "NO"
|
||||
ignoresPersistentStateOnLaunch = "NO"
|
||||
debugDocumentVersioning = "YES"
|
||||
debugServiceExtension = "internal"
|
||||
allowLocationSimulation = "YES">
|
||||
<MacroExpansion>
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "F4CE98801C8A921300D735C1"
|
||||
BuildableName = "SwiftyMarkdown.framework"
|
||||
BlueprintName = "SwiftyMarkdown"
|
||||
ReferencedContainer = "container:SwiftyMarkdown.xcodeproj">
|
||||
</BuildableReference>
|
||||
</MacroExpansion>
|
||||
<AdditionalOptions>
|
||||
</AdditionalOptions>
|
||||
</LaunchAction>
|
||||
<ProfileAction
|
||||
buildConfiguration = "Release"
|
||||
shouldUseLaunchSchemeArgsEnv = "YES"
|
||||
savedToolIdentifier = ""
|
||||
useCustomWorkingDirectory = "NO"
|
||||
debugDocumentVersioning = "YES">
|
||||
<MacroExpansion>
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "F4CE98801C8A921300D735C1"
|
||||
BuildableName = "SwiftyMarkdown.framework"
|
||||
BlueprintName = "SwiftyMarkdown"
|
||||
ReferencedContainer = "container:SwiftyMarkdown.xcodeproj">
|
||||
</BuildableReference>
|
||||
</MacroExpansion>
|
||||
</ProfileAction>
|
||||
<AnalyzeAction
|
||||
buildConfiguration = "Debug">
|
||||
</AnalyzeAction>
|
||||
<ArchiveAction
|
||||
buildConfiguration = "Release"
|
||||
revealArchiveInOrganizer = "YES">
|
||||
</ArchiveAction>
|
||||
</Scheme>
|
||||
@@ -0,0 +1,8 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>IDEDidComputeMac32BitWarning</key>
|
||||
<true/>
|
||||
</dict>
|
||||
</plist>
|
||||
@@ -15,11 +15,11 @@
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>FMWK</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>0.2.1</string>
|
||||
<string>0.6.0</string>
|
||||
<key>CFBundleSignature</key>
|
||||
<string>????</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>12</string>
|
||||
<string>19</string>
|
||||
<key>NSPrincipalClass</key>
|
||||
<string></string>
|
||||
</dict>
|
||||
|
||||
+223
-148
@@ -9,9 +9,10 @@
|
||||
import UIKit
|
||||
|
||||
|
||||
public protocol FontProperties {
|
||||
@objc public protocol FontProperties {
|
||||
var fontName : String? { get set }
|
||||
var color : UIColor { get set }
|
||||
var fontSize : CGFloat { get set }
|
||||
}
|
||||
|
||||
|
||||
@@ -20,79 +21,81 @@ A struct defining the styles that can be applied to the parsed Markdown. The `fo
|
||||
|
||||
If that is not set, then the system default will be used.
|
||||
*/
|
||||
public struct BasicStyles : FontProperties {
|
||||
public var fontName : String? = UIFont.preferredFontForTextStyle(UIFontTextStyleBody).fontName
|
||||
public var color = UIColor.blackColor()
|
||||
@objc open class BasicStyles : NSObject, FontProperties {
|
||||
public var fontName : String? = UIFont.preferredFont(forTextStyle: UIFont.TextStyle.body).fontName
|
||||
public var color = UIColor.black
|
||||
public var fontSize : CGFloat = 0.0
|
||||
}
|
||||
|
||||
enum LineType : Int {
|
||||
case H1, H2, H3, H4, H5, H6, Body
|
||||
case h1, h2, h3, h4, h5, h6, body
|
||||
}
|
||||
|
||||
|
||||
enum LineStyle : Int {
|
||||
case None
|
||||
case Italic
|
||||
case Bold
|
||||
case Code
|
||||
case Link
|
||||
case none
|
||||
case italic
|
||||
case bold
|
||||
case code
|
||||
case link
|
||||
|
||||
static func styleFromString(string : String ) -> LineStyle {
|
||||
static func styleFromString(_ string : String ) -> LineStyle {
|
||||
if string == "**" || string == "__" {
|
||||
return .Bold
|
||||
return .bold
|
||||
} else if string == "*" || string == "_" {
|
||||
return .Italic
|
||||
return .italic
|
||||
} else if string == "`" {
|
||||
return .Code
|
||||
return .code
|
||||
} else if string == "[" {
|
||||
return .Link
|
||||
return .link
|
||||
} else {
|
||||
return .None
|
||||
return .none
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// 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.
|
||||
public class SwiftyMarkdown {
|
||||
@objc open class SwiftyMarkdown: NSObject {
|
||||
|
||||
/// The styles to apply to any H1 headers found in the Markdown
|
||||
public var h1 = BasicStyles()
|
||||
|
||||
open var h1 = BasicStyles()
|
||||
|
||||
/// The styles to apply to any H2 headers found in the Markdown
|
||||
public var h2 = BasicStyles()
|
||||
open var h2 = BasicStyles()
|
||||
|
||||
/// The styles to apply to any H3 headers found in the Markdown
|
||||
public var h3 = BasicStyles()
|
||||
open var h3 = BasicStyles()
|
||||
|
||||
/// The styles to apply to any H4 headers found in the Markdown
|
||||
public var h4 = BasicStyles()
|
||||
open var h4 = BasicStyles()
|
||||
|
||||
/// The styles to apply to any H5 headers found in the Markdown
|
||||
public var h5 = BasicStyles()
|
||||
open var h5 = BasicStyles()
|
||||
|
||||
/// The styles to apply to any H6 headers found in the Markdown
|
||||
public var h6 = BasicStyles()
|
||||
open var h6 = BasicStyles()
|
||||
|
||||
/// The default body styles. These are the base styles and will be used for e.g. headers if no other styles override them.
|
||||
public var body = BasicStyles()
|
||||
open var body = BasicStyles()
|
||||
|
||||
/// The styles to apply to any links found in the Markdown
|
||||
public var link = BasicStyles()
|
||||
|
||||
open var link = BasicStyles()
|
||||
|
||||
/// The styles to apply to any bold text found in the Markdown
|
||||
public var bold = BasicStyles()
|
||||
open var bold = BasicStyles()
|
||||
|
||||
/// The styles to apply to any italic text found in the Markdown
|
||||
public var italic = BasicStyles()
|
||||
open var italic = BasicStyles()
|
||||
|
||||
/// The styles to apply to any code blocks or inline code text found in the Markdown
|
||||
public var code = BasicStyles()
|
||||
|
||||
open var code = BasicStyles()
|
||||
|
||||
|
||||
var currentType : LineType = .body
|
||||
|
||||
var currentType : LineType = .Body
|
||||
|
||||
|
||||
let string : String
|
||||
let instructionSet = NSCharacterSet(charactersInString: "[\\*_`")
|
||||
let instructionSet = CharacterSet(charactersIn: "[\\*_`")
|
||||
|
||||
/**
|
||||
|
||||
@@ -111,27 +114,70 @@ public class SwiftyMarkdown {
|
||||
|
||||
- returns: An initialized SwiftyMarkdown object, or nil if the string couldn't be read
|
||||
*/
|
||||
public init?(url : NSURL ) {
|
||||
public init?(url : URL ) {
|
||||
|
||||
do {
|
||||
self.string = try NSString(contentsOfURL: url, encoding: NSUTF8StringEncoding) as String
|
||||
self.string = try NSString(contentsOf: url, encoding: String.Encoding.utf8.rawValue) as String
|
||||
|
||||
} catch {
|
||||
self.string = ""
|
||||
fatalError("Couldn't read string")
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
Set font size for all styles
|
||||
|
||||
- parameter size: size of font
|
||||
*/
|
||||
open func setFontSizeForAllStyles(with size: CGFloat) {
|
||||
h1.fontSize = size
|
||||
h2.fontSize = size
|
||||
h3.fontSize = size
|
||||
h4.fontSize = size
|
||||
h5.fontSize = size
|
||||
h6.fontSize = size
|
||||
body.fontSize = size
|
||||
italic.fontSize = size
|
||||
code.fontSize = size
|
||||
link.fontSize = size
|
||||
}
|
||||
|
||||
open func setFontColorForAllStyles(with color: UIColor) {
|
||||
h1.color = color
|
||||
h2.color = color
|
||||
h3.color = color
|
||||
h4.color = color
|
||||
h5.color = color
|
||||
h6.color = color
|
||||
body.color = color
|
||||
italic.color = color
|
||||
code.color = color
|
||||
link.color = color
|
||||
}
|
||||
|
||||
open func setFontNameForAllStyles(with name: String) {
|
||||
h1.fontName = name
|
||||
h2.fontName = name
|
||||
h3.fontName = name
|
||||
h4.fontName = name
|
||||
h5.fontName = name
|
||||
h6.fontName = name
|
||||
body.fontName = name
|
||||
italic.fontName = name
|
||||
code.fontName = name
|
||||
link.fontName = name
|
||||
}
|
||||
|
||||
/**
|
||||
Generates an NSAttributedString from the string or URL passed at initialisation. Custom fonts or styles are applied to the appropriate elements when this method is called.
|
||||
|
||||
- returns: An NSAttributedString with the styles applied
|
||||
*/
|
||||
public func attributedString() -> NSAttributedString {
|
||||
open func attributedString() -> NSAttributedString {
|
||||
let attributedString = NSMutableAttributedString(string: "")
|
||||
|
||||
let lines = self.string.componentsSeparatedByCharactersInSet(NSCharacterSet.newlineCharacterSet())
|
||||
let lines = self.string.components(separatedBy: CharacterSet.newlines)
|
||||
|
||||
var lineCount = 0
|
||||
|
||||
@@ -139,24 +185,24 @@ public class SwiftyMarkdown {
|
||||
|
||||
var skipLine = false
|
||||
for theLine in lines {
|
||||
lineCount++
|
||||
lineCount += 1
|
||||
if skipLine {
|
||||
skipLine = false
|
||||
continue
|
||||
}
|
||||
var line = theLine
|
||||
var line = theLine == "" ? " " : theLine
|
||||
for heading in headings {
|
||||
|
||||
if let range = line.rangeOfString(heading) where range.startIndex == line.startIndex {
|
||||
if let range = line.range(of: heading) , range.lowerBound == line.startIndex {
|
||||
|
||||
let startHeadingString = line.replacingCharacters(in: range, with: "")
|
||||
|
||||
let startHeadingString = line.stringByReplacingCharactersInRange(range, withString: "")
|
||||
|
||||
// Remove ending
|
||||
let endHeadingString = heading.stringByTrimmingCharactersInSet(NSCharacterSet.whitespaceAndNewlineCharacterSet())
|
||||
line = startHeadingString.stringByReplacingOccurrencesOfString(endHeadingString, withString: "").stringByTrimmingCharactersInSet(NSCharacterSet.whitespaceAndNewlineCharacterSet())
|
||||
let endHeadingString = heading.trimmingCharacters(in: CharacterSet.whitespacesAndNewlines)
|
||||
line = startHeadingString.replacingOccurrences(of: endHeadingString, with: "").trimmingCharacters(in: CharacterSet.whitespacesAndNewlines)
|
||||
|
||||
currentType = LineType(rawValue: headings.index(of: heading)!)!
|
||||
|
||||
currentType = LineType(rawValue: headings.indexOf(heading)!)!
|
||||
|
||||
// We found a heading so break out of the inner loop
|
||||
break
|
||||
}
|
||||
@@ -166,209 +212,233 @@ public class SwiftyMarkdown {
|
||||
if lineCount < lines.count {
|
||||
let nextLine = lines[lineCount]
|
||||
|
||||
if let range = nextLine.rangeOfString("=") where range.startIndex == nextLine.startIndex {
|
||||
let hasNonWhiteSpaceCharacters = (line.rangeOfCharacter(from: CharacterSet.whitespacesAndNewlines.inverted) != nil)
|
||||
|
||||
if hasNonWhiteSpaceCharacters, let range = nextLine.range(of: "=") , range.lowerBound == nextLine.startIndex {
|
||||
// Make H1
|
||||
currentType = .H1
|
||||
currentType = .h1
|
||||
// We need to skip the next line
|
||||
skipLine = true
|
||||
}
|
||||
|
||||
if let range = nextLine.rangeOfString("-") where range.startIndex == nextLine.startIndex {
|
||||
// Make H2
|
||||
currentType = .H2
|
||||
// We need to skip the next line
|
||||
skipLine = true
|
||||
if hasNonWhiteSpaceCharacters, let nextRange = nextLine.range(of: "-") , nextRange.lowerBound == nextLine.startIndex {
|
||||
if let range = line.range(of: "-"), range.lowerBound == line.startIndex {
|
||||
// This is a bullet list, not an `Alt-H2`, don't skip
|
||||
} else {
|
||||
// Make H2
|
||||
currentType = .h2
|
||||
// We need to skip the next line
|
||||
skipLine = true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// If this is not an empty line...
|
||||
if line.characters.count > 0 {
|
||||
if line.count > 0 {
|
||||
|
||||
// ...start scanning
|
||||
let scanner = NSScanner(string: line)
|
||||
let scanner = Scanner(string: line)
|
||||
|
||||
// We want to be aware of spaces
|
||||
scanner.charactersToBeSkipped = nil
|
||||
|
||||
while !scanner.atEnd {
|
||||
while !scanner.isAtEnd {
|
||||
var string : NSString?
|
||||
|
||||
|
||||
// Get all the characters up to the ones we are interested in
|
||||
if scanner.scanUpToCharactersFromSet(instructionSet, intoString: &string) {
|
||||
if scanner.scanUpToCharacters(from: instructionSet, into: &string) {
|
||||
|
||||
if let hasString = string as? String {
|
||||
let bodyString = attributedStringFromString(hasString, withStyle: .None)
|
||||
attributedString.appendAttributedString(bodyString)
|
||||
if let hasString = string as String? {
|
||||
let bodyString = attributedStringFromString(hasString, withStyle: .none)
|
||||
attributedString.append(bodyString)
|
||||
|
||||
let location = scanner.scanLocation
|
||||
|
||||
let matchedCharacters = tagFromScanner(scanner).foundCharacters
|
||||
// If the next string after the characters is a space, then add it to the final string and continue
|
||||
|
||||
let set = NSMutableCharacterSet.whitespaceCharacterSet()
|
||||
set.formUnionWithCharacterSet(NSCharacterSet.punctuationCharacterSet())
|
||||
if scanner.scanUpToCharactersFromSet(set, intoString: nil) {
|
||||
let set = NSMutableCharacterSet.whitespace()
|
||||
set.formUnion(with: CharacterSet.punctuationCharacters)
|
||||
if scanner.scanUpToCharacters(from: set as CharacterSet, into: nil) {
|
||||
scanner.scanLocation = location
|
||||
attributedString.appendAttributedString(self.attributedStringFromScanner(scanner))
|
||||
|
||||
attributedString.append(self.attributedStringFromScanner(scanner))
|
||||
|
||||
} else if matchedCharacters == "[" {
|
||||
scanner.scanLocation = location
|
||||
attributedString.appendAttributedString(self.attributedStringFromScanner(scanner))
|
||||
attributedString.append(self.attributedStringFromScanner(scanner))
|
||||
} else {
|
||||
let charAtts = attributedStringFromString(matchedCharacters, withStyle: .None)
|
||||
attributedString.appendAttributedString(charAtts)
|
||||
|
||||
let charAtts = attributedStringFromString(matchedCharacters, withStyle: .none)
|
||||
attributedString.append(charAtts)
|
||||
|
||||
}
|
||||
}
|
||||
} else {
|
||||
attributedString.appendAttributedString(self.attributedStringFromScanner(scanner, atStartOfLine: true))
|
||||
attributedString.append(self.attributedStringFromScanner(scanner, atStartOfLine: true))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Append a new line character to the end of the processed line
|
||||
attributedString.appendAttributedString(NSAttributedString(string: "\n"))
|
||||
currentType = .Body
|
||||
if lineCount < lines.count {
|
||||
attributedString.append(NSAttributedString(string: "\n"))
|
||||
}
|
||||
currentType = .body
|
||||
}
|
||||
|
||||
return attributedString
|
||||
}
|
||||
|
||||
func attributedStringFromScanner( scanner : NSScanner, atStartOfLine start : Bool = false) -> NSAttributedString {
|
||||
func attributedStringFromScanner( _ scanner : Scanner, atStartOfLine start : Bool = false) -> NSAttributedString {
|
||||
var followingString : NSString?
|
||||
|
||||
|
||||
let results = self.tagFromScanner(scanner)
|
||||
|
||||
|
||||
var style = LineStyle.styleFromString(results.foundCharacters)
|
||||
|
||||
var attributes = [String : AnyObject]()
|
||||
if style == .Link {
|
||||
var attributes = [NSAttributedString.Key : AnyObject]()
|
||||
if style == .link {
|
||||
|
||||
var linkText : NSString?
|
||||
var linkURL : NSString?
|
||||
let linkCharacters = NSCharacterSet(charactersInString: "]()")
|
||||
let linkCharacters = CharacterSet(charactersIn: "]()")
|
||||
|
||||
scanner.scanUpToCharactersFromSet(linkCharacters, intoString: &linkText)
|
||||
scanner.scanCharactersFromSet(linkCharacters, intoString: nil)
|
||||
scanner.scanUpToCharactersFromSet(linkCharacters, intoString: &linkURL)
|
||||
scanner.scanCharactersFromSet(linkCharacters, intoString: nil)
|
||||
scanner.scanUpToCharacters(from: linkCharacters, into: &linkText)
|
||||
scanner.scanCharacters(from: linkCharacters, into: nil)
|
||||
scanner.scanUpToCharacters(from: linkCharacters, into: &linkURL)
|
||||
scanner.scanCharacters(from: linkCharacters, into: nil)
|
||||
|
||||
|
||||
if let hasLink = linkText, hasURL = linkURL {
|
||||
followingString = hasLink as String
|
||||
attributes[NSLinkAttributeName] = hasURL as String
|
||||
if let hasLink = linkText, let hasURL = linkURL {
|
||||
followingString = hasLink
|
||||
attributes[NSAttributedString.Key.link] = hasURL
|
||||
} else {
|
||||
style = .None
|
||||
style = .none
|
||||
}
|
||||
} else {
|
||||
scanner.scanUpToCharactersFromSet(instructionSet, intoString: &followingString)
|
||||
scanner.scanUpToCharacters(from: instructionSet, into: &followingString)
|
||||
}
|
||||
|
||||
let attributedString = attributedStringFromString(results.escapedCharacters, withStyle: style).mutableCopy() as! NSMutableAttributedString
|
||||
if let hasString = followingString as? String {
|
||||
|
||||
|
||||
if let hasString = followingString as String? {
|
||||
|
||||
let prefix = ( style == .Code && start ) ? "\t" : ""
|
||||
let prefix = ( style == .code && start ) ? "\t" : ""
|
||||
let attString = attributedStringFromString(prefix + hasString, withStyle: style, attributes: attributes)
|
||||
attributedString.appendAttributedString(attString)
|
||||
attributedString.append(attString)
|
||||
}
|
||||
let suffix = self.tagFromScanner(scanner)
|
||||
attributedString.appendAttributedString(attributedStringFromString(suffix.escapedCharacters, withStyle: style))
|
||||
attributedString.append(attributedStringFromString(suffix.escapedCharacters, withStyle: style))
|
||||
|
||||
return attributedString
|
||||
}
|
||||
|
||||
func tagFromScanner( scanner : NSScanner ) -> (foundCharacters : String, escapedCharacters : String) {
|
||||
func tagFromScanner( _ scanner : Scanner ) -> (foundCharacters : String, escapedCharacters : String) {
|
||||
var matchedCharacters : String = ""
|
||||
var tempCharacters : NSString?
|
||||
|
||||
// Scan the ones we are interested in
|
||||
while scanner.scanCharactersFromSet(instructionSet, intoString: &tempCharacters) {
|
||||
if let chars = tempCharacters as? String {
|
||||
while scanner.scanCharacters(from: instructionSet, into: &tempCharacters) {
|
||||
if let chars = tempCharacters as String? {
|
||||
matchedCharacters = matchedCharacters + chars
|
||||
}
|
||||
}
|
||||
var foundCharacters : String = ""
|
||||
|
||||
while matchedCharacters.containsString("\\") {
|
||||
if let hasRange = matchedCharacters.rangeOfString("\\") {
|
||||
while matchedCharacters.contains("\\") {
|
||||
if let hasRange = matchedCharacters.range(of: "\\") {
|
||||
|
||||
let newRange = Range(start: hasRange.startIndex, end: hasRange.endIndex.advancedBy(1))
|
||||
foundCharacters = foundCharacters + matchedCharacters.substringWithRange(newRange)
|
||||
|
||||
matchedCharacters.removeRange(newRange)
|
||||
if matchedCharacters.count > 1 {
|
||||
let newRange = hasRange.lowerBound..<matchedCharacters.index(hasRange.upperBound, offsetBy: 1)
|
||||
foundCharacters = foundCharacters + matchedCharacters[newRange].replacingOccurrences(of: "\\", with: "")
|
||||
|
||||
matchedCharacters.removeSubrange(newRange)
|
||||
} else {
|
||||
foundCharacters = matchedCharacters
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
return (matchedCharacters, foundCharacters.stringByReplacingOccurrencesOfString("\\", withString: ""))
|
||||
return (matchedCharacters, foundCharacters)
|
||||
}
|
||||
|
||||
|
||||
// Make H1
|
||||
|
||||
func attributedStringFromString(string : String, withStyle style : LineStyle, var attributes : [String : AnyObject] = [:] ) -> NSAttributedString {
|
||||
let textStyle : String
|
||||
func attributedStringFromString(_ string : String, withStyle style : LineStyle, attributes : [NSAttributedString.Key : AnyObject] = [:] ) -> NSAttributedString {
|
||||
let textStyle : UIFont.TextStyle
|
||||
var fontName : String?
|
||||
|
||||
var attributes = attributes
|
||||
var fontSize : CGFloat?
|
||||
|
||||
// What type are we and is there a font name set?
|
||||
|
||||
|
||||
switch currentType {
|
||||
case .H1:
|
||||
case .h1:
|
||||
fontName = h1.fontName
|
||||
fontSize = h1.fontSize
|
||||
if #available(iOS 9, *) {
|
||||
textStyle = UIFontTextStyleTitle1
|
||||
textStyle = UIFont.TextStyle.title1
|
||||
} else {
|
||||
textStyle = UIFontTextStyleHeadline
|
||||
textStyle = UIFont.TextStyle.headline
|
||||
}
|
||||
attributes[NSForegroundColorAttributeName] = h1.color
|
||||
case .H2:
|
||||
attributes[NSAttributedString.Key.foregroundColor] = h1.color
|
||||
case .h2:
|
||||
fontName = h2.fontName
|
||||
fontSize = h2.fontSize
|
||||
if #available(iOS 9, *) {
|
||||
textStyle = UIFontTextStyleTitle2
|
||||
textStyle = UIFont.TextStyle.title2
|
||||
} else {
|
||||
textStyle = UIFontTextStyleHeadline
|
||||
textStyle = UIFont.TextStyle.headline
|
||||
}
|
||||
attributes[NSForegroundColorAttributeName] = h2.color
|
||||
case .H3:
|
||||
attributes[NSAttributedString.Key.foregroundColor] = h2.color
|
||||
case .h3:
|
||||
fontName = h3.fontName
|
||||
fontSize = h3.fontSize
|
||||
if #available(iOS 9, *) {
|
||||
textStyle = UIFontTextStyleTitle2
|
||||
textStyle = UIFont.TextStyle.title2
|
||||
} else {
|
||||
textStyle = UIFontTextStyleSubheadline
|
||||
textStyle = UIFont.TextStyle.subheadline
|
||||
}
|
||||
attributes[NSForegroundColorAttributeName] = h3.color
|
||||
case .H4:
|
||||
attributes[NSAttributedString.Key.foregroundColor] = h3.color
|
||||
case .h4:
|
||||
fontName = h4.fontName
|
||||
textStyle = UIFontTextStyleHeadline
|
||||
attributes[NSForegroundColorAttributeName] = h4.color
|
||||
case .H5:
|
||||
fontSize = h4.fontSize
|
||||
textStyle = UIFont.TextStyle.headline
|
||||
attributes[NSAttributedString.Key.foregroundColor] = h4.color
|
||||
case .h5:
|
||||
fontName = h5.fontName
|
||||
textStyle = UIFontTextStyleSubheadline
|
||||
attributes[NSForegroundColorAttributeName] = h5.color
|
||||
case .H6:
|
||||
fontSize = h5.fontSize
|
||||
textStyle = UIFont.TextStyle.subheadline
|
||||
attributes[NSAttributedString.Key.foregroundColor] = h5.color
|
||||
case .h6:
|
||||
fontName = h6.fontName
|
||||
textStyle = UIFontTextStyleFootnote
|
||||
attributes[NSForegroundColorAttributeName] = h6.color
|
||||
fontSize = h6.fontSize
|
||||
textStyle = UIFont.TextStyle.footnote
|
||||
attributes[NSAttributedString.Key.foregroundColor] = h6.color
|
||||
default:
|
||||
fontName = body.fontName
|
||||
textStyle = UIFontTextStyleBody
|
||||
attributes[NSForegroundColorAttributeName] = body.color
|
||||
fontSize = body.fontSize
|
||||
textStyle = UIFont.TextStyle.body
|
||||
attributes[NSAttributedString.Key.foregroundColor] = body.color
|
||||
break
|
||||
}
|
||||
|
||||
// Check for code
|
||||
|
||||
if style == .Code {
|
||||
if style == .code {
|
||||
fontName = code.fontName
|
||||
attributes[NSForegroundColorAttributeName] = code.color
|
||||
fontSize = code.fontSize
|
||||
attributes[NSAttributedString.Key.foregroundColor] = code.color
|
||||
}
|
||||
|
||||
if style == .Link {
|
||||
if style == .link {
|
||||
fontName = link.fontName
|
||||
attributes[NSForegroundColorAttributeName] = link.color
|
||||
fontSize = link.fontSize
|
||||
attributes[NSAttributedString.Key.foregroundColor] = link.color
|
||||
}
|
||||
|
||||
// Fallback to body
|
||||
@@ -378,29 +448,34 @@ public class SwiftyMarkdown {
|
||||
fontName = body.fontName
|
||||
}
|
||||
|
||||
let font = UIFont.preferredFontForTextStyle(textStyle)
|
||||
let styleDescriptor = font.fontDescriptor()
|
||||
let styleSize = styleDescriptor.fontAttributes()[UIFontDescriptorSizeAttribute] as? CGFloat ?? CGFloat(14)
|
||||
fontSize = fontSize == 0.0 ? nil : fontSize
|
||||
let font = UIFont.preferredFont(forTextStyle: textStyle)
|
||||
let styleDescriptor = font.fontDescriptor
|
||||
let styleSize = fontSize ?? styleDescriptor.fontAttributes[UIFontDescriptor.AttributeName.size] as? CGFloat ?? CGFloat(14)
|
||||
|
||||
var finalFont : UIFont
|
||||
if let finalFontName = fontName, font = UIFont(name: finalFontName, size: styleSize) {
|
||||
if let finalFontName = fontName, let font = UIFont(name: finalFontName, size: styleSize) {
|
||||
finalFont = font
|
||||
} else {
|
||||
finalFont = UIFont.preferredFontForTextStyle(textStyle)
|
||||
finalFont = UIFont.preferredFont(forTextStyle: textStyle)
|
||||
}
|
||||
|
||||
let finalFontDescriptor = finalFont.fontDescriptor()
|
||||
if style == .Italic {
|
||||
let italicDescriptor = finalFontDescriptor.fontDescriptorWithSymbolicTraits(.TraitItalic)
|
||||
finalFont = UIFont(descriptor: italicDescriptor, size: styleSize)
|
||||
let finalFontDescriptor = finalFont.fontDescriptor
|
||||
if style == .italic {
|
||||
if let italicDescriptor = finalFontDescriptor.withSymbolicTraits(.traitItalic) {
|
||||
finalFont = UIFont(descriptor: italicDescriptor, size: styleSize)
|
||||
}
|
||||
|
||||
}
|
||||
if style == .Bold {
|
||||
let boldDescriptor = finalFontDescriptor.fontDescriptorWithSymbolicTraits(.TraitBold)
|
||||
finalFont = UIFont(descriptor: boldDescriptor, size: styleSize)
|
||||
if style == .bold {
|
||||
if let boldDescriptor = finalFontDescriptor.withSymbolicTraits(.traitBold) {
|
||||
finalFont = UIFont(descriptor: boldDescriptor, size: styleSize)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
attributes[NSFontAttributeName] = finalFont
|
||||
attributes[NSAttributedString.Key.font] = finalFont
|
||||
|
||||
return NSAttributedString(string: string, attributes: attributes)
|
||||
}
|
||||
|
||||
@@ -233,18 +233,21 @@
|
||||
isa = PBXProject;
|
||||
attributes = {
|
||||
LastSwiftUpdateCheck = 0720;
|
||||
LastUpgradeCheck = 0720;
|
||||
LastUpgradeCheck = 1000;
|
||||
ORGANIZATIONNAME = "Voyage Travel Apps";
|
||||
TargetAttributes = {
|
||||
F4CE98A71C8AEF7D00D735C1 = {
|
||||
CreatedOnToolsVersion = 7.2.1;
|
||||
LastSwiftMigration = 0900;
|
||||
};
|
||||
F4CE98BB1C8AEF7D00D735C1 = {
|
||||
CreatedOnToolsVersion = 7.2.1;
|
||||
LastSwiftMigration = 0900;
|
||||
TestTargetID = F4CE98A71C8AEF7D00D735C1;
|
||||
};
|
||||
F4CE98C61C8AEF7D00D735C1 = {
|
||||
CreatedOnToolsVersion = 7.2.1;
|
||||
LastSwiftMigration = 0900;
|
||||
TestTargetID = F4CE98A71C8AEF7D00D735C1;
|
||||
};
|
||||
};
|
||||
@@ -389,13 +392,23 @@
|
||||
CLANG_CXX_LIBRARY = "libc++";
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CLANG_ENABLE_OBJC_ARC = YES;
|
||||
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
|
||||
CLANG_WARN_BOOL_CONVERSION = YES;
|
||||
CLANG_WARN_COMMA = YES;
|
||||
CLANG_WARN_CONSTANT_CONVERSION = YES;
|
||||
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
|
||||
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
|
||||
CLANG_WARN_EMPTY_BODY = YES;
|
||||
CLANG_WARN_ENUM_CONVERSION = YES;
|
||||
CLANG_WARN_INFINITE_RECURSION = YES;
|
||||
CLANG_WARN_INT_CONVERSION = YES;
|
||||
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
|
||||
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
|
||||
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
|
||||
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
|
||||
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
|
||||
CLANG_WARN_STRICT_PROTOTYPES = YES;
|
||||
CLANG_WARN_SUSPICIOUS_MOVE = YES;
|
||||
CLANG_WARN_UNREACHABLE_CODE = YES;
|
||||
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
|
||||
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
|
||||
@@ -434,13 +447,23 @@
|
||||
CLANG_CXX_LIBRARY = "libc++";
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CLANG_ENABLE_OBJC_ARC = YES;
|
||||
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
|
||||
CLANG_WARN_BOOL_CONVERSION = YES;
|
||||
CLANG_WARN_COMMA = YES;
|
||||
CLANG_WARN_CONSTANT_CONVERSION = YES;
|
||||
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
|
||||
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
|
||||
CLANG_WARN_EMPTY_BODY = YES;
|
||||
CLANG_WARN_ENUM_CONVERSION = YES;
|
||||
CLANG_WARN_INFINITE_RECURSION = YES;
|
||||
CLANG_WARN_INT_CONVERSION = YES;
|
||||
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
|
||||
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
|
||||
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
|
||||
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
|
||||
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
|
||||
CLANG_WARN_STRICT_PROTOTYPES = YES;
|
||||
CLANG_WARN_SUSPICIOUS_MOVE = YES;
|
||||
CLANG_WARN_UNREACHABLE_CODE = YES;
|
||||
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
|
||||
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
|
||||
@@ -459,6 +482,7 @@
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 9.2;
|
||||
MTL_ENABLE_DEBUG_INFO = NO;
|
||||
SDKROOT = iphoneos;
|
||||
SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule";
|
||||
TARGETED_DEVICE_FAMILY = "1,2";
|
||||
VALIDATE_PRODUCT = YES;
|
||||
};
|
||||
@@ -472,6 +496,8 @@
|
||||
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.voyagetravelapps.SwiftyMarkdownExample;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SWIFT_SWIFT3_OBJC_INFERENCE = On;
|
||||
SWIFT_VERSION = 4.0;
|
||||
};
|
||||
name = Debug;
|
||||
};
|
||||
@@ -483,6 +509,8 @@
|
||||
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.voyagetravelapps.SwiftyMarkdownExample;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SWIFT_SWIFT3_OBJC_INFERENCE = On;
|
||||
SWIFT_VERSION = 4.0;
|
||||
};
|
||||
name = Release;
|
||||
};
|
||||
@@ -494,6 +522,8 @@
|
||||
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.voyagetravelapps.SwiftyMarkdownExampleTests;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SWIFT_SWIFT3_OBJC_INFERENCE = On;
|
||||
SWIFT_VERSION = 4.0;
|
||||
TEST_HOST = "$(BUILT_PRODUCTS_DIR)/SwiftyMarkdownExample.app/SwiftyMarkdownExample";
|
||||
};
|
||||
name = Debug;
|
||||
@@ -506,6 +536,8 @@
|
||||
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.voyagetravelapps.SwiftyMarkdownExampleTests;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SWIFT_SWIFT3_OBJC_INFERENCE = On;
|
||||
SWIFT_VERSION = 4.0;
|
||||
TEST_HOST = "$(BUILT_PRODUCTS_DIR)/SwiftyMarkdownExample.app/SwiftyMarkdownExample";
|
||||
};
|
||||
name = Release;
|
||||
@@ -517,6 +549,8 @@
|
||||
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.voyagetravelapps.SwiftyMarkdownExampleUITests;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SWIFT_SWIFT3_OBJC_INFERENCE = On;
|
||||
SWIFT_VERSION = 4.0;
|
||||
TEST_TARGET_NAME = SwiftyMarkdownExample;
|
||||
USES_XCTRUNNER = YES;
|
||||
};
|
||||
@@ -529,6 +563,8 @@
|
||||
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.voyagetravelapps.SwiftyMarkdownExampleUITests;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SWIFT_SWIFT3_OBJC_INFERENCE = On;
|
||||
SWIFT_VERSION = 4.0;
|
||||
TEST_TARGET_NAME = SwiftyMarkdownExample;
|
||||
USES_XCTRUNNER = YES;
|
||||
};
|
||||
|
||||
@@ -14,30 +14,30 @@ class AppDelegate: UIResponder, UIApplicationDelegate {
|
||||
var window: UIWindow?
|
||||
|
||||
|
||||
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
|
||||
private func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: Any]?) -> Bool {
|
||||
// Override point for customization after application launch.
|
||||
return true
|
||||
}
|
||||
|
||||
func applicationWillResignActive(application: UIApplication) {
|
||||
func applicationWillResignActive(_ application: UIApplication) {
|
||||
// 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.
|
||||
// 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.
|
||||
}
|
||||
|
||||
func applicationDidEnterBackground(application: UIApplication) {
|
||||
func applicationDidEnterBackground(_ application: UIApplication) {
|
||||
// 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.
|
||||
// If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits.
|
||||
}
|
||||
|
||||
func applicationWillEnterForeground(application: UIApplication) {
|
||||
func applicationWillEnterForeground(_ application: UIApplication) {
|
||||
// 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.
|
||||
}
|
||||
|
||||
func applicationDidBecomeActive(application: UIApplication) {
|
||||
func applicationDidBecomeActive(_ application: UIApplication) {
|
||||
// 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.
|
||||
}
|
||||
|
||||
func applicationWillTerminate(application: UIApplication) {
|
||||
func applicationWillTerminate(_ application: UIApplication) {
|
||||
// Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.
|
||||
}
|
||||
|
||||
|
||||
@@ -1,9 +1,13 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="9532" systemVersion="15D21" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" initialViewController="BYZ-38-t0r">
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="12118" systemVersion="16E195" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" colorMatched="YES" initialViewController="BYZ-38-t0r">
|
||||
<device id="retina4_7" orientation="portrait">
|
||||
<adaptation id="fullscreen"/>
|
||||
</device>
|
||||
<dependencies>
|
||||
<deployment identifier="iOS"/>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="9530"/>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="12086"/>
|
||||
<capability name="Constraints to layout margins" minToolsVersion="6.0"/>
|
||||
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
|
||||
</dependencies>
|
||||
<scenes>
|
||||
<!--View Controller-->
|
||||
@@ -15,22 +19,31 @@
|
||||
<viewControllerLayoutGuide type="bottom" id="wfy-db-euE"/>
|
||||
</layoutGuides>
|
||||
<view key="view" contentMode="scaleToFill" id="8bC-Xf-vdC">
|
||||
<rect key="frame" x="0.0" y="0.0" width="600" height="600"/>
|
||||
<rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<subviews>
|
||||
<textView clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="scaleToFill" editable="NO" usesAttributedText="YES" translatesAutoresizingMaskIntoConstraints="NO" id="qZP-CU-74n">
|
||||
<rect key="frame" x="20" y="20" width="560" height="580"/>
|
||||
<color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
|
||||
<rect key="frame" x="16" y="20" width="343" height="601"/>
|
||||
<color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<attributedString key="attributedText"/>
|
||||
<textInputTraits key="textInputTraits" autocapitalizationType="sentences"/>
|
||||
<dataDetectorType key="dataDetectorTypes" link="YES"/>
|
||||
</textView>
|
||||
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="JK2-Lo-xRa">
|
||||
<rect key="frame" x="164" y="629" width="47" height="30"/>
|
||||
<state key="normal" title="Reload"/>
|
||||
<connections>
|
||||
<action selector="reloadText:" destination="BYZ-38-t0r" eventType="touchUpInside" id="fGe-1g-NTo"/>
|
||||
</connections>
|
||||
</button>
|
||||
</subviews>
|
||||
<color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="calibratedWhite"/>
|
||||
<color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<constraints>
|
||||
<constraint firstItem="qZP-CU-74n" firstAttribute="leading" secondItem="8bC-Xf-vdC" secondAttribute="leadingMargin" id="1yU-8N-26a"/>
|
||||
<constraint firstItem="wfy-db-euE" firstAttribute="top" secondItem="qZP-CU-74n" secondAttribute="bottom" id="7lJ-OQ-4eh"/>
|
||||
<constraint firstItem="JK2-Lo-xRa" firstAttribute="centerX" secondItem="8bC-Xf-vdC" secondAttribute="centerX" id="3Zx-lw-7hH"/>
|
||||
<constraint firstAttribute="trailingMargin" secondItem="qZP-CU-74n" secondAttribute="trailing" id="F5p-iG-zTB"/>
|
||||
<constraint firstItem="JK2-Lo-xRa" firstAttribute="top" secondItem="qZP-CU-74n" secondAttribute="bottom" constant="8" id="Rod-d1-6Yb"/>
|
||||
<constraint firstItem="wfy-db-euE" firstAttribute="top" secondItem="JK2-Lo-xRa" secondAttribute="bottom" constant="8" id="Yc0-Xe-YPV"/>
|
||||
<constraint firstItem="qZP-CU-74n" firstAttribute="top" secondItem="y3c-jy-aDJ" secondAttribute="bottom" id="srf-u0-j0n"/>
|
||||
</constraints>
|
||||
</view>
|
||||
@@ -40,6 +53,7 @@
|
||||
</viewController>
|
||||
<placeholder placeholderIdentifier="IBFirstResponder" id="dkx-z0-nzr" sceneMemberID="firstResponder"/>
|
||||
</objects>
|
||||
<point key="canvasLocation" x="24.800000000000001" y="34.632683658170919"/>
|
||||
</scene>
|
||||
</scenes>
|
||||
</document>
|
||||
|
||||
@@ -15,27 +15,31 @@ class ViewController: UIViewController {
|
||||
|
||||
override func viewDidLoad() {
|
||||
super.viewDidLoad()
|
||||
// Do any additional setup after loading the view, typically from a nib.
|
||||
|
||||
// This is to help debugging.
|
||||
reloadText(nil)
|
||||
}
|
||||
|
||||
@IBAction func reloadText( _ sender : UIButton? ) {
|
||||
|
||||
self.textView.dataDetectorTypes = UIDataDetectorTypes.all
|
||||
|
||||
self.textView.dataDetectorTypes = UIDataDetectorTypes.All
|
||||
if let url = NSBundle.mainBundle().URLForResource("example", withExtension: "md"), md = SwiftyMarkdown(url: url) {
|
||||
if self.textView.text != "" {
|
||||
self.textView.attributedText = SwiftyMarkdown(string: "Yo I'm a *single* line **string**. How do I look?").attributedString()
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
if let url = Bundle.main.url(forResource: "example", withExtension: "md"), let md = SwiftyMarkdown(url: url) {
|
||||
md.h2.fontName = "AvenirNextCondensed-Bold"
|
||||
md.h2.color = UIColor.redColor()
|
||||
md.h2.color = UIColor.red
|
||||
md.code.fontName = "CourierNewPSMT"
|
||||
|
||||
|
||||
self.textView.attributedText = md.attributedString()
|
||||
|
||||
} else {
|
||||
fatalError("Error loading file")
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
override func didReceiveMemoryWarning() {
|
||||
super.didReceiveMemoryWarning()
|
||||
// Dispose of any resources that can be recreated.
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -15,3 +15,8 @@ Customise fonts and colours easily in a Swift-like way:
|
||||
|
||||
It ignores random * and correctly handles escaped \*asterisks\* and \_underlines\_ and has error handling for mismatched tags (\*\*bold\* == **bold*). It also supports inline Markdown [Links](http://voyagetravelapps.com/)
|
||||
|
||||
Supports Alternative Headings
|
||||
===
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -28,7 +28,7 @@ class SwiftyMarkdownExampleTests: XCTestCase {
|
||||
|
||||
func testPerformanceExample() {
|
||||
// This is an example of a performance test case.
|
||||
self.measureBlock {
|
||||
self.measure {
|
||||
// Put the code you want to measure the time of here.
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,10 +15,10 @@
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>BNDL</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>0.2.1</string>
|
||||
<string>0.6.0</string>
|
||||
<key>CFBundleSignature</key>
|
||||
<string>????</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>12</string>
|
||||
<string>19</string>
|
||||
</dict>
|
||||
</plist>
|
||||
|
||||
@@ -28,13 +28,13 @@ class SwiftyMarkdownTests: XCTestCase {
|
||||
let headerStringWithItalic = "## Header 2 _With Italics_"
|
||||
|
||||
var md = SwiftyMarkdown(string: headerString)
|
||||
XCTAssertEqual(md.attributedString().string, "Header 1\nHeader 2\nHeader 3\nHeader 4\nHeader 5\nHeader 6\n")
|
||||
XCTAssertEqual(md.attributedString().string, "Header 1\nHeader 2\nHeader 3\nHeader 4\nHeader 5\nHeader 6")
|
||||
|
||||
md = SwiftyMarkdown(string: headerStringWithBold)
|
||||
XCTAssertEqual(md.attributedString().string, "Bold Header 1\n")
|
||||
XCTAssertEqual(md.attributedString().string, "Bold Header 1")
|
||||
|
||||
md = SwiftyMarkdown(string: headerStringWithItalic)
|
||||
XCTAssertEqual(md.attributedString().string, "Header 2 With Italics\n")
|
||||
XCTAssertEqual(md.attributedString().string, "Header 2 With Italics")
|
||||
|
||||
}
|
||||
|
||||
@@ -47,19 +47,19 @@ class SwiftyMarkdownTests: XCTestCase {
|
||||
let h2StringWithCode = "Header 2 `With Code`\n---\nSome following text"
|
||||
|
||||
var md = SwiftyMarkdown(string: h1String)
|
||||
XCTAssertEqual(md.attributedString().string, "Header 1\nSome following text\n")
|
||||
XCTAssertEqual(md.attributedString().string, "Header 1\nSome following text")
|
||||
|
||||
md = SwiftyMarkdown(string: h2String)
|
||||
XCTAssertEqual(md.attributedString().string, "Header 2\nSome following text\n")
|
||||
XCTAssertEqual(md.attributedString().string, "Header 2\nSome following text")
|
||||
|
||||
md = SwiftyMarkdown(string: h1StringWithBold)
|
||||
XCTAssertEqual(md.attributedString().string, "Header 1 With Bold\nSome following text\n")
|
||||
XCTAssertEqual(md.attributedString().string, "Header 1 With Bold\nSome following text")
|
||||
|
||||
md = SwiftyMarkdown(string: h2StringWithItalic)
|
||||
XCTAssertEqual(md.attributedString().string, "Header 2 With Italic\nSome following text\n")
|
||||
XCTAssertEqual(md.attributedString().string, "Header 2 With Italic\nSome following text")
|
||||
|
||||
md = SwiftyMarkdown(string: h2StringWithCode)
|
||||
XCTAssertEqual(md.attributedString().string, "Header 2 With Code\nSome following text\n")
|
||||
XCTAssertEqual(md.attributedString().string, "Header 2 With Code\nSome following text")
|
||||
}
|
||||
|
||||
func testThatRegularTraitsAreParsedCorrectly() {
|
||||
@@ -78,34 +78,34 @@ class SwiftyMarkdownTests: XCTestCase {
|
||||
|
||||
|
||||
var md = SwiftyMarkdown(string: boldAtStartOfString)
|
||||
XCTAssertEqual(md.attributedString().string, "A bold string\n")
|
||||
XCTAssertEqual(md.attributedString().string, "A bold string")
|
||||
|
||||
md = SwiftyMarkdown(string: boldWithinString)
|
||||
XCTAssertEqual(md.attributedString().string, "A string with a bold word\n")
|
||||
XCTAssertEqual(md.attributedString().string, "A string with a bold word")
|
||||
|
||||
md = SwiftyMarkdown(string: codeAtStartOfString)
|
||||
XCTAssertEqual(md.attributedString().string, "\tCode (should be indented)\n")
|
||||
XCTAssertEqual(md.attributedString().string, "\tCode (should be indented)")
|
||||
|
||||
md = SwiftyMarkdown(string: codeWithinString)
|
||||
XCTAssertEqual(md.attributedString().string, "A string with code (should not be indented)\n")
|
||||
XCTAssertEqual(md.attributedString().string, "A string with code (should not be indented)")
|
||||
|
||||
md = SwiftyMarkdown(string: italicAtStartOfString)
|
||||
XCTAssertEqual(md.attributedString().string, "An italicised string\n")
|
||||
XCTAssertEqual(md.attributedString().string, "An italicised string")
|
||||
|
||||
md = SwiftyMarkdown(string: italicWithinString)
|
||||
XCTAssertEqual(md.attributedString().string, "A string with italicised text\n")
|
||||
XCTAssertEqual(md.attributedString().string, "A string with italicised text")
|
||||
|
||||
md = SwiftyMarkdown(string: multipleBoldWords)
|
||||
XCTAssertEqual(md.attributedString().string, "A bold string with a mix of bold styles\n")
|
||||
XCTAssertEqual(md.attributedString().string, "A bold string with a mix of bold styles")
|
||||
|
||||
md = SwiftyMarkdown(string: multipleCodeWords)
|
||||
XCTAssertEqual(md.attributedString().string, "\tA code string with multiple code instances\n")
|
||||
XCTAssertEqual(md.attributedString().string, "\tA code string with multiple code instances")
|
||||
|
||||
md = SwiftyMarkdown(string: multipleItalicWords)
|
||||
XCTAssertEqual(md.attributedString().string, "An italic string with a mix of italic styles\n")
|
||||
XCTAssertEqual(md.attributedString().string, "An italic string with a mix of italic styles")
|
||||
|
||||
md = SwiftyMarkdown(string: longMixedString)
|
||||
XCTAssertEqual(md.attributedString().string, "An italic string, follwed by a bold one, with some code, **and some** _escaped_ `characters`, ending with more variety.\n")
|
||||
XCTAssertEqual(md.attributedString().string, "An italic string, follwed by a bold one, with some code, **and some** _escaped_ `characters`, ending with more variety.")
|
||||
|
||||
}
|
||||
|
||||
@@ -114,10 +114,10 @@ class SwiftyMarkdownTests: XCTestCase {
|
||||
let mismatchedBoldCharactersWithin = "A string *that should be italic**"
|
||||
|
||||
var md = SwiftyMarkdown(string: mismatchedBoldCharactersAtStart)
|
||||
XCTAssertEqual(md.attributedString().string, "This should be bold\n")
|
||||
XCTAssertEqual(md.attributedString().string, "This should be bold")
|
||||
|
||||
md = SwiftyMarkdown(string: mismatchedBoldCharactersWithin)
|
||||
XCTAssertEqual(md.attributedString().string, "A string that should be italic\n")
|
||||
XCTAssertEqual(md.attributedString().string, "A string that should be italic")
|
||||
|
||||
}
|
||||
|
||||
@@ -138,39 +138,42 @@ class SwiftyMarkdownTests: XCTestCase {
|
||||
let oneEscapedAsteriskTwoNormalWithin = "A string with *\\**escaped**\\* asterisks"
|
||||
|
||||
var md = SwiftyMarkdown(string: escapedBoldAtStart)
|
||||
XCTAssertEqual(md.attributedString().string, "**A normal string**\n")
|
||||
XCTAssertEqual(md.attributedString().string, "**A normal string**")
|
||||
|
||||
md = SwiftyMarkdown(string: escapedBoldWithin)
|
||||
XCTAssertEqual(md.attributedString().string, "A string with **escaped** asterisks\n")
|
||||
XCTAssertEqual(md.attributedString().string, "A string with **escaped** asterisks")
|
||||
|
||||
md = SwiftyMarkdown(string: escapedItalicAtStart)
|
||||
XCTAssertEqual(md.attributedString().string, "_A normal string_\n")
|
||||
XCTAssertEqual(md.attributedString().string, "_A normal string_")
|
||||
|
||||
md = SwiftyMarkdown(string: escapedItalicWithin)
|
||||
XCTAssertEqual(md.attributedString().string, "A string with _escaped_ underscores\n")
|
||||
XCTAssertEqual(md.attributedString().string, "A string with _escaped_ underscores")
|
||||
|
||||
md = SwiftyMarkdown(string: escapedBackticksAtStart)
|
||||
XCTAssertEqual(md.attributedString().string, "`A normal string`\n")
|
||||
XCTAssertEqual(md.attributedString().string, "`A normal string`")
|
||||
|
||||
md = SwiftyMarkdown(string: escapedBacktickWithin)
|
||||
XCTAssertEqual(md.attributedString().string, "A string with `escaped` backticks\n")
|
||||
XCTAssertEqual(md.attributedString().string, "A string with `escaped` backticks")
|
||||
|
||||
md = SwiftyMarkdown(string: oneEscapedAsteriskOneNormalAtStart)
|
||||
XCTAssertEqual(md.attributedString().string, "*A normal string*\n")
|
||||
XCTAssertEqual(md.attributedString().string, "*A normal string*")
|
||||
|
||||
md = SwiftyMarkdown(string: oneEscapedAsteriskOneNormalWithin)
|
||||
XCTAssertEqual(md.attributedString().string, "A string with *escaped* asterisks\n")
|
||||
XCTAssertEqual(md.attributedString().string, "A string with *escaped* asterisks")
|
||||
|
||||
md = SwiftyMarkdown(string: oneEscapedAsteriskTwoNormalAtStart)
|
||||
XCTAssertEqual(md.attributedString().string, "*A normal string*\n")
|
||||
XCTAssertEqual(md.attributedString().string, "*A normal string*")
|
||||
|
||||
md = SwiftyMarkdown(string: oneEscapedAsteriskTwoNormalWithin)
|
||||
XCTAssertEqual(md.attributedString().string, "A string with *escaped* asterisks\n")
|
||||
XCTAssertEqual(md.attributedString().string, "A string with *escaped* asterisks")
|
||||
|
||||
}
|
||||
|
||||
func testThatAsterisksAndUnderscoresNotAttachedToWordsAreNotRemoved() {
|
||||
let asteriskSpace = "An asterisk followed by a space: * "
|
||||
let asteriskSpace = """
|
||||
An asterisk followed by a space: *
|
||||
Line break
|
||||
"""
|
||||
let backtickSpace = "A backtick followed by a space: ` "
|
||||
let underscoreSpace = "An underscore followed by a space: _ "
|
||||
|
||||
@@ -187,43 +190,43 @@ class SwiftyMarkdownTests: XCTestCase {
|
||||
let underscoreWithItalic = "An _italic_ word followed by an underscore _ "
|
||||
|
||||
var md = SwiftyMarkdown(string: asteriskSpace)
|
||||
XCTAssertEqual(md.attributedString().string, asteriskSpace + "\n")
|
||||
XCTAssertEqual(md.attributedString().string, asteriskSpace)
|
||||
|
||||
md = SwiftyMarkdown(string: backtickSpace)
|
||||
XCTAssertEqual(md.attributedString().string, backtickSpace + "\n")
|
||||
XCTAssertEqual(md.attributedString().string, backtickSpace)
|
||||
|
||||
md = SwiftyMarkdown(string: underscoreSpace)
|
||||
XCTAssertEqual(md.attributedString().string, underscoreSpace + "\n")
|
||||
XCTAssertEqual(md.attributedString().string, underscoreSpace)
|
||||
|
||||
md = SwiftyMarkdown(string: asteriskFullStop)
|
||||
XCTAssertEqual(md.attributedString().string, asteriskFullStop + "\n")
|
||||
XCTAssertEqual(md.attributedString().string, asteriskFullStop)
|
||||
|
||||
md = SwiftyMarkdown(string: backtickFullStop)
|
||||
XCTAssertEqual(md.attributedString().string, backtickFullStop + "\n")
|
||||
XCTAssertEqual(md.attributedString().string, backtickFullStop)
|
||||
|
||||
md = SwiftyMarkdown(string: underscoreFullStop)
|
||||
XCTAssertEqual(md.attributedString().string, underscoreFullStop + "\n")
|
||||
XCTAssertEqual(md.attributedString().string, underscoreFullStop)
|
||||
|
||||
md = SwiftyMarkdown(string: asteriskComma)
|
||||
XCTAssertEqual(md.attributedString().string, asteriskComma + "\n")
|
||||
XCTAssertEqual(md.attributedString().string, asteriskComma)
|
||||
|
||||
md = SwiftyMarkdown(string: backtickComma)
|
||||
XCTAssertEqual(md.attributedString().string, backtickComma + "\n")
|
||||
XCTAssertEqual(md.attributedString().string, backtickComma)
|
||||
|
||||
md = SwiftyMarkdown(string: underscoreComma)
|
||||
XCTAssertEqual(md.attributedString().string, underscoreComma + "\n")
|
||||
XCTAssertEqual(md.attributedString().string, underscoreComma)
|
||||
|
||||
md = SwiftyMarkdown(string: asteriskWithBold)
|
||||
XCTAssertEqual(md.attributedString().string, "A bold word followed by an asterisk * \n")
|
||||
XCTAssertEqual(md.attributedString().string, "A bold word followed by an asterisk * ")
|
||||
|
||||
md = SwiftyMarkdown(string: backtickWithCode)
|
||||
XCTAssertEqual(md.attributedString().string, "A code word followed by a backtick ` \n")
|
||||
XCTAssertEqual(md.attributedString().string, "A code word followed by a backtick ` ")
|
||||
|
||||
md = SwiftyMarkdown(string: underscoreWithItalic)
|
||||
XCTAssertEqual(md.attributedString().string, "An italic word followed by an underscore _ \n")
|
||||
XCTAssertEqual(md.attributedString().string, "An italic word followed by an underscore _ ")
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
func testForLinks() {
|
||||
|
||||
@@ -242,39 +245,53 @@ class SwiftyMarkdownTests: XCTestCase {
|
||||
let syntaxErrorParenthesisWithin = "A [Link](http://voyagetravelapps.com/"
|
||||
|
||||
var md = SwiftyMarkdown(string: linkAtStart)
|
||||
XCTAssertEqual(md.attributedString().string, "Link at start\n")
|
||||
XCTAssertEqual(md.attributedString().string, "Link at start")
|
||||
|
||||
md = SwiftyMarkdown(string: linkWithin)
|
||||
XCTAssertEqual(md.attributedString().string, "A Link\n")
|
||||
XCTAssertEqual(md.attributedString().string, "A Link")
|
||||
|
||||
md = SwiftyMarkdown(string: headerLink)
|
||||
XCTAssertEqual(md.attributedString().string, "Header link\n")
|
||||
XCTAssertEqual(md.attributedString().string, "Header link")
|
||||
|
||||
md = SwiftyMarkdown(string: multipleLinks)
|
||||
XCTAssertEqual(md.attributedString().string, "Link 1, Link 2\n")
|
||||
XCTAssertEqual(md.attributedString().string, "Link 1, Link 2")
|
||||
|
||||
md = SwiftyMarkdown(string: syntaxErrorSquareBracketAtStart)
|
||||
XCTAssertEqual(md.attributedString().string, "Link with missing square\n")
|
||||
XCTAssertEqual(md.attributedString().string, "Link with missing square")
|
||||
|
||||
md = SwiftyMarkdown(string: syntaxErrorSquareBracketWithin)
|
||||
XCTAssertEqual(md.attributedString().string, "A Link\n")
|
||||
XCTAssertEqual(md.attributedString().string, "A Link")
|
||||
|
||||
md = SwiftyMarkdown(string: syntaxErrorParenthesisAtStart)
|
||||
XCTAssertEqual(md.attributedString().string, "Link with missing parenthesis\n")
|
||||
XCTAssertEqual(md.attributedString().string, "Link with missing parenthesis")
|
||||
|
||||
md = SwiftyMarkdown(string: syntaxErrorParenthesisWithin)
|
||||
XCTAssertEqual(md.attributedString().string, "A Link\n")
|
||||
XCTAssertEqual(md.attributedString().string, "A Link")
|
||||
|
||||
md = SwiftyMarkdown(string: mailtoAndTwitterLinks)
|
||||
XCTAssertEqual(md.attributedString().string, "Email us at simon@voyagetravelapps.com Twitter @VoyageTravelApp\n")
|
||||
XCTAssertEqual(md.attributedString().string, "Email us at simon@voyagetravelapps.com Twitter @VoyageTravelApp")
|
||||
|
||||
|
||||
|
||||
// let mailtoAndTwitterLinks = "Twitter [@VoyageTravelApp](twitter://user?screen_name=VoyageTravelApp)"
|
||||
// let md = SwiftyMarkdown(string: mailtoAndTwitterLinks)
|
||||
// XCTAssertEqual(md.attributedString().string, "Twitter @VoyageTravelApp\n")
|
||||
// XCTAssertEqual(md.attributedString().string, "Twitter @VoyageTravelApp")
|
||||
}
|
||||
|
||||
/*
|
||||
The reason for this test is because the list of items dropped every other item in bullet lists marked with "-"
|
||||
The faulty result was: "A cool title\n \n- Här har vi svenska ÅÄÖåäö tecken\n \nA Link"
|
||||
As you can see, "- Point number one" and "- Point number two" are mysteriously missing.
|
||||
It incorrectly identified rows as `Alt-H2`
|
||||
*/
|
||||
func testInternationalCharactersInList() {
|
||||
|
||||
let extected = "A cool title\n \n- Point number one\n- Här har vi svenska ÅÄÖåäö tecken\n- Point number two\n \nA Link"
|
||||
let input = "# A cool title\n\n- Point number one\n- Här har vi svenska ÅÄÖåäö tecken\n- Point number two\n\n[A Link](http://dooer.com)"
|
||||
let output = SwiftyMarkdown(string: input).attributedString().string
|
||||
|
||||
XCTAssertEqual(output, extected)
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+4
-69
@@ -16,73 +16,8 @@
|
||||
|
||||
# This is the minimum version number required.
|
||||
# Update this, if you use features of a newer version
|
||||
fastlane_version "1.36.1"
|
||||
$scheme = "SwiftyMarkdown"
|
||||
$spec = "SwiftyMarkdown.podspec"
|
||||
$project = './SwiftyMarkdown.xcodeproj'
|
||||
|
||||
default_platform :ios
|
||||
|
||||
|
||||
|
||||
platform :ios do
|
||||
|
||||
spec = "SwiftyMarkdown.podspec"
|
||||
|
||||
before_all do
|
||||
ensure_git_branch
|
||||
ensure_git_status_clean
|
||||
increment_build_number
|
||||
commit_version_bump(xcodeproj: './SwiftyMarkdown.xcodeproj')
|
||||
end
|
||||
|
||||
desc "Bumps the patch version, increments it, and pushes it to both the remote and spec repos"
|
||||
lane :patch do
|
||||
# snapshot
|
||||
update(type: "patch")
|
||||
end
|
||||
|
||||
desc "Bumps the minor version, increments it, and pushes it to both the remote and spec repos"
|
||||
lane :minor do
|
||||
# snapshot
|
||||
update(type: "minor")
|
||||
|
||||
end
|
||||
|
||||
lane :initial do
|
||||
version = version_get_podspec
|
||||
bump(version: version)
|
||||
end
|
||||
|
||||
private_lane :update do |options|
|
||||
|
||||
type = options[:type]
|
||||
version = version_bump_podspec(path: spec, bump_type: type)
|
||||
increment_version_number( bump_type: type, version_number: version )
|
||||
git_commit(path: spec, message: "Updating podspec")
|
||||
|
||||
bump(version: version)
|
||||
|
||||
end
|
||||
|
||||
private_lane :bump do |options|
|
||||
version = options[:version]
|
||||
add_git_tag( tag: version)
|
||||
push_to_git_remote
|
||||
pod_push(path: spec)
|
||||
|
||||
end
|
||||
|
||||
# You can define as many lanes as you want
|
||||
|
||||
after_all do |lane|
|
||||
# This block is called, only if the executed lane was successful
|
||||
notification(subtitle: "SwiftyMarkdown fastlane finished", message: "Completed '#{lane}' successfully")
|
||||
end
|
||||
|
||||
error do |lane, exception|
|
||||
notification(subtitle: "Error: SwiftyMarkdown fastlane", message: "'#{exception.message}'")
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
|
||||
# More information about multiple platforms in fastlane: https://github.com/KrauseFx/fastlane/blob/master/docs/Platforms.md
|
||||
# All available actions: https://github.com/KrauseFx/fastlane/blob/master/docs/Actions.md
|
||||
import "../../Fastlane/FastfilePods"
|
||||
+66
-8
@@ -1,29 +1,87 @@
|
||||
fastlane documentation
|
||||
================
|
||||
# Installation
|
||||
|
||||
Make sure you have the latest version of the Xcode command line tools installed:
|
||||
|
||||
```
|
||||
sudo gem install fastlane
|
||||
xcode-select --install
|
||||
```
|
||||
|
||||
## Choose your installation method:
|
||||
|
||||
<table width="100%" >
|
||||
<tr>
|
||||
<th width="33%"><a href="http://brew.sh">Homebrew</a></td>
|
||||
<th width="33%">Installer Script</td>
|
||||
<th width="33%">Rubygems</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td width="33%" align="center">macOS</td>
|
||||
<td width="33%" align="center">macOS</td>
|
||||
<td width="33%" align="center">macOS or Linux with Ruby 2.0.0 or above</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td width="33%"><code>brew cask install fastlane</code></td>
|
||||
<td width="33%"><a href="https://download.fastlane.tools">Download the zip file</a>. Then double click on the <code>install</code> script (or run it in a terminal window).</td>
|
||||
<td width="33%"><code>sudo gem install fastlane -NV</code></td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
# Available Actions
|
||||
## iOS
|
||||
### ios patch
|
||||
```
|
||||
fastlane ios patch
|
||||
```
|
||||
Bumps the patch version, increments it, and pushes it to both the remote and spec repos
|
||||
This does the following:
|
||||
|
||||
|
||||
|
||||
- Runs the unit tests
|
||||
|
||||
- Ensures Cocoapods compatibility
|
||||
|
||||
- Bumps the patch version
|
||||
### ios minor
|
||||
```
|
||||
fastlane ios minor
|
||||
```
|
||||
Bumps the minor version, increments it, and pushes it to both the remote and spec repos
|
||||
### ios initial
|
||||
This does the following:
|
||||
|
||||
|
||||
|
||||
- Runs the unit tests
|
||||
|
||||
- Ensures Cocoapods compatibility
|
||||
|
||||
- Bumps the minor version
|
||||
### ios major
|
||||
```
|
||||
fastlane ios initial
|
||||
fastlane ios major
|
||||
```
|
||||
This does the following:
|
||||
|
||||
|
||||
|
||||
- Runs the unit tests
|
||||
|
||||
- Ensures Cocoapods compatibility
|
||||
|
||||
- Bumps the major version
|
||||
### ios test
|
||||
```
|
||||
fastlane ios test
|
||||
```
|
||||
|
||||
### ios submit_pod
|
||||
```
|
||||
fastlane ios submit_pod
|
||||
```
|
||||
Push the repo to remote and submits the Pod to the given spec repository. Do this after running update to run tests, bump versions, and commit changes.
|
||||
|
||||
----
|
||||
|
||||
This README.md is auto-generated and will be re-generated every time to run [fastlane](https://fastlane.tools).
|
||||
More information about fastlane can be found on [https://fastlane.tools](https://fastlane.tools).
|
||||
The documentation of fastlane can be found on [GitHub](https://github.com/fastlane/fastlane).
|
||||
This README.md is auto-generated and will be re-generated every time [fastlane](https://fastlane.tools) is run.
|
||||
More information about fastlane can be found on [fastlane.tools](https://fastlane.tools).
|
||||
The documentation of fastlane can be found on [docs.fastlane.tools](https://docs.fastlane.tools).
|
||||
|
||||
Reference in New Issue
Block a user