aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBibiko <bibiko@eva.mpg.de>2010-02-01 23:07:24 +0000
committerBibiko <bibiko@eva.mpg.de>2010-02-01 23:07:24 +0000
commitab560b63b13d9e74e3f1082287dcefe04322cdba (patch)
treebb0743612c817589a2549ba4efc9e3c4db3f7acf
parent502ccf54c641fcbdda80abf0ed4af243d70e475a (diff)
downloadsequelpro-ab560b63b13d9e74e3f1082287dcefe04322cdba.tar.gz
sequelpro-ab560b63b13d9e74e3f1082287dcefe04322cdba.tar.bz2
sequelpro-ab560b63b13d9e74e3f1082287dcefe04322cdba.zip
• sped up Query Editor for larger text
- rewrote [NoodleLineNumber requiredThickness] completely to avoid stack overflow for larger text due to [NSMutableString string] plus appendString all the time without releasing it in time
-rw-r--r--Source/CMTextView.h8
-rw-r--r--Source/CMTextView.m45
-rw-r--r--Source/NoodleLineNumberView.m179
3 files changed, 123 insertions, 109 deletions
diff --git a/Source/CMTextView.h b/Source/CMTextView.h
index ea0b36cc..a7c0ccea 100644
--- a/Source/CMTextView.h
+++ b/Source/CMTextView.h
@@ -38,6 +38,13 @@ static inline void NSMutableAttributedStringAddAttributeValueRange (NSMutableAtt
SPMutableAttributedStringAddAttributeValueRange(self, @selector(addAttribute:value:range:), aStr, aValue, aRange);
return;
}
+static inline id NSMutableAttributedStringAttributeAtIndex (NSMutableAttributedString* self, NSString* aStr, NSUInteger index, NSRangePointer range) {
+ typedef id (*SPMutableAttributedStringAttributeAtIndexMethodPtr)(NSMutableAttributedString*, SEL, NSString*, NSUInteger, NSRangePointer);
+ static SPMutableAttributedStringAttributeAtIndexMethodPtr SPMutableAttributedStringAttributeAtIndex;
+ if (!SPMutableAttributedStringAttributeAtIndex) SPMutableAttributedStringAttributeAtIndex = (SPMutableAttributedStringAttributeAtIndexMethodPtr)[self methodForSelector:@selector(attribute:atIndex:effectiveRange:)];
+ id r = SPMutableAttributedStringAttributeAtIndex(self, @selector(attribute:atIndex:effectiveRange:), aStr, index, range);
+ return r;
+}
@interface CMTextView : NSTextView {
BOOL autoindentEnabled;
@@ -49,6 +56,7 @@ static inline void NSMutableAttributedStringAddAttributeValueRange (NSMutableAtt
NoodleLineNumberView *lineNumberView;
BOOL startListeningToBoundChanges;
+ BOOL textBufferSizeIncreased;
NSString *showMySQLHelpFor;
diff --git a/Source/CMTextView.m b/Source/CMTextView.m
index 5ba0f3e9..f7b1663f 100644
--- a/Source/CMTextView.m
+++ b/Source/CMTextView.m
@@ -52,10 +52,10 @@ YY_BUFFER_STATE yy_scan_string (const char *);
#define kAPval @"linked"
#define kLEXToken @"Quoted" // set via lex to indicate a quoted string
#define kLEXTokenValue @"isMarked"
-#define kSQLkeyword @"SQLkw" // attribute for found SQL keywords
+#define kSQLkeyword @"s" // attribute for found SQL keywords
#define kQuote @"Quote"
#define kQuoteValue @"isQuoted"
-#define kValue @"dummy"
+#define kValue @"x"
#define kBTQuote @"BTQuote"
#define kBTQuoteValue @"isBTQuoted"
@@ -117,6 +117,7 @@ NSInteger alphabeticSort(id string1, id string2, void *reverse)
autohelpEnabled = NO;
delBackwardsWasPressed = NO;
startListeningToBoundChanges = NO;
+ textBufferSizeIncreased = NO;
snippetControlCounter = -1;
lineNumberView = [[NoodleLineNumberView alloc] initWithScrollView:scrollView];
@@ -791,7 +792,7 @@ NSInteger alphabeticSort(id string1, id string2, void *reverse)
NSRange r = NSMakeRange(0, [[self string] length]);
// Remove all colors before printing for large text buffer
- if(r.length > SP_SYNTAX_HILITE_BIAS) {
+ if(r.length > SP_TEXT_SIZE_TRIGGER_FOR_PARTLY_PARSING) {
// Cancel all doSyntaxHighlighting requests
[NSObject cancelPreviousPerformRequestsWithTarget:self
selector:@selector(doSyntaxHighlighting)
@@ -2882,55 +2883,54 @@ NSInteger alphabeticSort(id string1, id string2, void *reverse)
// If the current token is marked as SQL keyword, uppercase it if required.
tokenEnd = tokenRange.location+tokenRange.length-1;
// Check the end of the token
- if (allowToCheckForUpperCase && autouppercaseKeywords && !delBackwardsWasPressed
- && [[textStore attribute:kSQLkeyword atIndex:tokenEnd effectiveRange:nil] isEqualToString:kValue])
+ if (textBufferSizeIncreased && allowToCheckForUpperCase && autouppercaseKeywords && !delBackwardsWasPressed
+ && [(NSString*)NSMutableAttributedStringAttributeAtIndex(textStore, kSQLkeyword, tokenEnd, nil) length])
// check if next char is not a kSQLkeyword or current kSQLkeyword is at the end;
// if so then upper case keyword if not already done
// @try catch() for catching valid index esp. after deleteBackward:
{
-
+
NSString* curTokenString = [selfstr substringWithRange:tokenRange];
- NSString* upperCaseCurTokenString = [curTokenString uppercaseString];
BOOL doIt = NO;
@try
{
- doIt = ![[textStore attribute:kSQLkeyword atIndex:tokenEnd+1 effectiveRange:nil] isEqualToString:kValue];
+ doIt = ![(NSString*)NSMutableAttributedStringAttributeAtIndex(textStore, kSQLkeyword,tokenEnd+1,nil) length];
} @catch(id ae) { doIt = NO; }
-
- if(doIt && ![upperCaseCurTokenString isEqualToString:curTokenString])
+
+ if(doIt)
{
// Register it for undo works only partly for now, at least the uppercased keyword will be selected
[self shouldChangeTextInRange:tokenRange replacementString:curTokenString];
- [self replaceCharactersInRange:tokenRange withString:upperCaseCurTokenString];
+ [self replaceCharactersInRange:tokenRange withString:[curTokenString uppercaseString]];
}
}
-
+
NSMutableAttributedStringAddAttributeValueRange(textStore, NSForegroundColorAttributeName, tokenColor, tokenRange);
-
+
if(!allowToCheckForUpperCase) continue;
-
+
// Add an attribute to be used in the auto-pairing (keyDown:)
// to disable auto-pairing if caret is inside of any token found by lex.
// For discussion: maybe change it later (only for quotes not keywords?)
if(token < 6)
NSMutableAttributedStringAddAttributeValueRange(textStore, kLEXToken, kLEXTokenValue, tokenRange);
-
+
// Mark each SQL keyword for auto-uppercasing and do it for the next textStorageDidProcessEditing: event.
// Performing it one token later allows words which start as reserved keywords to be entered.
if(token == SPT_RESERVED_WORD)
NSMutableAttributedStringAddAttributeValueRange(textStore, kSQLkeyword, kValue, tokenRange);
-
+
// Add an attribute to be used to distinguish quotes from keywords etc.
// used e.g. in completion suggestions
else if(token < 4)
NSMutableAttributedStringAddAttributeValueRange(textStore, kQuote, kQuoteValue, tokenRange);
-
+
//distinguish backtick quoted word for completion
else if(token == SPT_BACKTICK_QUOTED_TEXT)
NSMutableAttributedStringAddAttributeValueRange(textStore, kBTQuote, kBTQuoteValue, tokenRange);
}
-
+
}
- (void)drawRect:(NSRect)rect {
@@ -3236,9 +3236,16 @@ NSInteger alphabeticSort(id string1, id string2, void *reverse)
}
}
}
+ if([[self textStorage] changeInLength] > 0)
+ textBufferSizeIncreased = YES;
+ else
+ textBufferSizeIncreased = NO;
- [self doSyntaxHighlighting];
+ if([[self textStorage] changeInLength] < SP_TEXT_SIZE_TRIGGER_FOR_PARTLY_PARSING)
+ [self doSyntaxHighlighting];
+ } else {
+ textBufferSizeIncreased = NO;
}
startListeningToBoundChanges = YES;
diff --git a/Source/NoodleLineNumberView.m b/Source/NoodleLineNumberView.m
index 1ba6e2f1..9be65981 100644
--- a/Source/NoodleLineNumberView.m
+++ b/Source/NoodleLineNumberView.m
@@ -50,13 +50,13 @@
- (id)initWithScrollView:(NSScrollView *)aScrollView
{
- if ((self = [super initWithScrollView:aScrollView orientation:NSVerticalRuler]) != nil)
- {
- [self setClientView:[aScrollView documentView]];
+ if ((self = [super initWithScrollView:aScrollView orientation:NSVerticalRuler]) != nil)
+ {
+ [self setClientView:[aScrollView documentView]];
lineIndices = nil;
}
-
- return self;
+
+ return self;
}
- (void)awakeFromNib
@@ -66,21 +66,21 @@
- (void)dealloc
{
- [[NSNotificationCenter defaultCenter] removeObserver:self];
-
- if (lineIndices) [lineIndices release];
- [font release];
-
- [super dealloc];
+ [[NSNotificationCenter defaultCenter] removeObserver:self];
+
+ if (lineIndices) [lineIndices release];
+ [font release];
+
+ [super dealloc];
}
- (void)setFont:(NSFont *)aFont
{
- if (font != aFont)
- {
- [font autorelease];
+ if (font != aFont)
+ {
+ [font autorelease];
font = [aFont retain];
- }
+ }
}
- (NSFont *)font
@@ -144,21 +144,21 @@
- (void)setClientView:(NSView *)aView
{
- id oldClientView;
-
+ id oldClientView;
+
oldClientView = [self clientView];
-
- if ((oldClientView != aView) && [oldClientView isKindOfClass:[NSTextView class]])
- {
+
+ if ((oldClientView != aView) && [oldClientView isKindOfClass:[NSTextView class]])
+ {
[[NSNotificationCenter defaultCenter] removeObserver:self name:NSTextStorageDidProcessEditingNotification object:[(NSTextView *)oldClientView textStorage]];
- }
- [super setClientView:aView];
- if ((aView != nil) && [aView isKindOfClass:[NSTextView class]])
- {
+ }
+ [super setClientView:aView];
+ if ((aView != nil) && [aView isKindOfClass:[NSTextView class]])
+ {
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(textDidChange:) name:NSTextStorageDidProcessEditingNotification object:[(NSTextView *)aView textStorage]];
[self invalidateLineIndices];
- }
+ }
}
- (NSMutableArray *)lineIndices
@@ -179,8 +179,8 @@
{
// Invalidate the line indices. They will be recalculated and recached on demand.
[self invalidateLineIndices];
-
- [self setNeedsDisplay:YES];
+
+ [self setNeedsDisplay:YES];
}
- (NSUInteger)lineNumberForLocation:(CGFloat)location
@@ -231,60 +231,60 @@
- (void)calculateLines
{
- id view;
+ id view;
- view = [self clientView];
-
- if ([view isKindOfClass:[NSTextView class]])
- {
- NSUInteger index, numberOfLines, stringLength, lineEnd, contentEnd;
- NSString *text;
- CGFloat oldThickness, newThickness;
-
- text = [view string];
- stringLength = [text length];
- // Switch off line numbering if text larger than 6MB
- // for performance reasons.
- // TODO improve performance maybe via threading
- if(stringLength>6000000)
- return;
- if (lineIndices) [lineIndices release];
- lineIndices = [[NSMutableArray alloc] init];
-
- index = 0;
- numberOfLines = 0;
-
- do
- {
- [lineIndices addObject:[NSNumber numberWithUnsignedInteger:index]];
-
- index = NSMaxRange([text lineRangeForRange:NSMakeRange(index, 0)]);
- numberOfLines++;
- }
- while (index < stringLength);
+ view = [self clientView];
- // Check if text ends with a new line.
- [text getLineStart:NULL end:&lineEnd contentsEnd:&contentEnd forRange:NSMakeRange([[lineIndices lastObject] unsignedIntegerValue], 0)];
- if (contentEnd < lineEnd)
- {
- [lineIndices addObject:[NSNumber numberWithUnsignedInteger:index]];
- }
+ if ([view isKindOfClass:[NSTextView class]])
+ {
+ NSUInteger index, numberOfLines, stringLength, lineEnd, contentEnd;
+ NSString *text;
+ CGFloat oldThickness, newThickness;
+
+ text = [view string];
+ stringLength = [text length];
+ // Switch off line numbering if text larger than 6MB
+ // for performance reasons.
+ // TODO improve performance maybe via threading
+ if(stringLength>6000000)
+ return;
+ if (lineIndices) [lineIndices release];
+ lineIndices = [[NSMutableArray alloc] init];
+
+ index = 0;
+ numberOfLines = 0;
+
+ do
+ {
+ [lineIndices addObject:[NSNumber numberWithUnsignedInteger:index]];
- oldThickness = [self ruleThickness];
- newThickness = [self requiredThickness];
- if (fabs(oldThickness - newThickness) > 1)
- {
+ index = NSMaxRange([text lineRangeForRange:NSMakeRange(index, 0)]);
+ numberOfLines++;
+ }
+ while (index < stringLength);
+
+ // Check if text ends with a new line.
+ [text getLineStart:NULL end:&lineEnd contentsEnd:&contentEnd forRange:NSMakeRange([[lineIndices lastObject] unsignedIntegerValue], 0)];
+ if (contentEnd < lineEnd)
+ {
+ [lineIndices addObject:[NSNumber numberWithUnsignedInteger:index]];
+ }
+
+ oldThickness = [self ruleThickness];
+ newThickness = [self requiredThickness];
+ if (fabs(oldThickness - newThickness) > 1)
+ {
NSInvocation *invocation;
-
+
// Not a good idea to resize the view during calculations (which can happen during
// display). Do a delayed perform (using NSInvocation since arg is a float).
invocation = [NSInvocation invocationWithMethodSignature:[self methodSignatureForSelector:@selector(setRuleThickness:)]];
[invocation setSelector:@selector(setRuleThickness:)];
[invocation setTarget:self];
[invocation setArgument:&newThickness atIndex:2];
-
+
[invocation performSelector:@selector(invoke) withObject:nil afterDelay:0.0];
- }
+ }
}
}
@@ -330,26 +330,25 @@
- (CGFloat)requiredThickness
{
- NSUInteger lineCount, digits, i;
- NSMutableString *sampleString;
- NSSize stringSize;
-
- lineCount = [[self lineIndices] count];
- digits = (NSUInteger)log10(lineCount) + 1;
- sampleString = [NSMutableString string];
- for (i = 0; i < digits; i++)
- {
- // Use "8" since it is one of the fatter numbers. Anything but "1"
- // will probably be ok here. I could be pedantic and actually find the fattest
- // number for the current font but nah.
- [sampleString appendString:@"8"];
- }
-
- stringSize = [sampleString sizeWithAttributes:[self textAttributes]];
-
- // Round up the value. There is a bug on 10.4 where the display gets all wonky when scrolling if you don't
- // return an integral value here.
- return ceil(MAX(DEFAULT_THICKNESS, stringSize.width + RULER_MARGIN * 2));
+ NSUInteger lineCount = [[self lineIndices] count];
+ if(lineCount < 10)
+ return ceil(MAX(DEFAULT_THICKNESS, [[NSString stringWithString:@"8"] sizeWithAttributes:[self textAttributes]].width + RULER_MARGIN * 2));
+ else if(lineCount < 100)
+ return ceil(MAX(DEFAULT_THICKNESS, [[NSString stringWithString:@"88"] sizeWithAttributes:[self textAttributes]].width + RULER_MARGIN * 2));
+ else if(lineCount < 1000)
+ return ceil(MAX(DEFAULT_THICKNESS, [[NSString stringWithString:@"888"] sizeWithAttributes:[self textAttributes]].width + RULER_MARGIN * 2));
+ else if(lineCount < 10000)
+ return ceil(MAX(DEFAULT_THICKNESS, [[NSString stringWithString:@"8888"] sizeWithAttributes:[self textAttributes]].width + RULER_MARGIN * 2));
+ else if(lineCount < 100000)
+ return ceil(MAX(DEFAULT_THICKNESS, [[NSString stringWithString:@"88888"] sizeWithAttributes:[self textAttributes]].width + RULER_MARGIN * 2));
+ else if(lineCount < 1000000)
+ return ceil(MAX(DEFAULT_THICKNESS, [[NSString stringWithString:@"888888"] sizeWithAttributes:[self textAttributes]].width + RULER_MARGIN * 2));
+ else if(lineCount < 10000000)
+ return ceil(MAX(DEFAULT_THICKNESS, [[NSString stringWithString:@"8888888"] sizeWithAttributes:[self textAttributes]].width + RULER_MARGIN * 2));
+ else if(lineCount < 100000000)
+ return ceil(MAX(DEFAULT_THICKNESS, [[NSString stringWithString:@"88888888"] sizeWithAttributes:[self textAttributes]].width + RULER_MARGIN * 2));
+ else
+ return 100;
}
- (void)drawHashMarksAndLabelsInRect:(NSRect)aRect