Created
August 3, 2018 00:18
-
-
Save xtravar/63382973bf80c89f6066d3185efa0853 to your computer and use it in GitHub Desktop.
NSAttributedString doing interpolation and being all struct-y
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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