Last active
August 12, 2018 21:35
-
-
Save jtbandes/0ecc47a7555bcffe9cd2 to your computer and use it in GitHub Desktop.
xcpaste — copy formatted code as HTML/CSS
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
// Output a HTML version of rich text on the pasteboard. Useful for nabbing Xcode syntax highlighting. | |
import Cocoa | |
extension String { | |
subscript(characterRange characterRange: Range<Int>) -> String { | |
let start = advance(startIndex, characterRange.startIndex) | |
let end = advance(start, characterRange.count) | |
return self[start..<end] | |
} | |
} | |
extension Dictionary { | |
mutating func getOrInsertValueForKey(key: Key, defaultValue: Key -> Value) -> Value { | |
if let value = self[key] { | |
return value | |
} | |
let newValue = defaultValue(key) | |
self[key] = newValue | |
return newValue | |
} | |
} | |
extension String { | |
var xmlEscapedString: String { | |
return CFXMLCreateStringByEscapingEntities(nil, self, nil) as String | |
} | |
} | |
extension NSColor { | |
var hexRepresentation: String { | |
var red: CGFloat = 0, green: CGFloat = 0, blue: CGFloat = 0 | |
colorUsingColorSpace(NSColorSpace.genericRGBColorSpace())?.getRed(&red, green: &green, blue: &blue, alpha: nil) | |
return String(format: "%02x%02x%02x", CInt(red*255), CInt(green*255), CInt(blue*255)) | |
} | |
} | |
extension NSAttributedString { | |
var attributeRuns: AnySequence<(String, [String: AnyObject])> { | |
return AnySequence<(String, [String: AnyObject])> { _ -> AnyGenerator<(String, [String: AnyObject])> in | |
let plain = self.string | |
var remainingRange = NSMakeRange(0, self.length) | |
return anyGenerator { | |
if remainingRange.length <= 0 { return nil } | |
var attrRange = NSRange(location: NSNotFound, length: 0) | |
let attrs = withUnsafeMutablePointer(&attrRange) { | |
self.attributesAtIndex(remainingRange.location, longestEffectiveRange: $0, inRange: remainingRange) | |
} | |
let ret = (plain[characterRange: attrRange.toRange()!], attrs) | |
remainingRange.location += attrRange.length | |
remainingRange.length -= attrRange.length | |
return ret | |
} | |
} | |
} | |
} | |
if let rtfdata = NSPasteboard.generalPasteboard().dataForType(kUTTypeRTF as String), | |
let source = NSAttributedString(RTF: rtfdata, documentAttributes: nil) | |
{ | |
var styleNames: [NSColor: String] = [:] | |
var styleString = "<style type=\"text/css\">\n" | |
var contentString = "<pre><code>" | |
for (string, attributes) in source.attributeRuns { | |
let escapedString = CFXMLCreateStringByEscapingEntities(nil, string, nil) as String | |
let el = NSXMLElement() | |
el.addChild(NSXMLNode.textWithStringValue(string) as! NSXMLNode) | |
if let link = attributes[NSLinkAttributeName] as? NSURL { | |
el.name = "a" | |
el.addAttribute(NSXMLNode.attributeWithName("href", stringValue: link.absoluteString) as! NSXMLNode) | |
} | |
else if let link = attributes[NSLinkAttributeName] as? String { | |
el.name = "a" | |
el.addAttribute(NSXMLNode.attributeWithName("href", stringValue: link) as! NSXMLNode) | |
} | |
else { | |
el.name = "span" | |
} | |
if let color = attributes[NSForegroundColorAttributeName] as? NSColor { | |
let className = styleNames.getOrInsertValueForKey(color) { | |
let hex = $0.hexRepresentation | |
let name = "c-"+hex | |
styleString += ".\(name) { color: #\(hex); }\n" | |
return name | |
} | |
el.addAttribute(NSXMLNode.attributeWithName("class", stringValue: className) as! NSXMLNode) | |
} | |
contentString += el.XMLString | |
} | |
styleString += "</style>" | |
contentString += "</code></pre>" | |
print(styleString) | |
print("\n\n") | |
print(contentString) | |
} | |
else { | |
print("no RTF on the pasteboard") | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment