diff options
Diffstat (limited to 'Source/NoodleLineNumberView.m')
-rw-r--r-- | Source/NoodleLineNumberView.m | 84 |
1 files changed, 44 insertions, 40 deletions
diff --git a/Source/NoodleLineNumberView.m b/Source/NoodleLineNumberView.m index 0213c151..193c9ada 100644 --- a/Source/NoodleLineNumberView.m +++ b/Source/NoodleLineNumberView.m @@ -80,7 +80,9 @@ typedef NSRange (*RangeOfLineIMP)(id object, SEL selector, NSRange range); [self font], NSFontAttributeName, [self textColor], NSForegroundColorAttributeName, nil] retain]; - maxWidthOfGlyph = [[NSString stringWithString:@"8"] sizeWithAttributes:textAttributes].width; + NSSize s = [[NSString stringWithString:@"8"] sizeWithAttributes:textAttributes]; + maxWidthOfGlyph = s.width; + maxHeightOfGlyph = s.height; [self updateGutterThicknessConstants]; currentRuleThickness = 0.0f; @@ -91,7 +93,10 @@ typedef NSRange (*RangeOfLineIMP)(id object, SEL selector, NSRange range); addObjectSel = @selector(addObject:); numberWithUnsignedIntegerSel = @selector(numberWithUnsignedInteger:); numberWithUnsignedIntegerIMP = [NSNumber methodForSelector:numberWithUnsignedIntegerSel]; + rangeOfLineSel = @selector(getLineStart:end:contentsEnd:forRange:); + currentNumberOfLines = 1; + numberClass = [NSNumber class]; } @@ -127,7 +132,9 @@ typedef NSRange (*RangeOfLineIMP)(id object, SEL selector, NSRange range); font, NSFontAttributeName, [self textColor], NSForegroundColorAttributeName, nil] retain]; - maxWidthOfGlyph = [[NSString stringWithString:@"8"] sizeWithAttributes:textAttributes].width; + NSSize s = [[NSString stringWithString:@"8"] sizeWithAttributes:textAttributes]; + maxWidthOfGlyph = s.width; + maxHeightOfGlyph = s.height; [self updateGutterThicknessConstants]; } } @@ -151,7 +158,9 @@ typedef NSRange (*RangeOfLineIMP)(id object, SEL selector, NSRange range); [self font], NSFontAttributeName, textColor, NSForegroundColorAttributeName, nil] retain]; - maxWidthOfGlyph = [[NSString stringWithString:@"8"] sizeWithAttributes:textAttributes].width; + NSSize s = [[NSString stringWithString:@"8"] sizeWithAttributes:textAttributes]; + maxWidthOfGlyph = s.width; + maxHeightOfGlyph = s.height; [self updateGutterThicknessConstants]; } } @@ -177,8 +186,9 @@ typedef NSRange (*RangeOfLineIMP)(id object, SEL selector, NSRange range); { layoutManager = [(NSTextView*)aView layoutManager]; container = [(NSTextView*)aView textContainer]; + clientView = (NSTextView*)[self clientView]; - [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(textDidChange:) name:NSTextStorageDidProcessEditingNotification object:[(NSTextView *)aView textStorage]]; + [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(textDidChange:) name:NSTextStorageDidProcessEditingNotification object:[clientView textStorage]]; [self invalidateLineIndices]; } @@ -189,16 +199,14 @@ typedef NSRange (*RangeOfLineIMP)(id object, SEL selector, NSRange range); - (void)textDidChange:(NSNotification *)notification { - if(![self clientView]) return; - - NSUInteger editMask = [[(NSTextView *)[self clientView] textStorage] editedMask]; + if(!clientView) return; // Invalidate the line indices only if text view was changed in length but not if the font was changed. // They will be recalculated and recached on demand. - if(editMask != 1) + if([[clientView textStorage] editedMask] != 1) [self invalidateLineIndices]; - [self setNeedsDisplay:YES]; + [self setNeedsDisplayInRect:[self bounds]]; } @@ -279,7 +287,7 @@ typedef NSRange (*RangeOfLineIMP)(id object, SEL selector, NSRange range); - (void)drawHashMarksAndLabelsInRect:(NSRect)aRect { - id view; + NSRect bounds; bounds = [self bounds]; @@ -293,9 +301,7 @@ typedef NSRange (*RangeOfLineIMP)(id object, SEL selector, NSRange range); // [NSBezierPath strokeLineFromPoint:NSMakePoint(NSMaxX(bounds) - 0.5, NSMinY(bounds)) toPoint:NSMakePoint(NSMaxX(bounds) - 0.5, NSMaxY(bounds))]; // } - view = [self clientView]; - - if ([view isKindOfClass:[NSTextView class]]) + if ([clientView isKindOfClass:[NSTextView class]]) { NSRect visibleRect; NSRange range, nullRange; @@ -303,15 +309,17 @@ typedef NSRange (*RangeOfLineIMP)(id object, SEL selector, NSRange range); NSUInteger rectCount, lineIndex, line, count; NSRectArray rects; CGFloat yinset; - NSSize stringSize; NSArray *lines; nullRange = NSMakeRange(NSNotFound, 0); - yinset = [view textContainerInset].height; + yinset = [clientView textContainerInset].height; visibleRect = [[[self scrollView] contentView] bounds]; lines = [self lineIndices]; + count = [lines count]; + + if(!count) return; // Find the characters that are currently visible range = [layoutManager characterRangeForGlyphRange:[layoutManager glyphRangeForBoundingRect:visibleRect inTextContainer:container] actualGlyphRange:NULL]; @@ -320,14 +328,11 @@ typedef NSRange (*RangeOfLineIMP)(id object, SEL selector, NSRange range); // It doesn't show up in the glyphs so would not be accounted for. range.length++; - count = [lines count]; - CGFloat boundsRULERMargin2 = NSWidth(bounds) - RULER_MARGIN2; CGFloat boundsWidthRULER = NSWidth(bounds) - RULER_MARGIN; CGFloat yinsetMinY = yinset - NSMinY(visibleRect); CGFloat rectHeight; - for (line = (NSUInteger)(*lineNumberForCharacterIndexIMP)(self, lineNumberForCharacterIndexSel, range.location); line < count; line++) { lineIndex = [NSArrayObjectAtIndex(lines, line) unsignedIntegerValue]; @@ -347,13 +352,16 @@ typedef NSRange (*RangeOfLineIMP)(id object, SEL selector, NSRange range); // Line numbers are internally stored starting at 0 labelText = [NSString stringWithFormat:@"%lu", (NSUInteger)(line + 1)]; - stringSize = [labelText sizeWithAttributes:textAttributes]; + // How many digits has the current line number? + NSUInteger idx = line + 1; + NSInteger numOfDigits = 0; + while(idx) { numOfDigits++; idx/=10; } rectHeight = NSHeight(rects[0]); // Draw string flush right, centered vertically within the line [labelText drawInRect: - NSMakeRect(boundsWidthRULER - stringSize.width, - yinsetMinY + NSMinY(rects[0]) + ((NSInteger)(rectHeight - stringSize.height) >> 1), + NSMakeRect(boundsWidthRULER - (maxWidthOfGlyph * numOfDigits), + yinsetMinY + NSMinY(rects[0]) + ((NSInteger)(rectHeight - maxHeightOfGlyph) >> 1), boundsRULERMargin2, rectHeight) withAttributes:textAttributes]; } @@ -494,51 +502,45 @@ typedef NSRange (*RangeOfLineIMP)(id object, SEL selector, NSRange range); - (void)calculateLines { - id view = [self clientView]; - if ([view isKindOfClass:[NSTextView class]]) + if ([clientView isKindOfClass:[NSTextView class]]) { - NSUInteger anIndex, stringLength, lineEnd, contentEnd, lastLine; + NSUInteger anIndex, stringLength, lineEnd, contentEnd; NSString *textString; CGFloat newThickness; - textString = [view string]; + textString = [clientView string]; stringLength = [textString length]; - // Switch off line numbering if text larger than 6MB + // Switch off line numbering if text larger than 3MB // for performance reasons. // TODO improve performance maybe via threading - if(stringLength>6000000) + if(stringLength>3000000) return; - if (lineIndices) [lineIndices release], lineIndices = nil; - // Init lineIndices with text length / 16 + 1 - lineIndices = [[NSMutableArray alloc] initWithCapacity:((NSUInteger)stringLength>>4)+1]; + lineIndices = [[NSMutableArray alloc] initWithCapacity:currentNumberOfLines]; anIndex = 0; // Cache loop methods for speed - RangeOfLineIMP rangeOfLineIMP = (RangeOfLineIMP)[textString methodForSelector:lineRangeForRangeSel]; + IMP rangeOfLineIMP = [textString methodForSelector:rangeOfLineSel]; addObjectIMP = [lineIndices methodForSelector:addObjectSel]; do { - (void)(*addObjectIMP)(lineIndices, addObjectSel, (*numberWithUnsignedIntegerIMP)([NSNumber class], numberWithUnsignedIntegerSel, anIndex)); - lastLine = anIndex; - anIndex = NSMaxRange((*rangeOfLineIMP)(textString, lineRangeForRangeSel, NSMakeRange(anIndex, 0))); + (void)(*addObjectIMP)(lineIndices, addObjectSel, (*numberWithUnsignedIntegerIMP)(numberClass, numberWithUnsignedIntegerSel, anIndex)); + (*rangeOfLineIMP)(textString, rangeOfLineSel, NULL, &anIndex, NULL, NSMakeRange(anIndex, 0)); } while (anIndex < stringLength); // Check if text ends with a new line. - [textString getLineStart:NULL end:&lineEnd contentsEnd:&contentEnd forRange:NSMakeRange(lastLine, 0)]; + (*rangeOfLineIMP)(textString, rangeOfLineSel, NULL, &lineEnd, &contentEnd, NSMakeRange([[lineIndices lastObject] unsignedIntValue], 0)); if (contentEnd < lineEnd) - (void)(*addObjectIMP)(lineIndices, addObjectSel, (*numberWithUnsignedIntegerIMP)([NSNumber class], numberWithUnsignedIntegerSel, anIndex)); + (void)(*addObjectIMP)(lineIndices, addObjectSel, (*numberWithUnsignedIntegerIMP)(numberClass, numberWithUnsignedIntegerSel, anIndex)); NSUInteger lineCount = [lineIndices count]; - if(lineCount < 10) - newThickness = maxWidthOfGlyph1; - else if(lineCount < 100) + if(lineCount < 100) newThickness = maxWidthOfGlyph2; else if(lineCount < 1000) newThickness = maxWidthOfGlyph3; @@ -555,7 +557,9 @@ typedef NSRange (*RangeOfLineIMP)(id object, SEL selector, NSRange range); else newThickness = 100; - if (fabs(currentRuleThickness - newThickness) > 1) + currentNumberOfLines = lineCount; + + if (currentRuleThickness != newThickness) { currentRuleThickness = newThickness; |