NSTextField usesSingleLineMode Stops Working When You Implement NSTextViewDelegate Methods

Today I learned why my NSTextField permits pasting of newline characters even though I set usesSingleLineMode properly. It's because I made it conform to NSTextViewDelegate to cache changes. When you edit text inside of an NSTextField, you actually type inside a field editor of the window. That's a shared NSTextView instance. Most of the hard work of an NSTextField is done by its cell, which is an NSTextCell. NSTextCells implement at least the delegate method NSTextViewDelegate.textView(_:shouldChangeTextIn:replacementText:) – and when you set usesSingleLineMode, this is actually set for the cell, not the view itself. You can use textView(_:shouldChangeTextIn:replacementText:) to sanitize input text, and I suspect that's where the usesSingleLineMode implementation happens. If your NSTextField subclass implements this method, the NSTextCell implementation isn't called. And since that one isn't public (it was called "implicit protocol conformance" back in the day), you cannot delegate up in Swift because the compiler knows it isn't there.

Continue reading …

RxSwift: Typing/Idle Event Stream for NSTextView

To improve my note editing app The Archive's responsiveness, I want to find out when the user is actively editing a note. Here's how to create the idle switch in RxSwift/RxCocoa. A simple enum of .typing and .idle will do for a start. Of course, NSTextViewDelegate provides a textDidChange(_:) callback to hook into; it's based on a notification, so you can also subscribe to the NSText.didChangeNotification directly if you don't want to use a delegate. That's the input signal I'm going to use.

Continue reading …

NSTextView's Default Insertion Point and Selected Text Colors

Teaser image

NSTextView can be customized to display different colors for the insertion point (aka caret, aka text cursor) and for selected text. This is especially useful when you add themes to your editor and the default settings don't fit anymore. The default values are not exposed anywhere, so I had to log them and reconstruct convenient accessors to reset a text view if needed:

Continue reading …

NSTextView: When Did the Find Bar Disappear?

For whatever reason, my current app project's find bar does not make the text view firstResponder again when you hit Escape or click the "Done" button to close it. This is very uncomfortable for users: they type away, hit ⌘F to find a phrase, then hit Esc – and now they're in limbo. To my astonishment, the NSTextFinderAction called hideFindInterface is not triggered when you make the find bar disappear. Its opposite, showFindInterface, is triggered when the find bar slides back in, though. Intercepting in NSTextView.performTextFinderAction(_:) does not help, then.

Continue reading …

Why the Selection Changes When You Do Syntax Highlighting in a NSTextView and What You Can Do About It

Teaser image

On iOS, this does maybe not happen at all, but when you want to write syntax highlighting code for macOS apps, copying together stuff from around the web, you'll end up with broken application behavior. In short: when you type and the attributes of the line change, the insertion point is moved to the end of the line. That sucks.

Continue reading …