aboutsummaryrefslogtreecommitdiffstats
path: root/Source
diff options
context:
space:
mode:
Diffstat (limited to 'Source')
-rw-r--r--Source/CMTextView.h9
-rw-r--r--Source/CMTextView.m293
-rw-r--r--Source/CustomQuery.m48
-rw-r--r--Source/NoodleLineNumberView.m8
-rw-r--r--Source/SPEditorTokens.h8
-rw-r--r--Source/SPPreferenceController.h12
-rw-r--r--Source/SPPreferenceController.m130
7 files changed, 359 insertions, 149 deletions
diff --git a/Source/CMTextView.h b/Source/CMTextView.h
index 964598cd..a133d825 100644
--- a/Source/CMTextView.h
+++ b/Source/CMTextView.h
@@ -29,6 +29,7 @@
#import "CMMCPConnection.h"
#import "CMMCPResult.h"
+#define SP_TEXT_SIZE_TRIGGER_FOR_PARTLY_PARSING 10000
@interface CMTextView : NSTextView {
BOOL autoindentEnabled;
@@ -41,15 +42,15 @@
NSString *showMySQLHelpFor;
- BOOL sqlStringIsTooLarge;
-
IBOutlet NSScrollView *scrollView;
+
+ NSUserDefaults *prefs;
}
- (IBAction)showMySQLHelpForCurrentWord:(id)sender;
-- (BOOL) isNextCharMarkedBy:(id)attribute;
+- (BOOL) isNextCharMarkedBy:(id)attribute withValue:(id)aValue;
- (BOOL) areAdjacentCharsLinked;
- (BOOL) wrapSelectionWithPrefix:(NSString *)prefix suffix:(NSString *)suffix;
- (BOOL) shiftSelectionRight;
@@ -69,6 +70,6 @@
- (void) selectLineNumber:(unsigned int)lineNumber ignoreLeadingNewLines:(BOOL)ignLeadingNewLines;
- (unsigned int) getLineNumberForCharacterIndex:(unsigned int)anIndex;
- (void) autoHelp;
-- (void) doSyntaxHighlighting:(NSTextStorage*)textStore;
+- (void) doSyntaxHighlighting;
@end
diff --git a/Source/CMTextView.m b/Source/CMTextView.m
index 982cd9c6..85f4f8bf 100644
--- a/Source/CMTextView.m
+++ b/Source/CMTextView.m
@@ -37,18 +37,21 @@ typedef struct yy_buffer_state *YY_BUFFER_STATE;
void yy_switch_to_buffer(YY_BUFFER_STATE);
YY_BUFFER_STATE yy_scan_string (const char *);
-#define kAPlinked @"Linked" // attribute for a via auto-pair inserted char
-#define kAPval @"linked"
-#define kWQquoted @"Quoted" // set via lex to indicate a quoted string
-#define kSQLkeyword @"SQLkw" // attribute for found SQL keywords
-#define kQuote @"Quote"
-#define kQuoteValue @"isQuoted"
-#define kValue @"dummy"
-#define kBTQuote @"BTQuote"
-#define kBTQuoteValue @"isBTQuoted"
+#define kAPlinked @"Linked" // attribute for a via auto-pair inserted 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 kQuote @"Quote"
+#define kQuoteValue @"isQuoted"
+#define kValue @"dummy"
+#define kBTQuote @"BTQuote"
+#define kBTQuoteValue @"isBTQuoted"
#define SP_CQ_SEARCH_IN_MYSQL_HELP_MENU_ITEM_TAG 1000
+#define SP_SYNTAX_HILITE_BIAS 2000
+
#define MYSQL_DOC_SEARCH_URL @"http://dev.mysql.com/doc/refman/%@/en/%@.html"
@@ -115,7 +118,7 @@ YY_BUFFER_STATE yy_scan_string (const char *);
/*
* Checks if the char after the current caret position/selection matches a supplied attribute
*/
-- (BOOL) isNextCharMarkedBy:(id)attribute
+- (BOOL) isNextCharMarkedBy:(id)attribute withValue:(id)aValue
{
unsigned int caretPosition = [self selectedRange].location;
@@ -123,7 +126,7 @@ YY_BUFFER_STATE yy_scan_string (const char *);
if (caretPosition >= [[self string] length]) return NO;
// Perform the check
- if ([[self textStorage] attribute:attribute atIndex:caretPosition effectiveRange:nil])
+ if ([[[self textStorage] attribute:attribute atIndex:caretPosition effectiveRange:nil] isEqualToString:aValue])
return YES;
return NO;
@@ -154,7 +157,7 @@ YY_BUFFER_STATE yy_scan_string (const char *);
// Check that the pairing character exists after the caret, and is tagged with the link attribute
if (matchingChar == [[self string] characterAtIndex:caretPosition]
- && [[self textStorage] attribute:kAPlinked atIndex:caretPosition effectiveRange:nil]) {
+ && [[[self textStorage] attribute:kAPlinked atIndex:caretPosition effectiveRange:nil] isEqualToString:kAPval]) {
return YES;
}
@@ -233,6 +236,25 @@ YY_BUFFER_STATE yy_scan_string (const char *);
[self scrollRangeToVisible:selRange];
}
+/*
+ * Used for autoHelp update if the user changed the caret position by using the mouse.
+ */
+- (void) mouseDown:(NSEvent *)theEvent
+{
+
+ // Cancel autoHelp timer
+ if([prefs boolForKey:@"CustomQueryAutohelp"])
+ [NSObject cancelPreviousPerformRequestsWithTarget:self
+ selector:@selector(autoHelp)
+ object:nil];
+
+ [super mouseDown:theEvent];
+
+ // Start autoHelp timer
+ if([prefs boolForKey:@"CustomQueryAutohelp"])
+ [self performSelector:@selector(autoHelp) withObject:nil afterDelay:[[[prefs valueForKey:@"CustomQueryAutohelpDelay"] retain] floatValue]];
+
+}
/*
* Handle some keyDown events in order to provide autopairing functionality (if enabled).
@@ -240,7 +262,7 @@ YY_BUFFER_STATE yy_scan_string (const char *);
- (void) keyDown:(NSEvent *)theEvent
{
- if(autohelpEnabled) // cancel autoHelp request
+ if([prefs boolForKey:@"CustomQueryAutohelp"]) // cancel autoHelp request
[NSObject cancelPreviousPerformRequestsWithTarget:self
selector:@selector(autoHelp)
object:nil];
@@ -262,7 +284,6 @@ YY_BUFFER_STATE yy_scan_string (const char *);
unichar insertedCharacter = [characters characterAtIndex:0];
long curFlags = ([theEvent modifierFlags] & allFlags);
-
// Note: switch(insertedCharacter) {} does not work instead use charactersIgnoringModifiers
if([charactersIgnMod isEqualToString:@"c"]) // ^C copy as RTF
if(curFlags==(NSControlKeyMask))
@@ -279,7 +300,7 @@ YY_BUFFER_STATE yy_scan_string (const char *);
}
// Only process for character autopairing if autopairing is enabled and a single character is being added.
- if (autopairEnabled && characters && [characters length] == 1) {
+ if ([prefs boolForKey:@"CustomQueryAutopair"] && characters && [characters length] == 1) {
delBackwardsWasPressed = NO;
@@ -295,10 +316,10 @@ YY_BUFFER_STATE yy_scan_string (const char *);
(insertedCharacter == '\'' || insertedCharacter == '"' || insertedCharacter == '`')
// And if the next char marked as linked auto-pair
- && [self isNextCharMarkedBy:kAPlinked]
+ && [self isNextCharMarkedBy:kAPlinked withValue:kAPval]
// And we are inside a quoted string
- && [self isNextCharMarkedBy:kWQquoted]
+ && [self isNextCharMarkedBy:kLEXToken withValue:kLEXTokenValue]
// And there is no selection, just the text caret
&& ![self selectedRange].length
@@ -320,7 +341,7 @@ YY_BUFFER_STATE yy_scan_string (const char *);
// There is one exception to this - if the caret is before a linked pair character,
// processing continues in order to check whether the next character should be jumped
// over; e.g. [| := caret]: "foo|" and press " => only caret will be moved "foo"|
- if(![self isNextCharMarkedBy:kAPlinked] && [self isNextCharMarkedBy:kWQquoted] && ![self selectedRange].length) {
+ if(![self isNextCharMarkedBy:kAPlinked withValue:kAPval] && [self isNextCharMarkedBy:kLEXToken withValue:kLEXTokenValue] && ![self selectedRange].length) {
[super keyDown:theEvent];
return;
}
@@ -360,7 +381,7 @@ YY_BUFFER_STATE yy_scan_string (const char *);
if (skipTypedLinkedCharacter) {
currentRange = [self selectedRange];
if (currentRange.location != NSNotFound && currentRange.length == 0) {
- if ([self isNextCharMarkedBy:kAPlinked]) {
+ if ([self isNextCharMarkedBy:kAPlinked withValue:kAPval]) {
if ([[[self textStorage] string] characterAtIndex:currentRange.location] == insertedCharacter) {
currentRange.length = 1;
[self setSelectedRange:currentRange];
@@ -405,29 +426,12 @@ YY_BUFFER_STATE yy_scan_string (const char *);
// The default action is to perform the normal key-down action.
[super keyDown:theEvent];
- if(autohelpEnabled)
- [self performSelector:@selector(autoHelp) withObject:nil afterDelay:1];
+ if([prefs boolForKey:@"CustomQueryAutohelp"])
+ [self performSelector:@selector(autoHelp) withObject:nil afterDelay:[[[prefs valueForKey:@"CustomQueryAutohelpDelay"] retain] floatValue]];
}
-/*
- * Notify autoHelp if user changed the insertion point
- */
-- (void)mouseDown:(NSEvent *)theEvent
-{
-
- if(autohelpEnabled) // cancel autoHelp request
- [NSObject cancelPreviousPerformRequestsWithTarget:self
- selector:@selector(autoHelp)
- object:nil];
-
- [super mouseDown:theEvent];
- if(autohelpEnabled)
- [self performSelector:@selector(autoHelp) withObject:nil afterDelay:1];
-
-}
-
- (void) deleteBackward:(id)sender
{
@@ -456,7 +460,7 @@ YY_BUFFER_STATE yy_scan_string (const char *);
// Handle newlines, adding any indentation found on the current line to the new line - ignoring the enter key if appropriate
if (aSelector == @selector(insertNewline:)
- && autoindentEnabled
+ && [prefs boolForKey:@"CustomQueryAutoindent"]
&& (!autoindentIgnoresEnter || [[NSApp currentEvent] keyCode] != 0x4C))
{
NSString *textViewString = [[self textStorage] string];
@@ -629,7 +633,7 @@ YY_BUFFER_STATE yy_scan_string (const char *);
// Check if the caret is inside quotes "" or ''; if so
// return the normal word suggestion due to the spelling's settings
- if(!sqlStringIsTooLarge && [[[self textStorage] attribute:kQuote atIndex:charRange.location effectiveRange:nil] isEqualToString:kQuoteValue] )
+ if([[[self textStorage] attribute:kQuote atIndex:charRange.location effectiveRange:nil] isEqualToString:kQuoteValue] )
return [[NSSpellChecker sharedSpellChecker] completionsForPartialWordRange:NSMakeRange(0,charRange.length) inString:[[self string] substringWithRange:charRange] language:nil inSpellDocumentWithTag:0];
@@ -665,12 +669,15 @@ YY_BUFFER_STATE yy_scan_string (const char *);
}
// If caret is not inside backticks add keywords and all words coming from the view.
- if(!sqlStringIsTooLarge && ![[[self textStorage] attribute:kBTQuote atIndex:charRange.location effectiveRange:nil] isEqualToString:kBTQuoteValue] )
+ if(![[[self textStorage] attribute:kBTQuote atIndex:charRange.location effectiveRange:nil] isEqualToString:kBTQuoteValue] )
{
- NSCharacterSet *separators = [NSCharacterSet characterSetWithCharactersInString:@" \t\r\n,()\"'`-!;=+|?:~"];
- NSArray *textViewWords = [[self string] componentsSeparatedByCharactersInSet:separators];
-
- [possibleCompletions addObjectsFromArray:textViewWords];
+ // Only parse for words if text size is less than 6MB
+ if([[self string] length]<6000000)
+ {
+ NSCharacterSet *separators = [NSCharacterSet characterSetWithCharactersInString:@" \t\r\n,()\"'`-!;=+|?:~"];
+ NSArray *textViewWords = [[self string] componentsSeparatedByCharactersInSet:separators];
+ [possibleCompletions addObjectsFromArray:textViewWords];
+ }
[possibleCompletions addObjectsFromArray:[self keywords]];
}
@@ -1762,32 +1769,58 @@ SYNTAX HIGHLIGHTING!
autohelpEnabled = NO;
delBackwardsWasPressed = NO;
- // commentColor = [NSColor colorWithDeviceRed:0.000 green:0.455 blue:0.000 alpha:1.000];
- // quoteColor = [NSColor colorWithDeviceRed:0.769 green:0.102 blue:0.086 alpha:1.000];
- // keywordColor = [NSColor colorWithDeviceRed:0.200 green:0.250 blue:1.000 alpha:1.000];
- // backtickColor = [NSColor colorWithDeviceRed:0.0 green:0.0 blue:0.658 alpha:1.000];
- // numericColor = [NSColor colorWithDeviceRed:0.506 green:0.263 blue:0.0 alpha:1.000];
- // variableColor = [NSColor colorWithDeviceRed:0.5 green:0.5 blue:0.5 alpha:1.000];
-
lineNumberView = [[NoodleLineNumberView alloc] initWithScrollView:scrollView];
[scrollView setVerticalRulerView:lineNumberView];
[scrollView setHasHorizontalRuler:NO];
[scrollView setHasVerticalRuler:YES];
[scrollView setRulersVisible:YES];
+
+ // disabled to get the current text range in textView safer
+ [[self layoutManager] setBackgroundLayoutEnabled:NO];
+
+ // add NSViewBoundsDidChangeNotification to scrollView
+ [[scrollView contentView] setPostsBoundsChangedNotifications:YES];
+ NSNotificationCenter *aNotificationCenter = [NSNotificationCenter defaultCenter];
+ [aNotificationCenter addObserver:self selector:@selector(boundsDidChangeNotification:) name:@"NSViewBoundsDidChangeNotification" object:[scrollView contentView]];
+
+ prefs = [[NSUserDefaults standardUserDefaults] retain];
}
+/*
+ * Scrollview delegate after the textView's view port was changed.
+ * Manily used to update the syntax highlighting for a large text size.
+ */
+- (void) boundsDidChangeNotification:(NSNotification *)notification
+{
+ // Invoke syntax highlighting if text view port was changed for large text
+ if([[self string] length] > SP_TEXT_SIZE_TRIGGER_FOR_PARTLY_PARSING)
+ {
+ [NSObject cancelPreviousPerformRequestsWithTarget:self
+ selector:@selector(doSyntaxHighlighting)
+ object:nil];
+
+ if(![[self textStorage] changeInLength])
+ [self performSelector:@selector(doSyntaxHighlighting) withObject:nil afterDelay:0.4];
+ }
+
+}
+/*
+ * If enabled it shows the MySQL Help for the current word (not inside quotes) or for the selection
+ * after an adjustable delay if the textView is idle, i.e. no user interaction.
+ */
- (void)autoHelp
{
- if(!autohelpEnabled) return;
+ if(![prefs boolForKey:@"CustomQueryAutohelp"]) return;
+ // If selection show Help for it
if([self selectedRange].length)
{
[[[[self window] delegate] valueForKeyPath:@"customQueryInstance"] performSelector:@selector(showHelpForCurrentWord:) withObject:self afterDelay:0.1];
return;
}
-
+ // Otherwise show Help if caret is not inside quotes
long cursorPosition = [self selectedRange].location;
if (cursorPosition >= [[self string] length]) cursorPosition--;
if(cursorPosition > -1 && (![[self textStorage] attribute:kQuote atIndex:cursorPosition effectiveRange:nil]||[[self textStorage] attribute:kSQLkeyword atIndex:cursorPosition effectiveRange:nil]))
@@ -1795,33 +1828,102 @@ SYNTAX HIGHLIGHTING!
}
-- (void)doSyntaxHighlighting:(NSTextStorage*)textStore
+/*
+ * Syntax Highlighting.
+ *
+ * (The main bottleneck is the [NSTextStorage addAttribute:value:range:] method - the parsing itself is really fast!)
+ * Some sample code from Andrew Choi ( http://members.shaw.ca/akochoi-old/blog/2003/11-09/index.html#3 ) has been reused.
+ */
+- (void)doSyntaxHighlighting
{
+
+ NSTextStorage *textStore = [self textStorage];
+ NSRange textRange;
+
+ // If text larger than SP_TEXT_SIZE_TRIGGER_FOR_PARTLY_PARSING
+ // do highlighting partly (max SP_SYNTAX_HILITE_BIAS*2).
+ // The approach is to take the middle position of the current view port
+ // and highlight only ±SP_SYNTAX_HILITE_BIAS of that middle position
+ // considering of line starts resp. ends
+ if([[self string] length] > SP_TEXT_SIZE_TRIGGER_FOR_PARTLY_PARSING)
+ {
+
+ // Cancel all doSyntaxHighlighting requests
+ [NSObject cancelPreviousPerformRequestsWithTarget:self
+ selector:@selector(doSyntaxHighlighting)
+ object:nil];
+
+ // Get the text range currently displayed in the view port
+ NSRect visibleRect = [[[self enclosingScrollView] contentView] documentVisibleRect];
+ NSRange visibleRange = [[self layoutManager] glyphRangeForBoundingRectWithoutAdditionalLayout:visibleRect inTextContainer:[self textContainer]];
+ if(!visibleRange.length) return;
+
+ // Take roughly the middle position in the current view port
+ int curPos = visibleRange.location+(int)(visibleRange.length/2);
+
+ int strlength = [[self string] length];
+
+ // get the last line to parse due to SP_SYNTAX_HILITE_BIAS
+ int end = curPos + SP_SYNTAX_HILITE_BIAS;
+ if (end > strlength )
+ {
+ end = strlength;
+ } else {
+ while(end < strlength)
+ {
+ if([[self string] characterAtIndex:end]=='\n')
+ break;
+ end++;
+ }
+ }
+
+ // get the first line to parse due to SP_SYNTAX_HILITE_BIAS
+ int start = end - (SP_SYNTAX_HILITE_BIAS*2);
+ if (start > 0)
+ while(start>-1)
+ {
+ if([[self string] characterAtIndex:start]=='\n')
+ break;
+ start--;
+ }
+ else
+ start = 0;
+
+
+ textRange = NSMakeRange(start, end-start);
+ // only to be sure that nothing went wrongly
+ textRange = NSIntersectionRange(textRange, NSMakeRange(0, [textStore length]));
+ if (!textRange.length)
+ return;
+ } else {
+ // If text size is less SP_TEXT_SIZE_TRIGGER_FOR_PARTLY_PARSING
+ // process syntax highlighting for the entire text view buffer
+ textRange = NSMakeRange(0,[[self string] length]);
+ }
+
NSColor *tokenColor;
- NSColor *commentColor = [NSColor colorWithDeviceRed:0.000 green:0.455 blue:0.000 alpha:1.000];
- NSColor *quoteColor = [NSColor colorWithDeviceRed:0.769 green:0.102 blue:0.086 alpha:1.000];
- NSColor *keywordColor = [NSColor colorWithDeviceRed:0.200 green:0.250 blue:1.000 alpha:1.000];
- NSColor *backtickColor = [NSColor colorWithDeviceRed:0.0 green:0.0 blue:0.658 alpha:1.000];
- NSColor *numericColor = [NSColor colorWithDeviceRed:0.506 green:0.263 blue:0.0 alpha:1.000];
- NSColor *variableColor = [NSColor colorWithDeviceRed:0.5 green:0.5 blue:0.5 alpha:1.000];
+
+ NSColor *commentColor = [[NSUnarchiver unarchiveObjectWithData:[prefs dataForKey:@"CustomQueryEditorCommentColor"]] retain];//[NSColor colorWithDeviceRed:0.000 green:0.455 blue:0.000 alpha:1.000];
+ NSColor *quoteColor = [[NSUnarchiver unarchiveObjectWithData:[prefs dataForKey:@"CustomQueryEditorQuoteColor"]] retain];//[NSColor colorWithDeviceRed:0.769 green:0.102 blue:0.086 alpha:1.000];
+ NSColor *keywordColor = [[NSUnarchiver unarchiveObjectWithData:[prefs dataForKey:@"CustomQueryEditorSQLKeywordColor"]] retain];//[NSColor colorWithDeviceRed:0.200 green:0.250 blue:1.000 alpha:1.000];
+ NSColor *backtickColor = [[NSUnarchiver unarchiveObjectWithData:[prefs dataForKey:@"CustomQueryEditorBacktickColor"]] retain];//[NSColor colorWithDeviceRed:0.0 green:0.0 blue:0.658 alpha:1.000];
+ NSColor *numericColor = [[NSUnarchiver unarchiveObjectWithData:[prefs dataForKey:@"CustomQueryEditorNumericColor"]] retain];//[NSColor colorWithDeviceRed:0.506 green:0.263 blue:0.0 alpha:1.000];
+ NSColor *variableColor = [[NSUnarchiver unarchiveObjectWithData:[prefs dataForKey:@"CustomQueryEditorVariableColor"]] retain];//[NSColor colorWithDeviceRed:0.5 green:0.5 blue:0.5 alpha:1.000];
+ NSColor *textColor = [[NSUnarchiver unarchiveObjectWithData:[prefs dataForKey:@"CustomQueryEditorTextColor"]] retain];//[NSColor colorWithDeviceRed:0.5 green:0.5 blue:0.5 alpha:1.000];
- int token;
- NSRange textRange, tokenRange;
+ BOOL autouppercaseKeywords = [prefs boolForKey:@"CustomQueryAutouppercaseKeywords"];
- textRange = NSMakeRange(0, [textStore length]);
+ unsigned long tokenEnd, token;
+ NSRange tokenRange;
//first remove the old colors and kQuote
[textStore removeAttribute:NSForegroundColorAttributeName range:textRange];
[textStore removeAttribute:kQuote range:textRange];
-
- //don't color texts longer than about 20KB. would be too slow
- sqlStringIsTooLarge = (textRange.length > 20000);
- if(sqlStringIsTooLarge) return;
-
+ [textStore removeAttribute:kLEXToken range:textRange];
//initialise flex
- yyuoffset = 0; yyuleng = 0;
- yy_switch_to_buffer(yy_scan_string([[textStore string] UTF8String]));
+ yyuoffset = textRange.location; yyuleng = 0;
+ yy_switch_to_buffer(yy_scan_string([[[self string] substringWithRange:textRange] UTF8String]));
//now loop through all the tokens
while (token=yylex()){
@@ -1845,8 +1947,11 @@ SYNTAX HIGHLIGHTING!
case SPT_VARIABLE:
tokenColor = variableColor;
break;
- default:
+ case SPT_WHITESPACE:
tokenColor = nil;
+ break;
+ default:
+ tokenColor = textColor;
}
if (!tokenColor) continue;
@@ -1859,19 +1964,20 @@ SYNTAX HIGHLIGHTING!
if (!tokenRange.length) continue;
// If the current token is marked as SQL keyword, uppercase it if required.
- unsigned long tokenEnd = tokenRange.location+tokenRange.length-1;
+ tokenEnd = tokenRange.location+tokenRange.length-1;
// Check the end of the token
- if (autouppercaseKeywordsEnabled && !delBackwardsWasPressed
+ if (autouppercaseKeywords && !delBackwardsWasPressed
&& [[self textStorage] attribute:kSQLkeyword atIndex:tokenEnd effectiveRange:nil])
// 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 = [[self string] substringWithRange:tokenRange];
BOOL doIt = NO;
@try
{
- doIt = ![[self textStorage] attribute:kSQLkeyword atIndex:tokenEnd+1 effectiveRange:nil];
+ doIt = ![[self textStorage] attribute:kSQLkeyword atIndex:tokenEnd+1 effectiveRange:nil];
} @catch(id ae) { doIt = YES; }
if(doIt && ![[curTokenString uppercaseString] isEqualToString:curTokenString])
@@ -1889,10 +1995,11 @@ SYNTAX HIGHLIGHTING!
// 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?)
- [textStore addAttribute: kWQquoted
- value: kValue
+ if(token < 6)
+ [textStore addAttribute: kLEXToken
+ value: kLEXTokenValue
range: 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.
@@ -1906,34 +2013,44 @@ SYNTAX HIGHLIGHTING!
[textStore addAttribute: kQuote
value: kQuoteValue
range: tokenRange ];
+ //distinguish backtick quoted word for completion
else if(token == SPT_BACKTICK_QUOTED_TEXT)
[textStore addAttribute: kBTQuote
value: kBTQuoteValue
range: tokenRange ];
+
}
}
/*
- * Performs syntax highlighting.
- * This method recolors the entire text on every keypress. For performance reasons, this function does
- * nothing if the text is more than 20 KB.
- *
- * The main bottleneck is the [NSTextStorage addAttribute:value:range:] method - the parsing itself is really fast!
- *
- * Some sample code from Andrew Choi ( http://members.shaw.ca/akochoi-old/blog/2003/11-09/index.html#3 ) has been reused.
+ * Performs syntax highlighting after a text change.
*/
- (void)textStorageDidProcessEditing:(NSNotification *)notification
{
-
NSTextStorage *textStore = [notification object];
//make sure that the notification is from the correct textStorage object
if (textStore!=[self textStorage]) return;
- [self doSyntaxHighlighting:textStore];
-
+ [NSObject cancelPreviousPerformRequestsWithTarget:self
+ selector:@selector(doSyntaxHighlighting)
+ object:nil];
+
+ [self doSyntaxHighlighting];
+
+}
+
+/*
+ * Show only setable modes in the font panel
+ */
+- (unsigned int)validModesForFontPanel:(NSFontPanel *)fontPanel
+{
+ return (NSFontPanelFaceModeMask | NSFontPanelSizeModeMask);
}
+
+
@end
+
diff --git a/Source/CustomQuery.m b/Source/CustomQuery.m
index 2289b561..5efc0ffc 100644
--- a/Source/CustomQuery.m
+++ b/Source/CustomQuery.m
@@ -190,7 +190,6 @@ closes the sheet
[NSApp stopModal];
}
-
/*
* Perform simple actions (which don't require their own method), triggered by selecting the appropriate menu item
* in the "gear" action menu displayed beneath the cusotm query view.
@@ -228,7 +227,7 @@ closes the sheet
// "Indent new lines" toggle
if (sender == autoindentMenuItem) {
- BOOL enableAutoindent = ([autoindentMenuItem state] == NSOffState);
+ BOOL enableAutoindent = !([autoindentMenuItem state] == NSOffState);
[prefs setBool:enableAutoindent forKey:@"CustomQueryAutoindent"];
[prefs synchronize];
[autoindentMenuItem setState:enableAutoindent?NSOnState:NSOffState];
@@ -237,7 +236,7 @@ closes the sheet
// "Auto-pair characters" toggle
if (sender == autopairMenuItem) {
- BOOL enableAutopair = ([autopairMenuItem state] == NSOffState);
+ BOOL enableAutopair = !([autopairMenuItem state] == NSOffState);
[prefs setBool:enableAutopair forKey:@"CustomQueryAutopair"];
[prefs synchronize];
[autopairMenuItem setState:enableAutopair?NSOnState:NSOffState];
@@ -246,7 +245,7 @@ closes the sheet
// "Auto-help" toggle
if (sender == autohelpMenuItem) {
- BOOL enableAutohelp = ([autohelpMenuItem state] == NSOffState);
+ BOOL enableAutohelp = !([autohelpMenuItem state] == NSOffState);
[prefs setBool:enableAutohelp forKey:@"CustomQueryAutohelp"];
[prefs synchronize];
[autohelpMenuItem setState:enableAutohelp?NSOnState:NSOffState];
@@ -255,7 +254,7 @@ closes the sheet
// "Auto-uppercase keywords" toggle
if (sender == autouppercaseKeywordsMenuItem) {
- BOOL enableAutouppercaseKeywords = ([autouppercaseKeywordsMenuItem state] == NSOffState);
+ BOOL enableAutouppercaseKeywords = !([autouppercaseKeywordsMenuItem state] == NSOffState);
[prefs setBool:enableAutouppercaseKeywords forKey:@"CustomQueryAutouppercaseKeywords"];
[prefs synchronize];
[autouppercaseKeywordsMenuItem setState:enableAutouppercaseKeywords?NSOnState:NSOffState];
@@ -910,8 +909,20 @@ sets the connection (received from TableDocument) and makes things that have to
}
// Set up the interface
- [customQueryView setVerticalMotionCanBeginDrag:NO];
+ // Bind backgroundColor
+ [textView setAllowsDocumentBackgroundColorChange:YES];
+ NSMutableDictionary *bindingOptions = [NSMutableDictionary dictionary];
+ [bindingOptions setObject:NSUnarchiveFromDataTransformerName
+ forKey:@"NSValueTransformerName"];
+ [textView bind: @"backgroundColor"
+ toObject: [NSUserDefaultsController sharedUserDefaultsController]
+ withKeyPath:@"values.CustomQueryEditorBackgroundColor"
+ options:bindingOptions];
[textView setFont:[NSUnarchiver unarchiveObjectWithData:[prefs dataForKey:@"CustomQueryEditorFont"]]];
+ [textView setBackgroundColor:[NSUnarchiver unarchiveObjectWithData:[prefs dataForKey:@"CustomQueryEditorBackgroundColor"]]];
+ [textView setTextColor:[NSUnarchiver unarchiveObjectWithData:[prefs dataForKey:@"CustomQueryEditorTextColor"]]];
+
+ [customQueryView setVerticalMotionCanBeginDrag:NO];
[textView setContinuousSpellCheckingEnabled:NO];
[autoindentMenuItem setState:([prefs boolForKey:@"CustomQueryAutoindent"]?NSOnState:NSOffState)];
[textView setAutoindent:[prefs boolForKey:@"CustomQueryAutoindent"]];
@@ -1343,23 +1354,9 @@ traps enter key and
[runSelectionMenuItem setTitle:NSLocalizedString(@"Run Selected Text", @"Title of action menu item to run selected text in custom query view")];
[runSelectionMenuItem setEnabled:YES];
}
-}
-
-
-/*
- * Save the custom query editor font if it is changed.
- */
-- (void)textViewDidChangeTypingAttributes:(NSNotification *)aNotification
-{
- // Only save the font if prefs have been loaded, ensuring the saved font has been applied once.
- if (prefs) {
- [prefs setObject:[NSArchiver archivedDataWithRootObject:[textView font]] forKey:@"CustomQueryEditorFont"];
- }
}
-
-
#pragma mark -
#pragma mark TableView notifications
@@ -1377,6 +1374,16 @@ traps enter key and
}
}
+/*
+ * Save the custom query editor font if it is changed.
+ */
+- (void)textViewDidChangeTypingAttributes:(NSNotification *)aNotification
+{
+
+ // Only save the font if prefs have been loaded, ensuring the saved font has been applied once.
+ if (prefs)
+ [prefs setObject:[NSArchiver archivedDataWithRootObject:[textView font]] forKey:@"CustomQueryEditorFont"];
+}
#pragma mark -
@@ -1403,6 +1410,7 @@ traps enter key and
*/
- (void)showHelpFor:(NSString *)searchString addToHistory:(BOOL)addToHistory
{
+
NSString * helpString = [self getHTMLformattedMySQLHelpFor:searchString];
// Order out resp. init the Help window if not visible
diff --git a/Source/NoodleLineNumberView.m b/Source/NoodleLineNumberView.m
index a4383102..1c5e8281 100644
--- a/Source/NoodleLineNumberView.m
+++ b/Source/NoodleLineNumberView.m
@@ -240,6 +240,14 @@
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)
+ {
+ NSLog(@"Line Numbering switched off. Text length larger than 6MB.");
+ return;
+ }
[lineIndices release];
lineIndices = [[NSMutableArray alloc] init];
diff --git a/Source/SPEditorTokens.h b/Source/SPEditorTokens.h
index 65aba747..efa7167c 100644
--- a/Source/SPEditorTokens.h
+++ b/Source/SPEditorTokens.h
@@ -13,7 +13,7 @@
#define SPT_BACKTICK_QUOTED_TEXT 4
#define SPT_RESERVED_WORD 5
#define SPT_WHITESPACE 6
-#define SPT_WORD 7
-#define SPT_OTHER 8
-#define SPT_NUMERIC 9
-#define SPT_VARIABLE 10
+#define SPT_NUMERIC 7
+#define SPT_VARIABLE 8
+#define SPT_WORD 9
+#define SPT_OTHER 10
diff --git a/Source/SPPreferenceController.h b/Source/SPPreferenceController.h
index cb12cde1..5f949a5f 100644
--- a/Source/SPPreferenceController.h
+++ b/Source/SPPreferenceController.h
@@ -35,6 +35,9 @@
IBOutlet NSView *favoritesView;
IBOutlet NSView *autoUpdateView;
IBOutlet NSView *networkView;
+ IBOutlet NSView *editorView;
+
+
IBOutlet NSPopUpButton *defaultFavoritePopup;
@@ -47,7 +50,9 @@
IBOutlet NSTextField *databaseField;
IBOutlet NSSecureTextField *passwordField;
KeyChain *keychain;
-
+
+ IBOutlet NSTextField *editorFontName;
+
NSToolbar *toolbar;
NSToolbarItem *generalItem;
@@ -56,6 +61,7 @@
NSToolbarItem *favoritesItem;
NSToolbarItem *autoUpdateItem;
NSToolbarItem *networkItem;
+ NSToolbarItem *editorItem;
NSUserDefaults *prefs;
}
@@ -68,6 +74,8 @@
- (IBAction)duplicateFavorite:(id)sender;
- (IBAction)saveFavorite:(id)sender;
- (IBAction)updateDefaultFavorite:(id)sender;
+- (IBAction)showCustomQueryFontPanel:(id)sender;
+- (IBAction)setDefaultColors:(id)sender;
// Toolbar item IBAction methods
- (IBAction)displayGeneralPreferences:(id)sender;
@@ -76,9 +84,11 @@
- (IBAction)displayNotificationPreferences:(id)sender;
- (IBAction)displayAutoUpdatePreferences:(id)sender;
- (IBAction)displayNetworkPreferences:(id)sender;
+- (IBAction)displayEditorPreferences:(id)sender;
// Other
- (void)updateDefaultFavoritePopup;
- (void)selectFavorites:(NSArray *)favorite;
+- (void)changeFont:(id)sender;
@end
diff --git a/Source/SPPreferenceController.m b/Source/SPPreferenceController.m
index 0d44a373..de17860c 100644
--- a/Source/SPPreferenceController.m
+++ b/Source/SPPreferenceController.m
@@ -25,6 +25,7 @@
#import "SPWindowAdditions.h"
#import "SPFavoriteTextFieldCell.h"
#import "KeyChain.h"
+#import "TableDocument.h"
#define FAVORITES_PB_DRAG_TYPE @"SequelProPreferencesPasteboard"
@@ -34,6 +35,7 @@
#define PREFERENCE_TOOLBAR_NOTIFICATIONS @"Preference Toolbar Notifications"
#define PREFERENCE_TOOLBAR_AUTOUPDATE @"Preference Toolbar Auto Update"
#define PREFERENCE_TOOLBAR_NETWORK @"Preference Toolbar Network"
+#define PREFERENCE_TOOLBAR_EDITOR @"Preference Toolbar Editor"
#pragma mark -
@@ -57,6 +59,7 @@
prefs = [NSUserDefaults standardUserDefaults];
[self applyRevisionChanges];
}
+
return self;
}
@@ -82,6 +85,8 @@
[favoritesTableView reloadData];
[self updateDefaultFavoritePopup];
+
+ [prefs synchronize];
}
#pragma mark -
@@ -355,6 +360,17 @@
}
// -------------------------------------------------------------------------------
+// displayEditorPreferences:
+// -------------------------------------------------------------------------------
+- (IBAction)displayEditorPreferences:(id)sender
+{
+ [toolbar setSelectedItemIdentifier:PREFERENCE_TOOLBAR_EDITOR];
+ NSFont *nf = [NSUnarchiver unarchiveObjectWithData:[prefs dataForKey:@"CustomQueryEditorFont"]];
+ [editorFontName setStringValue:[NSString stringWithFormat:@"%@, %.1f pt", [nf displayName], [nf pointSize]]];
+ [self _resizeWindowForContentView:editorView];
+}
+
+// -------------------------------------------------------------------------------
// displayFavoritePreferences:
// -------------------------------------------------------------------------------
- (IBAction)displayFavoritePreferences:(id)sender
@@ -567,6 +583,9 @@
else if ([itemIdentifier isEqualToString:PREFERENCE_TOOLBAR_NETWORK]) {
return networkItem;
}
+ else if ([itemIdentifier isEqualToString:PREFERENCE_TOOLBAR_EDITOR]) {
+ return editorItem;
+ }
return [[[NSToolbarItem alloc] initWithItemIdentifier:itemIdentifier] autorelease];
}
@@ -576,7 +595,7 @@
// -------------------------------------------------------------------------------
- (NSArray *)toolbarAllowedItemIdentifiers:(NSToolbar *)toolbar
{
- return [NSArray arrayWithObjects:PREFERENCE_TOOLBAR_GENERAL, PREFERENCE_TOOLBAR_TABLES, PREFERENCE_TOOLBAR_FAVORITES, PREFERENCE_TOOLBAR_NOTIFICATIONS, PREFERENCE_TOOLBAR_AUTOUPDATE, PREFERENCE_TOOLBAR_NETWORK, nil];
+ return [NSArray arrayWithObjects:PREFERENCE_TOOLBAR_GENERAL, PREFERENCE_TOOLBAR_TABLES, PREFERENCE_TOOLBAR_FAVORITES, PREFERENCE_TOOLBAR_NOTIFICATIONS, PREFERENCE_TOOLBAR_AUTOUPDATE, PREFERENCE_TOOLBAR_NETWORK, PREFERENCE_TOOLBAR_EDITOR, nil];
}
// -------------------------------------------------------------------------------
@@ -584,7 +603,7 @@
// -------------------------------------------------------------------------------
- (NSArray *)toolbarDefaultItemIdentifiers:(NSToolbar *)toolbar
{
- return [NSArray arrayWithObjects:PREFERENCE_TOOLBAR_GENERAL, PREFERENCE_TOOLBAR_TABLES, PREFERENCE_TOOLBAR_FAVORITES, PREFERENCE_TOOLBAR_NOTIFICATIONS, PREFERENCE_TOOLBAR_AUTOUPDATE, PREFERENCE_TOOLBAR_NETWORK, nil];
+ return [NSArray arrayWithObjects:PREFERENCE_TOOLBAR_GENERAL, PREFERENCE_TOOLBAR_TABLES, PREFERENCE_TOOLBAR_FAVORITES, PREFERENCE_TOOLBAR_NOTIFICATIONS, PREFERENCE_TOOLBAR_AUTOUPDATE, PREFERENCE_TOOLBAR_NETWORK, PREFERENCE_TOOLBAR_EDITOR, nil];
}
// -------------------------------------------------------------------------------
@@ -592,7 +611,7 @@
// -------------------------------------------------------------------------------
- (NSArray *)toolbarSelectableItemIdentifiers:(NSToolbar *)toolbar
{
- return [NSArray arrayWithObjects:PREFERENCE_TOOLBAR_GENERAL, PREFERENCE_TOOLBAR_TABLES, PREFERENCE_TOOLBAR_FAVORITES, PREFERENCE_TOOLBAR_NOTIFICATIONS, PREFERENCE_TOOLBAR_AUTOUPDATE, PREFERENCE_TOOLBAR_NETWORK, nil];
+ return [NSArray arrayWithObjects:PREFERENCE_TOOLBAR_GENERAL, PREFERENCE_TOOLBAR_TABLES, PREFERENCE_TOOLBAR_FAVORITES, PREFERENCE_TOOLBAR_NOTIFICATIONS, PREFERENCE_TOOLBAR_AUTOUPDATE, PREFERENCE_TOOLBAR_NETWORK, PREFERENCE_TOOLBAR_EDITOR, nil];
}
#pragma mark -
@@ -683,6 +702,7 @@
// Mark the currently selected field in the window as having finished editing, to trigger saves.
if ([preferencesWindow firstResponder])
[preferencesWindow endEditingFor:[preferencesWindow firstResponder]];
+
}
#pragma mark -
@@ -729,6 +749,43 @@
}
// -------------------------------------------------------------------------------
+// query editor font selection
+//
+// -------------------------------------------------------------------------------
+// show the font panel
+- (IBAction)showCustomQueryFontPanel:(id)sender
+{
+ [[NSFontPanel sharedFontPanel] setPanelFont:[NSUnarchiver unarchiveObjectWithData:[prefs dataForKey:@"CustomQueryEditorFont"]] isMultiple:NO];
+ [[NSFontPanel sharedFontPanel] makeKeyAndOrderFront:self];
+}
+// reset syntax highlighting colors
+- (IBAction)setDefaultColors:(id)sender
+{
+
+ [prefs setObject:[NSArchiver archivedDataWithRootObject:[NSColor colorWithDeviceRed:0.000 green:0.455 blue:0.000 alpha:1.000]] forKey:@"CustomQueryEditorCommentColor"];
+ [prefs setObject:[NSArchiver archivedDataWithRootObject:[NSColor colorWithDeviceRed:0.769 green:0.102 blue:0.086 alpha:1.000]] forKey:@"CustomQueryEditorQuoteColor"];
+ [prefs setObject:[NSArchiver archivedDataWithRootObject:[NSColor colorWithDeviceRed:0.200 green:0.250 blue:1.000 alpha:1.000]] forKey:@"CustomQueryEditorSQLKeywordColor"];
+ [prefs setObject:[NSArchiver archivedDataWithRootObject:[NSColor colorWithDeviceRed:0.000 green:0.000 blue:0.658 alpha:1.000]] forKey:@"CustomQueryEditorBacktickColor"];
+ [prefs setObject:[NSArchiver archivedDataWithRootObject:[NSColor colorWithDeviceRed:0.506 green:0.263 blue:0.000 alpha:1.000]] forKey:@"CustomQueryEditorNumericColor"];
+ [prefs setObject:[NSArchiver archivedDataWithRootObject:[NSColor colorWithDeviceRed:0.500 green:0.500 blue:0.500 alpha:1.000]] forKey:@"CustomQueryEditorVariableColor"];
+ [prefs setObject:[NSArchiver archivedDataWithRootObject:[NSColor blackColor]] forKey:@"CustomQueryEditorTextColor"];
+ [prefs setObject:[NSArchiver archivedDataWithRootObject:[NSColor whiteColor]] forKey:@"CustomQueryEditorBackgroundColor"];
+
+}
+// set font panel's valid modes
+- (unsigned int)validModesForFontPanel:(NSFontPanel *)fontPanel
+{
+ return (NSFontPanelFaceModeMask | NSFontPanelSizeModeMask);
+}
+// Action receiver for a font change in the font panel
+- (void)changeFont:(id)sender
+{
+ NSFont *nf = [[NSFontPanel sharedFontPanel] panelConvertFont:[NSUnarchiver unarchiveObjectWithData:[prefs dataForKey:@"CustomQueryEditorFont"]]];
+ [prefs setObject:[NSArchiver archivedDataWithRootObject:nf] forKey:@"CustomQueryEditorFont"];
+ [editorFontName setStringValue:[NSString stringWithFormat:@"%@, %.1f pt", [nf displayName], [nf pointSize]]];
+}
+
+// -------------------------------------------------------------------------------
// dealloc
// -------------------------------------------------------------------------------
- (void)dealloc
@@ -752,62 +809,71 @@
- (void)_setupToolbar
{
toolbar = [[[NSToolbar alloc] initWithIdentifier:@"Preference Toolbar"] autorelease];
-
+
// General preferences
generalItem = [[NSToolbarItem alloc] initWithItemIdentifier:PREFERENCE_TOOLBAR_GENERAL];
-
+
[generalItem setLabel:NSLocalizedString(@"General", @"")];
- [generalItem setImage:[NSImage imageNamed:@"toolbar-preferences-general"]];
- [generalItem setTarget:self];
- [generalItem setAction:@selector(displayGeneralPreferences:)];
-
+ [generalItem setImage:[NSImage imageNamed:@"toolbar-preferences-general"]];
+ [generalItem setTarget:self];
+ [generalItem setAction:@selector(displayGeneralPreferences:)];
+
// Table preferences
tablesItem = [[NSToolbarItem alloc] initWithItemIdentifier:PREFERENCE_TOOLBAR_TABLES];
-
+
[tablesItem setLabel:NSLocalizedString(@"Tables", @"")];
[tablesItem setImage:[NSImage imageNamed:@"toolbar-preferences-tables"]];
[tablesItem setTarget:self];
[tablesItem setAction:@selector(displayTablePreferences:)];
-
+
// Favorite preferences
favoritesItem = [[NSToolbarItem alloc] initWithItemIdentifier:PREFERENCE_TOOLBAR_FAVORITES];
-
+
[favoritesItem setLabel:NSLocalizedString(@"Favorites", @"")];
- [favoritesItem setImage:[NSImage imageNamed:@"toolbar-preferences-favorites"]];
- [favoritesItem setTarget:self];
- [favoritesItem setAction:@selector(displayFavoritePreferences:)];
-
+ [favoritesItem setImage:[NSImage imageNamed:@"toolbar-preferences-favorites"]];
+ [favoritesItem setTarget:self];
+ [favoritesItem setAction:@selector(displayFavoritePreferences:)];
+
// Notification preferences
notificationsItem = [[NSToolbarItem alloc] initWithItemIdentifier:PREFERENCE_TOOLBAR_NOTIFICATIONS];
-
+
[notificationsItem setLabel:NSLocalizedString(@"Notifications", @"")];
- [notificationsItem setImage:[NSImage imageNamed:@"toolbar-preferences-notifications"]];
- [notificationsItem setTarget:self];
- [notificationsItem setAction:@selector(displayNotificationPreferences:)];
+ [notificationsItem setImage:[NSImage imageNamed:@"toolbar-preferences-notifications"]];
+ [notificationsItem setTarget:self];
+ [notificationsItem setAction:@selector(displayNotificationPreferences:)];
// AutoUpdate preferences
autoUpdateItem = [[NSToolbarItem alloc] initWithItemIdentifier:PREFERENCE_TOOLBAR_AUTOUPDATE];
-
+
[autoUpdateItem setLabel:NSLocalizedString(@"Auto Update", @"")];
- [autoUpdateItem setImage:[NSImage imageNamed:@"toolbar-preferences-autoupdate"]];
- [autoUpdateItem setTarget:self];
- [autoUpdateItem setAction:@selector(displayAutoUpdatePreferences:)];
-
+ [autoUpdateItem setImage:[NSImage imageNamed:@"toolbar-preferences-autoupdate"]];
+ [autoUpdateItem setTarget:self];
+ [autoUpdateItem setAction:@selector(displayAutoUpdatePreferences:)];
+
// Network preferences
networkItem = [[NSToolbarItem alloc] initWithItemIdentifier:PREFERENCE_TOOLBAR_NETWORK];
-
+
[networkItem setLabel:NSLocalizedString(@"Network", @"")];
- [networkItem setImage:[NSImage imageNamed:@"toolbar-preferences-network"]];
- [networkItem setTarget:self];
- [networkItem setAction:@selector(displayNetworkPreferences:)];
-
+ [networkItem setImage:[NSImage imageNamed:@"toolbar-preferences-network"]];
+ [networkItem setTarget:self];
+ [networkItem setAction:@selector(displayNetworkPreferences:)];
+
+ // Editor preferences
+ editorItem = [[NSToolbarItem alloc] initWithItemIdentifier:PREFERENCE_TOOLBAR_EDITOR];
+
+ [editorItem setLabel:NSLocalizedString(@"Query Editor", @"")];
+ [editorItem setImage:[NSImage imageNamed:@"toolbar-switch-to-sql"]];
+ [editorItem setTarget:self];
+ [editorItem setAction:@selector(displayEditorPreferences:)];
+
+
[toolbar setDelegate:self];
[toolbar setSelectedItemIdentifier:PREFERENCE_TOOLBAR_GENERAL];
[toolbar setAllowsUserCustomization:NO];
-
+
[preferencesWindow setToolbar:toolbar];
[preferencesWindow setShowsToolbarButton:NO];
-
+
[self displayGeneralPreferences:nil];
}