From cca4f8dc17e904c516dc7e3ba8193aff5b8f9e70 Mon Sep 17 00:00:00 2001 From: Bibiko Date: Sun, 24 Jan 2010 21:39:43 +0000 Subject: =?UTF-8?q?=E2=80=A2=20added=20possibility=20to=20add=20a=20query?= =?UTF-8?q?=20favorite=20by=20user-definable=20alphanumeric=20tab=20trigge?= =?UTF-8?q?r;=20eg=20if=20tab=20trigger=20is=20set=20to=20"sel"=20sel?= =?UTF-8?q?=E2=87=A5=20will=20insert=20the=20first=20query=20which=20has?= =?UTF-8?q?=20the=20defined=20the=20tab=20trigger=20=E2=80=A2=20preparatio?= =?UTF-8?q?ns=20to=20insert=20programmable=20query=20favorites=20-=20eg=20?= =?UTF-8?q?"SELECT=20${*}=20FROM=20${Table}"=20--=20after=20insertion=20"S?= =?UTF-8?q?ELECT=20*=20FROM=20Table"=20the=20'*'=20is=20highlighted=20to?= =?UTF-8?q?=20change,=20press=20=E2=87=A5=20to=20select=20the=20next=20sni?= =?UTF-8?q?ppet=20'Table';=20=E2=87=A7=E2=87=A5=20selects=20the=20previous?= =?UTF-8?q?=20snippet;=20the=20snippet=20selection=20follows=20the=20user?= =?UTF-8?q?=20input=20-=20Note:=20not=20yet=20active?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Source/CMTextView.h | 8 +++ Source/CMTextView.m | 148 +++++++++++++++++++++++++++++++++++++++- Source/CustomQuery.m | 24 ++++++- Source/SPQueryController.m | 4 +- Source/SPQueryFavoriteManager.h | 1 + Source/SPQueryFavoriteManager.m | 20 +++++- 6 files changed, 196 insertions(+), 9 deletions(-) (limited to 'Source') diff --git a/Source/CMTextView.h b/Source/CMTextView.h index 868e7093..137c5348 100644 --- a/Source/CMTextView.h +++ b/Source/CMTextView.h @@ -59,6 +59,11 @@ static inline void NSMutableAttributedStringAddAttributeValueRange (NSMutableAtt MCPConnection *mySQLConnection; NSInteger mySQLmajorVersion; + NSInteger snippetControlArray[20][2]; + NSInteger snippetControlCounter; + NSInteger currentSnippetIndex; + BOOL snippetWasJustInserted; + } - (IBAction)showMySQLHelpForCurrentWord:(id)sender; @@ -91,6 +96,9 @@ static inline void NSMutableAttributedStringAddAttributeValueRange (NSMutableAtt - (NSArray *)suggestionsForSQLCompletionWith:(NSString *)currentWord dictMode:(BOOL)isDictMode browseMode:(BOOL)dbBrowseMode withTableName:(NSString*)aTableName withDbName:(NSString*)aDbName; - (void) selectCurrentQuery; +- (BOOL)checkForCaretInsideSnippet; +- (void)insertFavoriteAsSnippet:(NSString*)theSnippet atRange:(NSRange)targetRange; + - (NSUInteger)characterIndexOfPoint:(NSPoint)aPoint; - (void)insertFileContentOfFile:(NSString *)aPath; diff --git a/Source/CMTextView.m b/Source/CMTextView.m index 4b42d009..26c5790d 100644 --- a/Source/CMTextView.m +++ b/Source/CMTextView.m @@ -30,6 +30,7 @@ #import "SPTextViewAdditions.h" #import "SPNarrowDownCompletion.h" #import "SPConstants.h" +#import "SPQueryController.h" #pragma mark - #pragma mark lex init @@ -86,6 +87,7 @@ YY_BUFFER_STATE yy_scan_string (const char *); autohelpEnabled = NO; delBackwardsWasPressed = NO; startListeningToBoundChanges = NO; + snippetControlCounter = -1; lineNumberView = [[NoodleLineNumberView alloc] initWithScrollView:scrollView]; [scrollView setVerticalRulerView:lineNumberView]; @@ -796,6 +798,74 @@ NSInteger alphabeticSort(id string1, id string2, void *reverse) } +- (void)selectCurrentSnippet +{ + if(snippetControlCounter > -1) + [self setSelectedRange:NSMakeRange(snippetControlArray[currentSnippetIndex][0], snippetControlArray[currentSnippetIndex][1])]; +} + +- (void)insertFavoriteAsSnippet:(NSString*)theSnippet atRange:(NSRange)targetRange +{ + + if(theSnippet == nil || ![theSnippet length]) return; + + NSMutableString *snip = [[NSMutableString string] autorelease]; + // NSString *re = @"(? -1) { + // // Store the end for eventually tab out + // snippetControlCounter++; + // snippetControlArray[snippetControlCounter][0] = targetRange.location + [snip length]; + // snippetControlArray[snippetControlCounter][1] = 0; + // } + + [self breakUndoCoalescing]; + [self setSelectedRange:targetRange]; + snippetWasJustInserted = YES; + [self insertText:snip]; + + currentSnippetIndex = 0; + if(snippetControlCounter > -1) + [self selectCurrentSnippet]; + + snippetWasJustInserted = NO; +} + +- (BOOL)checkForCaretInsideSnippet +{ + + if(snippetControlCounter < 0 || currentSnippetIndex == snippetControlCounter) { + snippetControlCounter = -1; + return NO; + } + + BOOL isCaretInsideASnippet = NO; + NSInteger caretPos = [self selectedRange].location; + NSInteger i; + + for(i=0; i= snippetControlArray[i][0] + && caretPos <= snippetControlArray[i][0] + snippetControlArray[i][1]) { + + isCaretInsideASnippet = YES; + break; + } + } + // if(!isCaretInsideASnippet) + // snippetControlCounter = -1; + return isCaretInsideASnippet; +} /* * Handle some keyDown events in order to provide autopairing functionality (if enabled). */ @@ -839,6 +909,45 @@ NSInteger alphabeticSort(id string1, id string2, void *reverse) return; } + // Check for {SHIFT}TAB to insert favorites via TAB-trigger if CMTextView belongs to CustomQuery + if ([theEvent keyCode] == 48 && [self isEditable] && [[self delegate] isKindOfClass:[CustomQuery class]]){ + NSRange targetRange = [self getRangeForCurrentWord]; + NSString *tabTrigger = [[self string] substringWithRange:targetRange]; + + // Is TAB trigger active change selection according to {SHIFT}TAB + if(snippetControlCounter > -1 && [self checkForCaretInsideSnippet]){ + if(curFlags==(NSShiftKeyMask)) { + currentSnippetIndex--; + if(currentSnippetIndex < 0) { + snippetControlCounter = -1; + } else { + [self selectCurrentSnippet]; + return; + } + } else { + currentSnippetIndex++; + if(currentSnippetIndex > snippetControlCounter) { + snippetControlCounter = -1; + } else if(currentSnippetIndex == snippetControlCounter) { + [self selectCurrentSnippet]; + snippetControlCounter = -1; + return; + } else { + [self selectCurrentSnippet]; + return; + } + } + } + // Check if tab-trigger is defined; if so insert it + if(snippetControlCounter < 0 && [[[self window] delegate] fileURL]) { + NSArray *snippets = [[SPQueryController sharedQueryController] queryFavoritesForFileURL:[[[self window] delegate] fileURL] andTabTrigger:tabTrigger includeGlobals:YES]; + if([snippets count] > 0 && [(NSString*)[(NSDictionary*)[snippets objectAtIndex:0] objectForKey:@"query"] length]) { + [self insertFavoriteAsSnippet:[(NSDictionary*)[snippets objectAtIndex:0] objectForKey:@"query"] atRange:targetRange]; + return; + } + } + } + // Note: switch(insertedCharacter) {} does not work instead use charactersIgnoringModifiers if([charactersIgnMod isEqualToString:@"c"]) // ^C copy as RTF if(curFlags==(NSControlKeyMask)) @@ -2719,9 +2828,12 @@ NSInteger alphabeticSort(id string1, id string2, void *reverse) //make sure that the notification is from the correct textStorage object if (textStore!=[self textStorage]) return; + NSInteger editedMask = [textStore editedMask]; + // Start autohelp only if the user really changed the text (not e.g. for setting a background color) - if([prefs boolForKey:SPCustomQueryUpdateAutoHelp] && [textStore editedMask] != 1) + if([prefs boolForKey:SPCustomQueryUpdateAutoHelp] && editedMask != 1) { [self performSelector:@selector(autoHelp) withObject:nil afterDelay:[[[prefs valueForKey:SPCustomQueryAutoHelpDelay] retain] doubleValue]]; + } if([[self string] length] > SP_TEXT_SIZE_TRIGGER_FOR_PARTLY_PARSING) [NSObject cancelPreviousPerformRequestsWithTarget:self @@ -2729,8 +2841,40 @@ NSInteger alphabeticSort(id string1, id string2, void *reverse) object:nil]; // Do syntax highlighting only if the user really changed the text - if([textStore editedMask] != 1){ + if(editedMask != 1) { + + if(snippetControlCounter > -1 && !snippetWasJustInserted) { + NSInteger editStartPosition = [textStore editedRange].location; + NSInteger changeInLength = [textStore changeInLength]; + NSInteger i; + BOOL isCaretInsideASnippet = NO; + for(i=0; i<=snippetControlCounter; i++) { + if(editStartPosition >= snippetControlArray[i][0] + && editStartPosition <= snippetControlArray[i][0] + snippetControlArray[i][1]) { + + if(i!=snippetControlCounter) + isCaretInsideASnippet = YES; + snippetControlArray[i][1] += changeInLength; + if(snippetControlArray[i][1] < 0) { + snippetControlCounter = -1; + break; + } + // Adjust start position of snippets after caret position + } else if(editStartPosition < snippetControlArray[i][0]) { + snippetControlArray[i][0] += changeInLength; + if(snippetControlArray[i][1] < 0) { + snippetControlCounter = -1; + break; + } + } + } + if(!isCaretInsideASnippet) + snippetControlCounter = -1; + + } + [self doSyntaxHighlighting]; + } startListeningToBoundChanges = YES; diff --git a/Source/CustomQuery.m b/Source/CustomQuery.m index b536491b..2e3b16c4 100644 --- a/Source/CustomQuery.m +++ b/Source/CustomQuery.m @@ -215,7 +215,7 @@ [textView setSelectedRange:NSMakeRange(0,[[textView string] length])]; // The actual query strings have been already stored as tooltip - [textView insertText:[[queryFavoritesButton selectedItem] toolTip]]; + [textView insertFavoriteAsSnippet:[[queryFavoritesButton selectedItem] toolTip] atRange:[textView selectedRange]]; } } @@ -2020,6 +2020,7 @@ // Ensure that the notification is from the custom query text view if ( [aNotification object] != textView ) return; + [textView checkForCaretInsideSnippet]; // Remove all background color attributes used by highlighting the current query if([prefs boolForKey:SPCustomQueryHighlightCurrentQuery]) { // Remove only the background attribute for the current range if still valid @@ -2701,8 +2702,17 @@ [menu addItem:headerMenuItem]; [headerMenuItem release]; for (NSDictionary *favorite in [[SPQueryController sharedQueryController] favoritesForFileURL:[tableDocumentInstance fileURL]]) { - NSMenuItem *item = [[NSMenuItem alloc] initWithTitle:[NSString stringWithString:[favorite objectForKey:@"name"]] action:NULL keyEquivalent:@""]; + if (![favorite isKindOfClass:[NSDictionary class]] || ![favorite objectForKey:@"name"]) continue; + NSMutableParagraphStyle *paraStyle = [[[NSMutableParagraphStyle alloc] init] autorelease]; + [paraStyle setTabStops:[NSArray array]]; + [paraStyle addTabStop:[[[NSTextTab alloc] initWithType:NSRightTabStopType location:190.0] autorelease]]; + NSDictionary *attributes = [NSDictionary dictionaryWithObjects:[NSArray arrayWithObjects:paraStyle, [NSFont systemFontOfSize:11], nil] forKeys:[NSArray arrayWithObjects:NSParagraphStyleAttributeName, NSFontAttributeName, nil]]; + NSAttributedString *titleString = [[[NSAttributedString alloc] + initWithString:([favorite objectForKey:@"tabtrigger"] && [(NSString*)[favorite objectForKey:@"tabtrigger"] length]) ? [NSString stringWithFormat:@"%@\t%@⇥", [favorite objectForKey:@"name"], [favorite objectForKey:@"tabtrigger"]] : [favorite objectForKey:@"name"] + attributes:attributes] autorelease]; + NSMenuItem *item = [[NSMenuItem alloc] initWithTitle:@"" action:NULL keyEquivalent:@""]; [item setToolTip:[NSString stringWithString:[favorite objectForKey:@"query"]]]; + [item setAttributedTitle:titleString]; [item setIndentationLevel:1]; [menu addItem:item]; [item release]; @@ -2717,8 +2727,16 @@ [headerMenuItem release]; for (NSDictionary *favorite in [prefs objectForKey:SPQueryFavorites]) { if (![favorite isKindOfClass:[NSDictionary class]] || ![favorite objectForKey:@"name"]) continue; - NSMenuItem *item = [[NSMenuItem alloc] initWithTitle:[NSString stringWithString:[favorite objectForKey:@"name"]] action:NULL keyEquivalent:@""]; + NSMutableParagraphStyle *paraStyle = [[[NSMutableParagraphStyle alloc] init] autorelease]; + [paraStyle setTabStops:[NSArray array]]; + [paraStyle addTabStop:[[[NSTextTab alloc] initWithType:NSRightTabStopType location:190.0] autorelease]]; + NSDictionary *attributes = [NSDictionary dictionaryWithObjects:[NSArray arrayWithObjects:paraStyle, [NSFont systemFontOfSize:11], nil] forKeys:[NSArray arrayWithObjects:NSParagraphStyleAttributeName, NSFontAttributeName, nil]]; + NSAttributedString *titleString = [[[NSAttributedString alloc] + initWithString:([favorite objectForKey:@"tabtrigger"] && [(NSString*)[favorite objectForKey:@"tabtrigger"] length]) ? [NSString stringWithFormat:@"%@\t%@⇥", [favorite objectForKey:@"name"], [favorite objectForKey:@"tabtrigger"]] : [favorite objectForKey:@"name"] + attributes:attributes] autorelease]; + NSMenuItem *item = [[NSMenuItem alloc] initWithTitle:@"" action:NULL keyEquivalent:@""]; [item setToolTip:[NSString stringWithString:[favorite objectForKey:@"query"]]]; + [item setAttributedTitle:titleString]; [item setIndentationLevel:1]; [menu addItem:item]; [item release]; diff --git a/Source/SPQueryController.m b/Source/SPQueryController.m index 37b4aa97..9f28c226 100644 --- a/Source/SPQueryController.m +++ b/Source/SPQueryController.m @@ -664,8 +664,10 @@ static SPQueryController *sharedQueryController = nil; if(includeGlobals && [prefs objectForKey:SPQueryFavorites]) { for(id fav in [prefs objectForKey:SPQueryFavorites]) { - if([fav objectForKey:@"tabtrigger"] && [[fav objectForKey:@"tabtrigger"] isEqualToString:tabTrigger]) + if([fav objectForKey:@"tabtrigger"] && [[fav objectForKey:@"tabtrigger"] isEqualToString:tabTrigger]) { [result addObject:fav]; + break; + } } } diff --git a/Source/SPQueryFavoriteManager.h b/Source/SPQueryFavoriteManager.h index 9318ed22..2a9c3c56 100644 --- a/Source/SPQueryFavoriteManager.h +++ b/Source/SPQueryFavoriteManager.h @@ -41,6 +41,7 @@ IBOutlet NSPopUpButton *encodingPopUp; IBOutlet NSTableView *favoritesTableView; IBOutlet NSTextField *favoriteNameTextField; + IBOutlet NSTextField *favoriteTabTriggerTextField; IBOutlet NSTextView *favoriteQueryTextView; IBOutlet NSButton *removeButton; IBOutlet BWAnchoredButtonBar *splitViewButtonBar; diff --git a/Source/SPQueryFavoriteManager.m b/Source/SPQueryFavoriteManager.m index 2745f83c..a6f8941b 100644 --- a/Source/SPQueryFavoriteManager.m +++ b/Source/SPQueryFavoriteManager.m @@ -29,6 +29,7 @@ #import "SPQueryController.h" #import "SPConstants.h" #import "SPConnectionController.h" +#import "RegexKitLite.h" #define SP_MULTIPLE_SELECTION_PLACEHOLDER_STRING NSLocalizedString(@"[multiple selection]", @"[multiple selection]") #define SP_NO_SELECTION_PLACEHOLDER_STRING NSLocalizedString(@"[no selection]", @"[no selection]") @@ -415,9 +416,15 @@ */ - (id)tableView:(NSTableView *)aTableView objectValueForTableColumn:(NSTableColumn *)aTableColumn row:(NSInteger)rowIndex { - if(![[favorites objectAtIndex:rowIndex] objectForKey:[aTableColumn identifier]]) return @""; - return [[favorites objectAtIndex:rowIndex] objectForKey:[aTableColumn identifier]]; + if([[aTableColumn identifier] isEqualToString:@"name"]) { + if(![[favorites objectAtIndex:rowIndex] objectForKey:@"name"]) return @""; + return [[favorites objectAtIndex:rowIndex] objectForKey:@"name"]; + } else if([[aTableColumn identifier] isEqualToString:@"tabtrigger"]) { + if(![[favorites objectAtIndex:rowIndex] objectForKey:@"tabtrigger"] || ![(NSString*)[[favorites objectAtIndex:rowIndex] objectForKey:@"tabtrigger"] length]) return @""; + return [NSString stringWithFormat:@"%@⇥", [[favorites objectAtIndex:rowIndex] objectForKey:@"tabtrigger"]]; + } + return @""; } /* @@ -511,7 +518,7 @@ } /* - * Changes in the name text field will be saved in data source directly + * Changes in the name/tabtrigger text field will be saved in data source directly * to update the table view accordingly */ - (void)controlTextDidChange:(NSNotification *)notification @@ -525,6 +532,13 @@ if(object == favoriteNameTextField) { [[favorites objectAtIndex:[favoritesTableView selectedRow]] setObject:[favoriteNameTextField stringValue] forKey:@"name"]; [favoritesTableView reloadData]; + } + else if(object == favoriteTabTriggerTextField){ + //Validate trigger - it only may contain alphnumeric characters + NSString *tabTrigger = [NSString stringWithString:[[favoriteTabTriggerTextField stringValue] stringByReplacingOccurrencesOfRegex:@"[^\\w0-9]" withString:@""]]; + [favoriteTabTriggerTextField setStringValue:tabTrigger]; + [[favorites objectAtIndex:[favoritesTableView selectedRow]] setObject:tabTrigger forKey:@"tabtrigger"]; + [favoritesTableView reloadData]; } } -- cgit v1.2.3