NSTextStorage Syntax Markdown

690 Views Asked by At

I'm writing a syntax markdown for iOS/osx.

It's a subclass of NSTextStorage. It works great in iOS but in OSX (after converting the code, UIColor to NSColor and UIFont to NSFont) it does work very well. It works great if I write at the end of current line but if I change caret position to middle of text, just after typing 1 letter, it changes caret position to end of line. This just happens in OSX because in IOS it works great.

I know the problem is located in - (void)setAttributes:(NSDictionary *)attrs range:(NSRange)range but don't know how to fix it... any help ?

- (NSString *)string {
    return [_backingStore string];
}

- (NSDictionary *)attributesAtIndex:(NSUInteger)location effectiveRange:(NSRangePointer)range {
    return [_backingStore attributesAtIndex:location effectiveRange:range];
}

- (void)replaceCharactersInRange:(NSRange)range withString:(NSString*)str {

    [self beginEditing];
    [_backingStore replaceCharactersInRange:range withString:str];
    [self edited:NSTextStorageEditedCharacters | NSTextStorageEditedAttributes range:range changeInLength:str.length - range.length];
    [self endEditing];

}

- (void)setAttributes:(NSDictionary *)attrs range:(NSRange)range {

    [self beginEditing];
    [_backingStore setAttributes:attrs range:range];
    [self edited:NSTextStorageEditedAttributes range:range changeInLength:0];
    [self endEditing];

}

- (void)processEditing {

    [self performReplacementsForRange:[self editedRange]];
    [super processEditing];
}

- (void)performReplacementsForRange:(NSRange)changedRange {

    NSString* backingString = [_backingStore string];
    NSRange extendedRange = extendedRange = NSUnionRange(changedRange, [backingString lineRangeForRange:NSMakeRange(NSMaxRange(changedRange), 0)]);
    [self applyStylesToRange:extendedRange];
}

- (void)applyStylesToRange:(NSRange)searchRange {

    NSDictionary* attributeDictionary = self.attributeDictionary;
    NSString* backingString = [_backingStore string];
    NSDictionary* bodyAttributes  = self.bodyAttributes;
    [self setAttributes:bodyAttributes range:searchRange];
    [attributeDictionary enumerateKeysAndObjectsUsingBlock:^(NSRegularExpression* regex, NSDictionary* attributes, BOOL* stop) {
        [regex enumerateMatchesInString:backingString options:0 range:searchRange
                             usingBlock:^(NSTextCheckingResult *match, NSMatchingFlags flags, BOOL *stop) {
                                 NSRange matchRange = [match rangeAtIndex:1];
                                 [self addAttributes:attributes range:matchRange];
                             }];
    }];

}
1

There are 1 best solutions below

5
On

I'm not familiar with NSTextStorage but I managed to fix this by overriding fixAttributesInRange: instead of processEditing.

Instead of

- (void)processEditing {

    [self performReplacementsForRange:[self editedRange]];
    [super processEditing];
}

do

- (void)fixAttributesInRange:(NSRange)range {
    [self performReplacementsForRange:range];
    [super fixAttributesInRange:(NSRange)range];
}

Btw: shouldn't applyStylesToRange be nested between beginEditing and endEditing?