TextViewPlus
Make life better with NSTextView+TextKit 1/2
[![Build Status][build status badge]][build status] [![Platforms][platforms badge]][platforms] The project is written primarily in Swift, distributed under the BSD 3-Clause "New" or "Revised" License license, first published in 2020. Key topics include: appkit, cocoa, macos, nstextview, swift.
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
swiftdependencies: [ .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.
swiftfunc textRange(for rect: NSRect) -> NSRange var visibleTextRange: NSRange
Selection
Convenience methods for computing selection ranges/locations.
swiftvar selectedTextRanges: [NSRange] var selectedContinuousRange: NSRange? var insertionLocation: Int?
Style
Styling changes can be very expensive, this method is much faster in certain common cases.
swiftfunc updateFont(_ newFont: NSFont, color newColor: NSColor)
Bounding
Computing bounding rectangles of displayed text.
swiftfunc 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.
swiftfunc 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).
swiftpublic 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.
swiftextension 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
swiftfunc 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.
Contributors
Showing top 2 contributors by commit count.
