Skip to content

Instantly share code, notes, and snippets.

@jtbandes
Last active August 12, 2018 21:35
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save jtbandes/0ecc47a7555bcffe9cd2 to your computer and use it in GitHub Desktop.
Save jtbandes/0ecc47a7555bcffe9cd2 to your computer and use it in GitHub Desktop.
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