TextViewPlus
Make life better with NSTextView+TextKit 1/2
Install / Use
/learn @ChimeHQ/TextViewPlusREADME
TextViewPlus
This project aims to make it easier to use NSTextView. It was originally built to support TextKit 1. But, now a major goal is to support TextKit 2.
Integration
dependencies: [
.package(url: "https://github.com/ChimeHQ/TextViewPlus")
],
targets: [
.target(
name: "UseCoreFunctionality",
dependencies: ["TextViewPlus"]
),
.target(
name: "UseBaseTextView",
dependencies: [.product(name: "BaseTextView", package: "TextViewPlus")]
),
]
BaseTextView
This is an TextKit 2-only NSTextView subclass that aims for an absolute minimal amount of changes. Things are allowed only if they are required for correct functionality. It is intended to be a drop-in replacement for NSTextView, and should maintain compatibilty with existing subclasses. Behaviors are appropriate for all types of text.
- Disables all support for TextKit 1
- Workaround for
scrollRangeToVisiblebug (FB13100459) - Minimum
textContainerInsetenforcement to address morescrollRangeToVisiblebugs - Additional routing to
NSTextViewDelegate.textView(_:, doCommandBy:) -> Bool:paste,pasteAsRichText,pasteAsPlainText - Hooks for
onKeyDown,onFlagsChanged,onMouseDown - Configurable selection notifcation delivery via
continuousSelectionNotifications
NSTextView Extensions
Ranges
Handy methods for computing ranges of text within the view.
func textRange(for rect: NSRect) -> NSRange
var visibleTextRange: NSRange
Selection
Convenience methods for computing selection ranges/locations.
var selectedTextRanges: [NSRange]
var selectedContinuousRange: NSRange?
var insertionLocation: Int?
Style
Styling changes can be very expensive, this method is much faster in certain common cases.
func updateFont(_ newFont: NSFont, color newColor: NSColor)
Bounding
Computing bounding rectangles of displayed text.
func boundingRect(for range: NSRange) -> NSRect?
func boundingRect(forGlyphRange range: NSRange) -> NSRect?
func boundingSelectionRects(forRange range: NSRange) -> [NSRect]
Attributed Strings
Programmatic modification of the underlying attributed string in the NSTextStorage, with support for delegate callbacks and undo.
func replaceCharacters(in range: NSRange, with attributedString: NSAttributedString)
// with undo supported
func replaceString(in range: NSRange, with attributedString: NSAttributedString)
Behavior
Changing NSTextView behaviors can be tricky, and often involve complex interactions with the whole system (NSLayoutManager, NSTextContainer, NSScrollView, etc).
public var wrapsTextToHorizontalBounds: Bool
TextKit 2 Features
Workarounds
In versions of macOS before 13, TextKit 2 doesn't correctly apply rendering attributes. You can sub in this NSTextLayoutFragment to workaround the issue.
extension YourClass: NSTextLayoutManagerDelegate {
func textLayoutManager(_ textLayoutManager: NSTextLayoutManager, textLayoutFragmentFor location: NSTextLocation, in textElement: NSTextElement) -> NSTextLayoutFragment {
let range = textElement.elementRange
switch textElement {
case let paragraph as NSTextParagraph:
return ParagraphRenderingAttributeTextLayoutFragment(textParagraph: paragraph, range: range)
default:
return NSTextLayoutFragment(textElement: textElement, range: range)
}
}
}
TextKit 1 Features
NSLayoutManager extensions
func enumerateLineFragments(for range: NSRange, block: (NSRect, NSRange) -> Void)
func enumerateLineFragments(for rect: NSRect, block: (NSRect, NSRange) -> Void)
Contributing and Collaboration
I'd love to hear from you! Get in touch via an issue or pull request.
I prefer collaboration, and would love to find ways to work together if you have a similar project.
I prefer indentation with tabs for improved accessibility. But, I'd rather you use the system you want and make a PR than hesitate because of whitespace.
By participating in this project you agree to abide by the Contributor Code of Conduct.
Related Skills
node-connect
344.1kDiagnose OpenClaw node connection and pairing failures for Android, iOS, and macOS companion apps
frontend-design
96.8kCreate distinctive, production-grade frontend interfaces with high design quality. Use this skill when the user asks to build web components, pages, or applications. Generates creative, polished code that avoids generic AI aesthetics.
openai-whisper-api
344.1kTranscribe audio via OpenAI Audio Transcriptions API (Whisper).
qqbot-media
344.1kQQBot 富媒体收发能力。使用 <qqmedia> 标签,系统根据文件扩展名自动识别类型(图片/语音/视频/文件)。
