2

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];
                             }];
    }];

}
  • Possible duplicate of [Modifying NSTextStorage causes insertion point to move to the end of the line](https://stackoverflow.com/questions/12151360/modifying-nstextstorage-causes-insertion-point-to-move-to-the-end-of-the-line) – ctietze Nov 30 '17 at 09:10

1 Answers1

-1

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?

Willeke
  • 14,578
  • 4
  • 19
  • 47
  • Hi, the applyStylesToRange nested between beginEditing and endEditing does not makes any different. How did you override fixAttributesInRange ? Can you share your solution ? Thanks –  Feb 22 '16 at 10:02
  • Changes between beginEditing and endEditing are buffered and processed in one go. – Willeke Feb 22 '16 at 12:44
  • Thanks, but it only solves for roman characters. If I have another keyboard scheme loaded like Japanese, it keeps replacing the same letter and does not move the cursor forward after i type a character... weird stuff... –  Feb 22 '16 at 12:49
  • I don't think Japanese characters are visible in Helvetica Neue. Call `[_backingStore fixAttributesInRange:searchRange]` at the end of `applyStylesToRange:`. – Willeke Feb 22 '16 at 16:41
  • See ["Modifying NSTextStorage causes insertion point to move to the end of the line"](https://stackoverflow.com/questions/12151360/modifying-nstextstorage-causes-insertion-point-to-move-to-the-end-of-the-line?noredirect=1&lq=1) and my answer there, this quick-fix is not necessary (and may cause additional trouble because your highlights are now exempt from attribute fixing) – ctietze Nov 30 '17 at 09:12