Skip to content

Instantly share code, notes, and snippets.

@xtravar
Created August 3, 2018 00:18
Show Gist options
  • Save xtravar/63382973bf80c89f6066d3185efa0853 to your computer and use it in GitHub Desktop.
Save xtravar/63382973bf80c89f6066d3185efa0853 to your computer and use it in GitHub Desktop.
NSAttributedString doing interpolation and being all struct-y
public struct AttributedString {
fileprivate var _handle: NSMutableAttributedString
fileprivate init(handle: NSMutableAttributedString) {
self._handle = handle
}
fileprivate init(_ str: NSAttributedString) {
self.init(handle: str.mutableCopy() as! NSMutableAttributedString)
}
fileprivate var handle: NSAttributedString { return self._handle }
fileprivate var mutatingHandle: NSMutableAttributedString {
mutating get {
if !isKnownUniquelyReferenced(&self._handle) {
self._handle = self.handle.mutableCopy() as! NSMutableAttributedString
}
return self._handle
}
}
}
extension AttributedString {
public init() {
self.init(NSMutableAttributedString())
}
public init(_ string: String) {
self.init(NSMutableAttributedString(string: string))
}
}
extension AttributedString {
public mutating func append(_ other: AttributedString) {
self.mutatingHandle.append(other.handle)
}
public static func + (_ lhs: AttributedString, _ rhs: AttributedString) -> AttributedString {
var result = lhs
result.append(rhs)
return result
}
}
extension AttributedString: ExpressibleByStringLiteral {
public init(stringLiteral value: String) {
self.init(NSMutableAttributedString(string: value))
}
}
extension AttributedString: _ObjectiveCBridgeable {
public func _bridgeToObjectiveC() -> NSAttributedString {
return self.handle
}
public static func _forceBridgeFromObjectiveC(_ source: NSAttributedString, result: inout AttributedString?) {
result = self.init(source.copy() as! NSAttributedString)
}
public static func _conditionallyBridgeFromObjectiveC(_ source: NSAttributedString, result: inout AttributedString?) -> Bool {
result = self.init(source.copy() as! NSAttributedString)
return true
}
public static func _unconditionallyBridgeFromObjectiveC(_ source: NSAttributedString?) -> AttributedString {
guard let s = source else {
return AttributedString()
}
return AttributedString(s)
}
public typealias _ObjectiveCType = NSAttributedString
}
extension AttributedString: _ExpressibleByStringInterpolation {
public init(stringInterpolation strings: AttributedString...) {
let attributedString = NSMutableAttributedString()
strings.forEach {
attributedString.append($0.handle)
}
self.init(handle: attributedString)
}
public init<T>(stringInterpolationSegment expr: T) {
switch expr {
case let str as String:
self.init(str)
case let att as AttributedString:
self = att
default:
preconditionFailure()
}
}
}
public extension NSAttributedString {
public typealias AttributeCollection = [Key: Any]
public typealias AttributedPair = (item: CustomStringConvertible, attributes: AttributeCollection)
public convenience init(attributes: AttributeCollection, format: String, arguments: NSAttributedString...) {
self.init(attributes: attributes, format: format, arguments: arguments)
}
public convenience init(attributes: AttributeCollection, format: String, arguments: AttributedPair...) {
let attributedStrings = arguments.map { NSAttributedString(string: $0.item.description, attributes: $0.attributes) }
self.init(attributes: attributes, format: format, arguments: attributedStrings)
}
public convenience init(attributes: AttributeCollection, format: String, arguments: [NSAttributedString]) {
let placeholders = (0 ..< arguments.count).map { "%%\($0)%%" }
let formattedString = String(format: format, arguments: placeholders)
let result = NSMutableAttributedString(string: formattedString, attributes: attributes)
for arg in zip(placeholders, arguments) {
// format parameters can be used multiple times
while let range = resultString.range(of: arg.0) {
let resultString = result.string
result.replaceCharacters(in: NSRange(range, in: resultString), with: arg.1)
}
}
self.init(attributedString: result)
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment