aboutsummaryrefslogtreecommitdiffstats
path: root/Source/NoodleLineNumberView.m
diff options
context:
space:
mode:
Diffstat (limited to 'Source/NoodleLineNumberView.m')
-rw-r--r--Source/NoodleLineNumberView.m84
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;