Last active
February 7, 2023 07:14
-
-
Save mminer/597c1b2c40adcf3c319f7feeade62ed4 to your computer and use it in GitHub Desktop.
NSTextView subclass that displays and opens hyperlinks.
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
// You don't necessarily need this subclass if your NSTextView is selectable. | |
// If it isn't though, this allows you to have an uneditable, unselectable label where links work as expected. | |
import AppKit | |
class HyperlinkTextView: NSTextView { | |
override func mouseDown(with event: NSEvent) { | |
super.mouseDown(with: event) | |
openClickedHyperlink(with: event) | |
} | |
override func resetCursorRects() { | |
super.resetCursorRects() | |
addHyperlinkCursorRects() | |
} | |
/// Displays a hand cursor when a link is hovered over. | |
private func addHyperlinkCursorRects() { | |
guard let layoutManager = layoutManager, let textContainer = textContainer else { | |
return | |
} | |
let attributedStringValue = attributedString() | |
let range = NSRange(location: 0, length: attributedStringValue.length) | |
attributedStringValue.enumerateAttribute(.link, in: range) { value, range, _ in | |
guard value != nil else { | |
return | |
} | |
let rect = layoutManager.boundingRect(forGlyphRange: range, in: textContainer) | |
addCursorRect(rect, cursor: .pointingHand) | |
} | |
} | |
/// Opens links when clicked. | |
private func openClickedHyperlink(with event: NSEvent) { | |
let attributedStringValue = attributedString() | |
let point = convert(event.locationInWindow, from: nil) | |
let characterIndex = characterIndexForInsertion(at: point) | |
guard characterIndex < attributedStringValue.length else { | |
return | |
} | |
let attributes = attributedStringValue.attributes(at: characterIndex, effectiveRange: nil) | |
guard let urlString = attributes[.link] as? String, let url = URL(string: urlString) else { | |
return | |
} | |
NSWorkspace.shared.open(url) | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment