NSTextStorageDelegate textStorage (_, willProcessEditing :, range :, changeInLength :) moves the selection

I'm trying to implement a text syntax editor that also does things like inserting a space at the beginning of a new line for you or replacing text with text attachments.

After re-viewing the documents after the previous implementation had problems with cancellation, it seems that the recommended bottleneck for this is the NSTextStorageDelegate textStorage (_, willProcessEditing :, range :, changeInLength :) method (which claims Delegates can change the characters or attributes. whereas didProcessEditing says that I can only change attributes). This works great, except that whenever I actually change attributes or text, the text entry label moves to the end of any range of text that I change (so if I change the style of the entire line, the cursor goes to the end of the line )

Does anyone know what extra calls I'm missing, what does NSTextStorage / NSTextView say so as not to damage the insert label? Also, as soon as I insert the text, I may have to tell him to move the input label to the account for the text I entered.

Note: I saw Changing NSTextStorage causes the insertion point to go to the end of the line , but this assumes that I am subclassing NSTextStorage, so I cannot use the solution there (and rather, I will not subclass NSTextStorage, since it is a semi-abstract subclass, and I would lose some Apple class behavior if I subclassed it).

+2
source share
1 answer

I figured out the source of the problem.

And the only solution that will work reliably based on reasons inherent in the Cocoa framework, and not just workarounds. (Note that there is probably at least one more metastable approach based on a ton of quick fixes that gives a similar result, but as the metastable alternatives go, it will be very fragile and require a lot of effort to maintain .)

  • TL; DR Problem: NSTextStorage collects edited calls and merges ranges, starting with user-modified changes (such as inserts), and then adding all ranges from addAttributes(_:range:) calls during allocation.

  • TL; DR Solution: select only with textDidChange(_:) .

More details

What happens when entering and changing a style

This applies only to one run of processEditing() , both in subclasses of NSTextStorage and in NSTextStorageDelegate callbacks.

The only safe way to do the selection I found is to connect to NSText.didChangeNotification or implement NSTextDelegate.textDidChange(_:) .

According to @Willeke's comments on the OP question, this is the best place to make changes after going through the layout. But unlike the comment stream, setting NSText.selectedRange not enough. You will not notice a problem after fixing the selection after the carriage has left, until

  • you select entire blocks of text,
  • spanning multiple lines, and
  • NSClipView visible ( NSClipView ) scroll borders.

In this rare case, most keystrokes will make the view scroll, swaying or not bouncing. But there are no additional quick fixes. I've tried. Not to prevent scrolling commands from being sent from a private API to NSLayoutManager and to avoid scrolling by overriding all methods by scrolling into them from a subclass of NSTextView works well. You can completely stop scrolling to the insertion point, but you will not be able to get a robust algorithm that does not scroll only when performing the selection.

The didChangeNotification approach works reliably in all situations in which my application testers and I could come up with (including a crash situation, as strange as scrolling text, and then during the animation, replacing the line with something shorter - - Yes, try to understand what material is from crash logs that report incorrect character generation ...).

This approach works because it performs 2 character generations:

  • One pass for the edited range, in the case of entering for each keystroke with an NSRange length 1, sending an edited notification using [.editedCharacters, .editedAttributes] , the first of which is responsible for moving the carriage;
  • another pass for any range affects syntax highlighting by sending an edited notification only with [.editedAttributes] , without affecting the caret position at all.

More detailed information

If you want to know more about the source of the problem, I will provide more of my research, various approaches, and solution details in a much longer blog for reference. This, however, is the solution itself. http://christiantietze.de/posts/2017/11/syntax-highlight-nstextstorage-insertion-point-change/

0
source

All Articles