iosswiftmacos

Awkward behaviour of Auto-Correction with NSTextViews


I have an app running on Mac and iOS. Part of the app offers live collaborative editing of various objects. I'm using Yata as the edit synchronisation system.

Every object on the screen (lines, shapes, embedded documents, every character in textViews) carry a YataID that allows me to deterministically merge many concurrent, conflicting, overlapping changes.

This all works. But AutoCorrect is throwing a spanner in the works.

First - a little background on text insertion: When some text is inserted into TextViews (iOS and Mac), it uses the attributes stored in the variable TypingAttributes and applies them to the new text. These attributes contain fonts, spacing, styles and any other values. I ensure that TypingAttributes never carries any YataIDs so that there is never any confusion about what is new text. Then after any insertion event is complete (paste, typing, auto-correct), I use the NSTextStorageDelegate function WillProcessEditing to look at the changes and identify what has been added or deleted, assign new YataIDs to those new characters, and then create Yata operations (distributed to other endpoints) to represent those changes.

In the background, I am also merging changes from remote endpoints into this endpoint.

Autocorrect screws this up royally sometimes.

First - a normal auto-correct:

To ensure the styles of the new text matches the old text, autocorrect copies the attributes from "c" and applies them to "ollect", including custom attributes. Which means that the YataID of "c" is duplicated in "ollect". Fortunately this is easy to detect as YataIDs are unique.

However where it gets difficult is where autocorrect needs to replace the first character.

So now in WillProcessEditing, I'm looking at the text, and "c" has a proper YataID, and "yst" as duplicate attributes and YataID. I can tell that the "yst" has been replaced, but I cannot tell that the "s" has been replaced with "c" unless I refer back to the Yata backing store.

I seems I have two options:

I'm looking to see if anyone else has experience with autocorrect and custom attributes. Is there an alternative approach here?

Thank you for your time.

Paul


Solution

  • It looks like {NS,UI}TextVIew's implementation of auto-correct does indeed copy custom attributes, so I've implemented option (a) above - a complete check of the incoming text against the Yata backing store. This is the only way forward I can see. I've coded it up and it works.

    One wrinkle is that I have to start the check one character before WillProcessEditing's editingRange because that previous character's attributes (and YataID) might have been copied when inserting the first character.

    A further wrinkle is that when changes happen to NSTextStorage, the textview sometimes moves the cursor. But it does this well after {Will,Did}ProcessEditing. Discussion and various solutions are available here, however one that works for me is to do processing in WillProcessEditing (I must do that because I might need to change the TextStorage), remember the cursor position I want, and then apply the cursor position in the TextDidChange delegate function which appears to execute very late in the various text change delegates.