xcpaste — copy formatted code as HTML/CSS
// 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