Merge pull request #4 from JohnSundell/cross-platform-fix
Streamline cross-platform implementation
This commit is contained in:
commit
0ec69daecd
@ -4,13 +4,9 @@
|
||||
* MIT license - see LICENSE.md
|
||||
*/
|
||||
|
||||
#if os(macOS)
|
||||
import Cocoa
|
||||
#endif
|
||||
#if !os(Linux)
|
||||
|
||||
#if os(iOS)
|
||||
import UIKit
|
||||
#endif
|
||||
import Foundation
|
||||
|
||||
/// Output format to use to generate an NSAttributedString from the
|
||||
/// highlighted code. A `Theme` is used to determine what fonts and
|
||||
@ -30,7 +26,7 @@ public struct AttributedStringOutputFormat: OutputFormat {
|
||||
public extension AttributedStringOutputFormat {
|
||||
struct Builder: OutputBuilder {
|
||||
private let theme: Theme
|
||||
private lazy var font = loadFont()
|
||||
private lazy var font = theme.font.load()
|
||||
private var string = NSMutableAttributedString()
|
||||
|
||||
fileprivate init(theme: Theme) {
|
||||
@ -54,48 +50,13 @@ public extension AttributedStringOutputFormat {
|
||||
public func build() -> NSAttributedString {
|
||||
return NSAttributedString(attributedString: string)
|
||||
}
|
||||
|
||||
#if os(macOS)
|
||||
private mutating func loadFont() -> NSFont {
|
||||
let size = CGFloat(theme.font.size)
|
||||
|
||||
switch theme.font.resource {
|
||||
case .system:
|
||||
return .defaultFont(ofSize: size)
|
||||
case .path(let path):
|
||||
guard let font = NSFont.loaded(from: path, size: size) else {
|
||||
return .defaultFont(ofSize: size)
|
||||
}
|
||||
|
||||
return font
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#if os(iOS)
|
||||
private mutating func loadFont() -> UIFont {
|
||||
|
||||
let size = CGFloat(theme.font.size)
|
||||
return .defaultFont(ofSize: size)
|
||||
|
||||
}
|
||||
#endif
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#if os(macOS)
|
||||
private extension NSMutableAttributedString {
|
||||
func append(_ string: String, font: NSFont, color: Color) {
|
||||
let color = NSColor(
|
||||
red: CGFloat(color.red),
|
||||
green: CGFloat(color.green),
|
||||
blue: CGFloat(color.blue),
|
||||
alpha: CGFloat(color.alpha)
|
||||
)
|
||||
|
||||
func append(_ string: String, font: Font.Loaded, color: Color) {
|
||||
let attributedString = NSAttributedString(string: string, attributes: [
|
||||
.foregroundColor: color,
|
||||
.foregroundColor: color.renderable,
|
||||
.font: font
|
||||
])
|
||||
|
||||
@ -103,60 +64,4 @@ private extension NSMutableAttributedString {
|
||||
}
|
||||
}
|
||||
|
||||
private extension NSFont {
|
||||
static func loaded(from path: String, size: CGFloat) -> NSFont? {
|
||||
let url = CFURLCreateWithFileSystemPath(
|
||||
kCFAllocatorDefault,
|
||||
path as CFString,
|
||||
.cfurlposixPathStyle,
|
||||
false
|
||||
)
|
||||
|
||||
guard let font = url.flatMap(CGDataProvider.init).flatMap(CGFont.init) else {
|
||||
return nil
|
||||
}
|
||||
|
||||
return CTFontCreateWithGraphicsFont(font, size, nil, nil)
|
||||
}
|
||||
|
||||
static func defaultFont(ofSize size: CGFloat) -> NSFont {
|
||||
guard let courier = loaded(from: "/Library/Fonts/Courier New.ttf", size: size) else {
|
||||
return .systemFont(ofSize: size)
|
||||
}
|
||||
|
||||
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
|
||||
|
@ -6,6 +6,8 @@
|
||||
|
||||
import Foundation
|
||||
|
||||
#if !os(Linux)
|
||||
|
||||
/// A representation of a color, for use with a `Theme`.
|
||||
/// Since Splash aims to be cross-platform, it uses this
|
||||
/// simplified color representation rather than `NSColor`
|
||||
@ -23,3 +25,34 @@ public struct Color {
|
||||
self.alpha = alpha
|
||||
}
|
||||
}
|
||||
|
||||
internal extension Color {
|
||||
var renderable: Renderable {
|
||||
return Renderable(
|
||||
red: CGFloat(red),
|
||||
green: CGFloat(green),
|
||||
blue: CGFloat(blue),
|
||||
alpha: CGFloat(alpha)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#if os(iOS)
|
||||
|
||||
import UIKit
|
||||
|
||||
internal extension Color {
|
||||
typealias Renderable = UIColor
|
||||
}
|
||||
|
||||
#elseif os(macOS)
|
||||
|
||||
import Cocoa
|
||||
|
||||
internal extension Color {
|
||||
typealias Renderable = NSColor
|
||||
}
|
||||
|
||||
#endif
|
||||
|
@ -6,9 +6,11 @@
|
||||
|
||||
import Foundation
|
||||
|
||||
#if !os(Linux)
|
||||
|
||||
/// A representation of a font, for use with a `Theme`.
|
||||
/// Since Splash aims to be cross-platform, it uses this
|
||||
/// simplified color representation rather than `NSFont`
|
||||
/// simplified font representation rather than `NSFont`
|
||||
/// or `UIFont`.
|
||||
public struct Font {
|
||||
/// The underlying resource used to load the font
|
||||
@ -19,12 +21,7 @@ public struct Font {
|
||||
/// Initialize an instance with a path to a font file
|
||||
/// on disk and a size.
|
||||
public init(path: String, size: Double) {
|
||||
#if os(macOS)
|
||||
resource = .path((path as NSString).expandingTildeInPath)
|
||||
#else
|
||||
resource = .path(path)
|
||||
#endif
|
||||
|
||||
self.size = size
|
||||
}
|
||||
|
||||
@ -41,7 +38,69 @@ public extension Font {
|
||||
enum Resource {
|
||||
/// Use an appropriate system font
|
||||
case system
|
||||
/// Use a pre-loaded font
|
||||
case preloaded(Loaded)
|
||||
/// Load a font file from a given file system path
|
||||
case path(String)
|
||||
}
|
||||
}
|
||||
|
||||
internal extension Font {
|
||||
func load() -> Loaded {
|
||||
switch resource {
|
||||
case .system:
|
||||
return loadDefaultFont()
|
||||
case .preloaded(let font):
|
||||
return font
|
||||
case .path(let path):
|
||||
return load(fromPath: path) ?? loadDefaultFont()
|
||||
}
|
||||
}
|
||||
|
||||
private func loadDefaultFont() -> Loaded {
|
||||
let font: Loaded?
|
||||
|
||||
#if os(iOS)
|
||||
font = UIFont(name: "Menlo-Regular", size: CGFloat(size))
|
||||
#else
|
||||
font = load(fromPath: "/Library/Fonts/Courier New.ttf")
|
||||
#endif
|
||||
|
||||
return font ?? .systemFont(ofSize: CGFloat(size))
|
||||
}
|
||||
|
||||
private func load(fromPath path: String) -> Loaded? {
|
||||
let url = CFURLCreateWithFileSystemPath(
|
||||
kCFAllocatorDefault,
|
||||
path as CFString,
|
||||
.cfurlposixPathStyle,
|
||||
false
|
||||
)
|
||||
|
||||
guard let font = url.flatMap(CGDataProvider.init).flatMap(CGFont.init) else {
|
||||
return nil
|
||||
}
|
||||
|
||||
return CTFontCreateWithGraphicsFont(font, CGFloat(size), nil, nil)
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#if os(iOS)
|
||||
|
||||
import UIKit
|
||||
|
||||
public extension Font {
|
||||
typealias Loaded = UIFont
|
||||
}
|
||||
|
||||
#elseif os(macOS)
|
||||
|
||||
import Cocoa
|
||||
|
||||
public extension Font {
|
||||
typealias Loaded = NSFont
|
||||
}
|
||||
|
||||
#endif
|
||||
|
@ -6,13 +6,9 @@
|
||||
|
||||
import Foundation
|
||||
|
||||
/*
|
||||
* Extends the Theme struct with static properties that
|
||||
* represent common Xcode defaults as well as community
|
||||
* favourites.
|
||||
*/
|
||||
public extension Theme {
|
||||
#if !os(Linux)
|
||||
|
||||
public extension Theme {
|
||||
/// Create a theme matching the "Sundell's Colors" Xcode theme
|
||||
static func sundellsColors(withFont font: Font) -> Theme {
|
||||
return Theme(
|
||||
@ -36,6 +32,7 @@ public extension Theme {
|
||||
)
|
||||
}
|
||||
|
||||
/// Create a theme matching Xcode's "Midnight" theme
|
||||
static func midnight(withFont font: Font) -> Theme {
|
||||
return Theme(
|
||||
font: font,
|
||||
@ -58,6 +55,7 @@ public extension Theme {
|
||||
)
|
||||
}
|
||||
|
||||
/// Creating a theme matching the colors used for the WWDC 2017 sample code
|
||||
static func wwdc17(withFont font: Font) -> Theme {
|
||||
return Theme(
|
||||
font: font,
|
||||
@ -80,6 +78,7 @@ public extension Theme {
|
||||
)
|
||||
}
|
||||
|
||||
/// Creating a theme matching the colors used for the WWDC 2018 sample code
|
||||
static func wwdc18(withFont font: Font) -> Theme {
|
||||
return Theme(
|
||||
font: font,
|
||||
@ -102,6 +101,7 @@ public extension Theme {
|
||||
)
|
||||
}
|
||||
|
||||
/// Create a theme matching Xcode's "Sunset" theme
|
||||
static func sunset(withFont font: Font) -> Theme {
|
||||
return Theme(
|
||||
font: font,
|
||||
@ -124,6 +124,7 @@ public extension Theme {
|
||||
)
|
||||
}
|
||||
|
||||
/// Create a theme matching Xcode's "Presentation" theme
|
||||
static func presentation(withFont font: Font) -> Theme {
|
||||
return Theme(
|
||||
font: font,
|
||||
@ -145,5 +146,6 @@ public extension Theme {
|
||||
]
|
||||
)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
@ -6,10 +6,11 @@
|
||||
|
||||
import Foundation
|
||||
|
||||
#if !os(Linux)
|
||||
|
||||
/// A theme describes what fonts and colors to use when rendering
|
||||
/// certain output formats - such as `NSAttributedString`. A default
|
||||
/// implementation is provided that matches the "Sundell's Colors"
|
||||
/// Xcode theme, by using the `sundellsColors(withFont:)` method.
|
||||
/// certain output formats - such as `NSAttributedString`. Several
|
||||
/// default implementations are provided - see Theme+Defaults.swift.
|
||||
public struct Theme {
|
||||
/// What font to use to render the highlighted text
|
||||
public var font: Font
|
||||
@ -24,3 +25,5 @@ public struct Theme {
|
||||
self.tokenColors = tokenColors
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
Loading…
x
Reference in New Issue
Block a user