Implements iOS support for AttributedStringOutputFormat

This commit is contained in:
Mihael Cholakov 2018-08-25 21:49:30 +03:00
parent 54598263bb
commit 5702cea843

View File

@ -5,19 +5,23 @@
*/ */
#if os(macOS) #if os(macOS)
import Cocoa import Cocoa
#endif
#if os(iOS)
import UIKit
#endif
/// Output format to use to generate an NSAttributedString from the /// Output format to use to generate an NSAttributedString from the
/// highlighted code. A `Theme` is used to determine what fonts and /// highlighted code. A `Theme` is used to determine what fonts and
/// colors to use for the various tokens. /// colors to use for the various tokens.
public struct AttributedStringOutputFormat: OutputFormat { public struct AttributedStringOutputFormat: OutputFormat {
public var theme: Theme public var theme: Theme
public init(theme: Theme) { public init(theme: Theme) {
self.theme = theme self.theme = theme
} }
public func makeBuilder() -> Builder { public func makeBuilder() -> Builder {
return Builder(theme: theme) return Builder(theme: theme)
} }
@ -28,32 +32,33 @@ public extension AttributedStringOutputFormat {
private let theme: Theme private let theme: Theme
private lazy var font = loadFont() private lazy var font = loadFont()
private var string = NSMutableAttributedString() private var string = NSMutableAttributedString()
fileprivate init(theme: Theme) { fileprivate init(theme: Theme) {
self.theme = theme self.theme = theme
} }
public mutating func addToken(_ token: String, ofType type: TokenType) { public mutating func addToken(_ token: String, ofType type: TokenType) {
let color = theme.tokenColors[type] ?? Color(red: 1, green: 1, blue: 1) let color = theme.tokenColors[type] ?? Color(red: 1, green: 1, blue: 1)
string.append(token, font: font, color: color) string.append(token, font: font, color: color)
} }
public mutating func addPlainText(_ text: String) { public mutating func addPlainText(_ text: String) {
string.append(text, font: font, color: theme.plainTextColor) string.append(text, font: font, color: theme.plainTextColor)
} }
public mutating func addWhitespace(_ whitespace: String) { public mutating func addWhitespace(_ whitespace: String) {
let color = Color(red: 1, green: 1, blue: 1) let color = Color(red: 1, green: 1, blue: 1)
string.append(whitespace, font: font, color: color) string.append(whitespace, font: font, color: color)
} }
public func build() -> NSAttributedString { public func build() -> NSAttributedString {
return NSAttributedString(attributedString: string) return NSAttributedString(attributedString: string)
} }
#if os(macOS)
private mutating func loadFont() -> NSFont { private mutating func loadFont() -> NSFont {
let size = CGFloat(theme.font.size) let size = CGFloat(theme.font.size)
switch theme.font.resource { switch theme.font.resource {
case .system: case .system:
return .defaultFont(ofSize: size) return .defaultFont(ofSize: size)
@ -61,13 +66,26 @@ public extension AttributedStringOutputFormat {
guard let font = NSFont.loaded(from: path, size: size) else { guard let font = NSFont.loaded(from: path, size: size) else {
return .defaultFont(ofSize: size) return .defaultFont(ofSize: size)
} }
return font return font
} }
} }
#endif
#if os(iOS)
private mutating func loadFont() -> UIFont {
let size = CGFloat(theme.font.size)
let font = UIFont.defaultFont(ofSize: size)
return font
}
#endif
} }
} }
#if os(macOS)
private extension NSMutableAttributedString { private extension NSMutableAttributedString {
func append(_ string: String, font: NSFont, color: Color) { func append(_ string: String, font: NSFont, color: Color) {
let color = NSColor( let color = NSColor(
@ -76,12 +94,12 @@ private extension NSMutableAttributedString {
blue: CGFloat(color.blue), blue: CGFloat(color.blue),
alpha: CGFloat(color.alpha) alpha: CGFloat(color.alpha)
) )
let attributedString = NSAttributedString(string: string, attributes: [ let attributedString = NSAttributedString(string: string, attributes: [
.foregroundColor: color, .foregroundColor: color,
.font: font .font: font
]) ])
append(attributedString) append(attributedString)
} }
} }
@ -94,21 +112,52 @@ private extension NSFont {
.cfurlposixPathStyle, .cfurlposixPathStyle,
false false
) )
guard let font = url.flatMap(CGDataProvider.init).flatMap(CGFont.init) else { guard let font = url.flatMap(CGDataProvider.init).flatMap(CGFont.init) else {
return nil return nil
} }
return CTFontCreateWithGraphicsFont(font, size, nil, nil) return CTFontCreateWithGraphicsFont(font, size, nil, nil)
} }
static func defaultFont(ofSize size: CGFloat) -> NSFont { static func defaultFont(ofSize size: CGFloat) -> NSFont {
guard let courier = loaded(from: "/Library/Fonts/Courier New.ttf", size: size) else { guard let courier = loaded(from: "/Library/Fonts/Courier New.ttf", size: size) else {
return .systemFont(ofSize: size) return .systemFont(ofSize: size)
} }
return courier return courier
} }
} }
#endif
#if os(iOS)
private extension NSMutableAttributedString {
func append(_ string: String, font: UIFont, color: Color) {
let color = UIColor(
red: CGFloat(color.red),
green: CGFloat(color.green),
blue: CGFloat(color.blue),
alpha: CGFloat(color.alpha)
)
let attributedString = NSAttributedString(string: string, attributes: [
.foregroundColor: color,
.font: font
])
append(attributedString)
}
}
private extension UIFont {
static func defaultFont(ofSize size: CGFloat) -> UIFont {
guard let menlo = UIFont(name: "Menlo-Regular", size: size) else {
return .systemFont(ofSize: size)
}
return menlo
}
}
#endif #endif