aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBibiko <bibiko@eva.mpg.de>2010-11-10 12:00:59 +0000
committerBibiko <bibiko@eva.mpg.de>2010-11-10 12:00:59 +0000
commit169fb3fffeff55cff32952a82adba055dfc050f9 (patch)
tree9c5bbf82e8971b31318c418556b8a8dee2d0a205
parentc3abe91fddf71117244fb57d55214d5621f79862 (diff)
downloadsequelpro-169fb3fffeff55cff32952a82adba055dfc050f9.tar.gz
sequelpro-169fb3fffeff55cff32952a82adba055dfc050f9.tar.bz2
sequelpro-169fb3fffeff55cff32952a82adba055dfc050f9.zip
• first implementation to allow the user to write and use self-definable functions inside the Custom Query Editor
- such commands will be stored as foo.spBundle in SP's Application Folder/Bundles - up to now they will be displayed inside the context menu as submenu Bundles which can be by itself contain further submenus specified via 'category' key - to each command the user can assign a tooltip and a keyboard short-cut; if user chose a standard SP short-cut it will be ignored - commands will be executed as bash commands ie it can also be written in any script language - the bash process inherits several environment variables like SP_BUNDLE_PATH, SP_SELECTED_TEXT, SP_SELECTED_DATABASE, SP_SELECTED_TABLE, SP_CURRENT_QUERY, SP_CURRENT_LINE, SP_CURRENT_WORD - the bash command's result can be processed as follows: insertAsText, insertAsSnippet, replaceContent, replaceSeletion (with fallbacks to word, line, query, entire content), showAsTextTooltip, showAsHTMLTooltip - up to now all installed bundles are reload for each menuForEvent: [this is tendative!] - each spBundle command has a scope to allow to the user to specify for which SP element a command can be useful; up to now only the scope 'editor' is supported; further scopes could be 'data table' for context menus of mysql table data (Content or Custom Query - including info of selected lines, table data in different formats, etc.) - foo.spBundle files can be installed simply by double-clicking at it (remember up to now Bundles will be reloaded while opening the editor's context menu!) two tiny examples for testing: http://wwwstaff.eva.mpg.de/~bibiko/dt/temp/spBundleExamples.zip
-rw-r--r--Source/SPDatabaseDocument.m4
-rw-r--r--Source/SPTextView.m154
2 files changed, 151 insertions, 7 deletions
diff --git a/Source/SPDatabaseDocument.m b/Source/SPDatabaseDocument.m
index 75a16e73..f3f419d8 100644
--- a/Source/SPDatabaseDocument.m
+++ b/Source/SPDatabaseDocument.m
@@ -241,7 +241,9 @@
[taskProgressWindow setAlphaValue:0.0];
[taskProgressWindow setContentView:taskProgressLayer];
- [contentViewSplitter setDelegate:self];
+ [[customQueryInstance valueForKeyPath:@"textView"] reloadBundleItems];
+
+ [contentViewSplitter setDelegate:self];
}
/**
diff --git a/Source/SPTextView.m b/Source/SPTextView.m
index 32edf6f1..9de1d0af 100644
--- a/Source/SPTextView.m
+++ b/Source/SPTextView.m
@@ -2129,7 +2129,7 @@ NSInteger alphabeticSort(id string1, id string2, void *reverse)
if([bundleKeyEquivalents count]) {
for(NSString* key in [bundleKeyEquivalents allKeys]) {
NSArray *keyData = [bundleKeyEquivalents objectForKey:key];
- if([[keyData objectAtIndex:0] isEqualToString:charactersIgnMod] && [[[bundleKeyEquivalents objectForKey:key] objectAtIndex:1] intValue] & curFlags) {
+ if([[keyData objectAtIndex:0] isEqualToString:charactersIgnMod] && [[[bundleKeyEquivalents objectForKey:key] objectAtIndex:1] intValue] == curFlags) {
NSMenuItem *item = [[[NSMenuItem alloc] init] autorelease];
[item setToolTip:[[bundleKeyEquivalents objectForKey:key] objectAtIndex:2]];
[item setTag:0];
@@ -3448,12 +3448,13 @@ NSInteger alphabeticSort(id string1, id string2, void *reverse)
if([cmdData objectForKey:@"keyEquivalent"] && [[cmdData objectForKey:@"keyEquivalent"] length]) {
NSString *theKey = [cmdData objectForKey:@"keyEquivalent"];
NSString *theChar = [theKey substringFromIndex:[theKey length]-1];
+ NSString *theMods = [theKey substringToIndex:[theKey length]-1];
NSUInteger mask = 0;
- if([theKey rangeOfString:@"^"].length)
+ if([theMods rangeOfString:@"^"].length)
mask = mask | NSControlKeyMask;
- if([theKey rangeOfString:@"@"].length)
+ if([theMods rangeOfString:@"@"].length)
mask = mask | NSCommandKeyMask;
- if([theKey rangeOfString:@"~"].length)
+ if([theMods rangeOfString:@"~"].length)
mask = mask | NSAlternateKeyMask;
if(![[theChar lowercaseString] isEqualToString:theChar])
mask = mask | NSShiftKeyMask;
@@ -3480,13 +3481,154 @@ NSInteger alphabeticSort(id string1, id string2, void *reverse)
- (IBAction)executeBundleItem:(id)sender
{
NSInteger idx = [sender tag] - 1000000;
+ NSString *infoPath = nil;
if(idx >=0 && idx < [bundleItems count]) {
- NSLog(@"%@", [[bundleItems objectAtIndex:idx] objectForKey:@"path"]);
+ infoPath = [[bundleItems objectAtIndex:idx] objectForKey:@"path"];
} else {
if([sender tag] == 0 && [[sender toolTip] length]) {
- NSLog(@"%@", [sender toolTip]);
+ infoPath = [sender toolTip];
}
}
+
+ if(!infoPath) {
+ NSBeep();
+ return;
+ }
+
+ NSError *readError = nil;
+ NSString *convError = nil;
+ NSPropertyListFormat format;
+ NSDictionary *cmdData = nil;
+ NSData *pData = [NSData dataWithContentsOfFile:infoPath options:NSUncachedRead error:&readError];
+
+ cmdData = [[NSPropertyListSerialization propertyListFromData:pData
+ mutabilityOption:NSPropertyListImmutable format:&format errorDescription:&convError] retain];
+
+ if(!cmdData || readError != nil || [convError length] || !(format == NSPropertyListXMLFormat_v1_0 || format == NSPropertyListBinaryFormat_v1_0)) {
+ NSLog(@"“%@” file couldn't be read.", infoPath);
+ NSBeep();
+ if (cmdData) [cmdData release];
+ return;
+ } else {
+ if([cmdData objectForKey:@"command"] && [[cmdData objectForKey:@"command"] length]) {
+
+ NSString *cmd = [cmdData objectForKey:@"command"];
+ NSError *err = nil;
+ NSRange currentWordRange, currentQueryRange, currentSelectionRange, currentLineRange;
+
+ NSMutableDictionary *env = [NSMutableDictionary dictionary];
+ [env setObject:[infoPath stringByDeletingLastPathComponent] forKey:@"SP_BUNDLE_PATH"];
+
+ currentSelectionRange = [self selectedRange];
+ if(currentSelectionRange.length)
+ [env setObject:[[self string] substringWithRange:currentSelectionRange] forKey:@"SP_SELECTED_TEXT"];
+
+ if (tablesListInstance && [tablesListInstance selectedDatabase])
+ [env setObject:[tablesListInstance selectedDatabase] forKey:@"SP_SELECTED_DATABASE"];
+
+ if (tablesListInstance && [tablesListInstance tableName])
+ [env setObject:[tablesListInstance tableName] forKey:@"SP_SELECTED_TABLE"];
+
+
+ if(customQueryInstance && [customQueryInstance currentQueryRange].length) {
+ currentQueryRange = [customQueryInstance currentQueryRange];
+ [env setObject:[[self string] substringWithRange:[customQueryInstance currentQueryRange]] forKey:@"SP_CURRENT_QUERY"];
+ } else {
+ currentQueryRange = currentSelectionRange;
+ }
+
+ currentWordRange = [self getRangeForCurrentWord];
+ if(currentWordRange.length)
+ [env setObject:[[self string] substringWithRange:currentWordRange] forKey:@"SP_CURRENT_WORD"];
+
+ currentLineRange = [[self string] lineRangeForRange:NSMakeRange([self selectedRange].location, 0)];
+ if(currentLineRange.length)
+ [env setObject:[[self string] substringWithRange:currentLineRange] forKey:@"SP_CURRENT_LINE"];
+
+ NSString *output = [cmd runBashCommandWithEnvironment:env atCurrentDirectoryPath:nil error:&err];
+
+ if(err == nil && [cmdData objectForKey:@"output"] && [[cmdData objectForKey:@"output"] length] && ![[cmdData objectForKey:@"output"] isEqualToString:@"nop"]) {
+ NSString *action = [[cmdData objectForKey:@"output"] lowercaseString];
+
+ if([action isEqualToString:@"insertastext"]) {
+ [self insertText:output];
+ }
+
+ else if([action isEqualToString:@"insertassnippet"]) {
+ NSString *inputAction = @"";
+ NSString *inputFallBackAction = @"";
+ if([cmdData objectForKey:@"input"])
+ inputAction = [[cmdData objectForKey:@"input"] lowercaseString];
+ if([cmdData objectForKey:@"input_fallback"])
+ inputFallBackAction = [[cmdData objectForKey:@"input_fallback"] lowercaseString];
+ NSRange replaceRange = NSMakeRange(currentSelectionRange.location, 0);
+ if([inputAction isEqualToString:@"selectedtext"]) {
+ if(!currentSelectionRange.length) {
+ if([inputFallBackAction isEqualToString:@"currentword"])
+ replaceRange = currentWordRange;
+ else if([inputFallBackAction isEqualToString:@"currentline"])
+ replaceRange = currentLineRange;
+ else if([inputFallBackAction isEqualToString:@"currentquery"])
+ replaceRange = currentQueryRange;
+ else if([inputAction isEqualToString:@"entirecontent"])
+ replaceRange = NSMakeRange(0,[[self string] length]);
+ } else {
+ replaceRange = currentSelectionRange;
+ }
+ }
+ [self insertAsSnippet:output atRange:replaceRange];
+ }
+
+ else if([action isEqualToString:@"replacecontent"]) {
+ if([[self string] length])
+ [self setSelectedRange:NSMakeRange(0,[[self string] length])];
+ [self insertText:output];
+ }
+
+ else if([action isEqualToString:@"replaceselection"]) {
+ NSString *inputAction = @"";
+ NSString *inputFallBackAction = @"";
+ if([cmdData objectForKey:@"input"])
+ inputAction = [[cmdData objectForKey:@"input"] lowercaseString];
+ if([cmdData objectForKey:@"input_fallback"])
+ inputFallBackAction = [[cmdData objectForKey:@"input_fallback"] lowercaseString];
+ NSRange replaceRange = NSMakeRange(currentSelectionRange.location, 0);
+ if([inputAction isEqualToString:@"selectedtext"]) {
+ if(!currentSelectionRange.length) {
+ if([inputFallBackAction isEqualToString:@"currentword"])
+ replaceRange = currentWordRange;
+ else if([inputFallBackAction isEqualToString:@"currentline"])
+ replaceRange = currentLineRange;
+ else if([inputFallBackAction isEqualToString:@"currentquery"])
+ replaceRange = currentQueryRange;
+ else if([inputAction isEqualToString:@"entirecontent"])
+ replaceRange = NSMakeRange(0,[[self string] length]);
+ } else {
+ replaceRange = currentSelectionRange;
+ }
+ }
+ [self shouldChangeTextInRange:replaceRange replacementString:output];
+ [self replaceCharactersInRange:replaceRange withString:output];
+ }
+
+ else if([action isEqualToString:@"showastexttooltip"]) {
+ [SPTooltip showWithObject:output];
+ }
+
+ else if([action isEqualToString:@"showashtmltooltip"]) {
+ [SPTooltip showWithObject:output ofType:@"html"];
+ }
+
+ } else {
+ NSString *errorMessage = [err localizedDescription];
+ SPBeginAlertSheet(NSLocalizedString(@"BASH Error", @"bash error"), NSLocalizedString(@"OK", @"OK button"), nil, nil, [self window], self, nil, nil,
+ [NSString stringWithFormat:@"%@ “%@”:\n%@", NSLocalizedString(@"Error for", @"error for message"), [cmdData objectForKey:@"name"], errorMessage]);
+ }
+ }
+
+ if (cmdData) [cmdData release];
+ }
+
}
#pragma mark -