Skip to content

Instantly share code, notes, and snippets.

@AliSoftware
Last active August 7, 2019 09:25
Show Gist options
  • Save AliSoftware/3018509f647e812d603029cd803d70f9 to your computer and use it in GitHub Desktop.
Save AliSoftware/3018509f647e812d603029cd803d70f9 to your computer and use it in GitHub Desktop.
//#! Swift 5
import Foundation
import AppKit
////////////////////////////////////////////////////////////////////
//: ## Type Definition
struct AttrString {
let attributedString: NSAttributedString
}
extension AttrString: ExpressibleByStringLiteral {
init(stringLiteral: String) {
self.attributedString = NSAttributedString(string: stringLiteral)
}
}
extension AttrString: CustomStringConvertible {
var description: String {
return String(describing: self.attributedString)
}
}
////////////////////////////////////////////////////////////////////
//: ## StringInterpolation Support (Designated methods)
extension AttrString: ExpressibleByStringInterpolation {
init(stringInterpolation: StringInterpolation) {
self.attributedString = NSAttributedString(attributedString: stringInterpolation.attributedString)
}
struct StringInterpolation: StringInterpolationProtocol {
var attributedString: NSMutableAttributedString
init(literalCapacity: Int, interpolationCount: Int) {
self.attributedString = NSMutableAttributedString()
}
func appendLiteral(_ literal: String) {
let astr = NSAttributedString(string: literal)
self.attributedString.append(astr)
}
func appendInterpolation(_ string: String, attributes: [NSAttributedString.Key: Any]) {
let astr = NSAttributedString(string: string, attributes: attributes)
self.attributedString.append(astr)
}
}
}
////////////////////////////////////////////////////////////////////
//: ## StringInterpolation : Style convenience methods
extension AttrString.StringInterpolation {
struct Style {
let attributes: [NSAttributedString.Key: Any]
static func font(_ font: NSFont) -> Style {
return Style(attributes: [.font: font])
}
static func color(_ color: NSColor) -> Style {
return Style(attributes: [.foregroundColor: color])
}
static func bgColor(_ color: NSColor) -> Style {
return Style(attributes: [.backgroundColor: color])
}
static func link(_ link: String) -> Style {
return .link(URL(string: link)!)
}
static func link(_ link: URL) -> Style {
return Style(attributes: [.link: link])
}
static let bold = Style(attributes: [.strokeWidth: -3.0])
static let oblique = Style(attributes: [.obliqueness: 0.1])
static func underline(_ color: NSColor, _ style: NSUnderlineStyle) -> Style {
return Style(attributes: [
.underlineColor: color,
.underlineStyle: style.rawValue
])
}
static func alignment(_ alignment: NSTextAlignment) -> Style {
let ps = NSMutableParagraphStyle()
ps.alignment = alignment
return Style(attributes: [.paragraphStyle: ps])
}
}
func appendInterpolation(_ string: String, _ style: Style...) {
var attrs: [NSAttributedString.Key: Any] = [:]
style.forEach { attrs.merge($0.attributes, uniquingKeysWith: {$1}) }
let astr = NSAttributedString(string: string, attributes: attrs)
self.attributedString.append(astr)
}
func appendInterpolation(image: NSImage, scale: CGFloat = 1.0) {
let attachment = NSTextAttachment()
let size = NSSize(
width: image.size.width * scale,
height: image.size.height * scale
)
attachment.image = NSImage(size: size, flipped: false, drawingHandler: { (rect: NSRect) -> Bool in
NSGraphicsContext.current?.cgContext.translateBy(x: 0, y: size.height)
NSGraphicsContext.current?.cgContext.scaleBy(x: 1, y: -1)
image.draw(in: rect)
return true
})
self.attributedString.append(NSAttributedString(attachment: attachment))
}
}
//////////////////////////////////
//: ## Demo
let str: AttrString = """
Hello \("world", .color(.red)), isn't this \("cool", .color(.blue), .bold, .oblique, .underline(.purple, .single))?
\(" Yay! ", .font(.systemFont(ofSize: 36)), .color(.blue), .bgColor(.yellow), .alignment(.center))
\(image: #imageLiteral(resourceName: "Logo_Apple_Swift.png"), scale: 0.5)
Oh, btw, here's a \("nice link", .link("http://swift.org"), .underline(.blue, .single))!
"""
//: Display
import PlaygroundSupport
let view = NSTextView(frame: NSRect(x: 0, y: 0, width: 300, height: 300))
view.textStorage?.setAttributedString(str.attributedString)
PlaygroundPage.current.liveView = view
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment