Search code examples
objective-cmacosnstextviewundo-redo

How to implement undo with NSTextview


I want to implement undo action after replacing portion of text in an NSTextView. I am replacing portion of text with following code

- (void)omeAction
{
    NSString *fullString = [self.textView string];
    NSRange selectedRange = [self.textView selectedRange];
    NSString *selectedString = [fullString substringWithRange:selectedRange];

    NSString *stringToReplace = ...;
    [[self.textView textStorage] beginEditing];
    [[self.textView  textStorage] replaceCharactersInRange:selectedRange withString:stringToReplace];
    [[self.textView textStorage] endEditing];
}

While performing undo I couldn't really undo the text replacement


Solution

  • From Cocoa Text Architecture Guide: Text Editing – Text Change Notifications and Delegate Messages:

    In actually making changes to the text, you must ensure that the changes are properly performed and recorded by different parts of the text system. You do this by bracketing each batch of potential changes with shouldChangeTextInRange:replacementString: and didChangeText messages. These methods ensure that the appropriate delegate messages are sent and notifications posted. …

    In my experience, that includes generating the relevant undo operation.

    So, you would do:

    if ([self.textView shouldChangeTextInRange:selectedRange replacementString:stringToReplace])
    {
        [[self.textView textStorage] beginEditing];
        [[self.textView textStorage] replaceCharactersInRange:selectedRange withString:stringToReplace];
        [[self.textView textStorage] endEditing];
        [self.textView didChangeText];
    }