diff options
Diffstat (limited to 'Source')
-rw-r--r-- | Source/SPAppController.m | 148 | ||||
-rw-r--r-- | Source/SPBundleCommandTextView.h | 3 | ||||
-rw-r--r-- | Source/SPBundleCommandTextView.m | 87 | ||||
-rw-r--r-- | Source/SPBundleEditorController.h | 3 | ||||
-rw-r--r-- | Source/SPBundleEditorController.m | 68 | ||||
-rw-r--r-- | Source/SPConstants.h | 24 | ||||
-rw-r--r-- | Source/SPConstants.m | 30 | ||||
-rw-r--r-- | Source/SPCopyTable.m | 432 | ||||
-rw-r--r-- | Source/SPCustomQuery.h | 1 | ||||
-rw-r--r-- | Source/SPCustomQuery.m | 8 | ||||
-rw-r--r-- | Source/SPDatabaseDocument.m | 22 | ||||
-rw-r--r-- | Source/SPNarrowDownCompletion.m | 34 | ||||
-rw-r--r-- | Source/SPStringAdditions.m | 92 | ||||
-rw-r--r-- | Source/SPTableContent.h | 1 | ||||
-rw-r--r-- | Source/SPTableContent.m | 8 | ||||
-rw-r--r-- | Source/SPTableStructure.m | 5 | ||||
-rw-r--r-- | Source/SPTextViewAdditions.m | 48 |
17 files changed, 727 insertions, 287 deletions
diff --git a/Source/SPAppController.m b/Source/SPAppController.m index c398b219..f51cfc13 100644 --- a/Source/SPAppController.m +++ b/Source/SPAppController.m @@ -640,7 +640,7 @@ // Try to find the SPDatabaseDocument which sent the the url scheme command // For speed check the front most first otherwise iterate through all - if(passedProcessID) { + if(passedProcessID && [passedProcessID length]) { if([activeProcessID isEqualToString:passedProcessID]) { processDocument = [[[self frontDocumentWindow] delegate] selectedTableDocument]; } else { @@ -691,18 +691,26 @@ return; } - // If command failed notify the file handle hand shake mechanism - NSString *out = @"1"; - [out writeToFile:[NSString stringWithFormat:@"%@%@", SPURLSchemeQueryResultStatusPathHeader, passedProcessID] - atomically:YES - encoding:NSUTF8StringEncoding - error:nil]; - out = @"Scheme Error"; - [out writeToFile:[NSString stringWithFormat:@"%@%@", SPURLSchemeQueryResultPathHeader, passedProcessID] - atomically:YES - encoding:NSUTF8StringEncoding - error:nil]; + if(processDocument != nil) { + // If command failed notify the file handle hand shake mechanism + NSString *out = @"1"; + [out writeToFile:[NSString stringWithFormat:@"%@%@", SPURLSchemeQueryResultStatusPathHeader, passedProcessID] + atomically:YES + encoding:NSUTF8StringEncoding + error:nil]; + out = @"Scheme Error"; + [out writeToFile:[NSString stringWithFormat:@"%@%@", SPURLSchemeQueryResultPathHeader, passedProcessID] + atomically:YES + encoding:NSUTF8StringEncoding + error:nil]; + } + if(passedProcessID == nil || ![passedProcessID length]) { + SPBeginAlertSheet(NSLocalizedString(@"sequelpro URL Scheme Error", @"sequelpro url Scheme Error"), NSLocalizedString(@"OK", @"OK button"), nil, nil, [NSApp mainWindow], self, nil, nil, + [NSString stringWithFormat:@"%@ “%@”:\n%@", NSLocalizedString(@"Error for", @"error for message"), [command description], NSLocalizedString(@"An error occur while executing a scheme command. If the scheme command was invoked by a Bundle command, it could be that the command still runs. You can try to terminate it by pressing ⌘+. or via the Activities pane.", @"an error occur while executing a scheme command. if the scheme command was invoked by a bundle command, it could be that the command still runs. you can try to terminate it by pressing ⌘+. or via the activities pane.")]); + } else { + NSBeep(); + } if(processDocument) NSLog(@"process doc ID: %@\n%@", [processDocument processID], [processDocument tabTitleForTooltip]); @@ -753,40 +761,18 @@ NSString *inputAction = @""; NSString *inputFallBackAction = @""; NSError *err = nil; - NSString *bundleInputFilePath = [NSString stringWithFormat:@"%@_%@", SPBundleTaskInputFilePath, [NSString stringWithNewUUID]]; + NSString *uuid = [NSString stringWithNewUUID]; + NSString *bundleInputFilePath = [NSString stringWithFormat:@"%@_%@", SPBundleTaskInputFilePath, uuid]; [[NSFileManager defaultManager] removeItemAtPath:bundleInputFilePath error:nil]; - if([cmdData objectForKey:SPBundleFileInputSourceKey]) - inputAction = [[cmdData objectForKey:SPBundleFileInputSourceKey] lowercaseString]; - if([cmdData objectForKey:SPBundleFileInputSourceFallBackKey]) - inputFallBackAction = [[cmdData objectForKey:SPBundleFileInputSourceFallBackKey] lowercaseString]; - NSMutableDictionary *env = [NSMutableDictionary dictionary]; - [env setObject:[infoPath stringByDeletingLastPathComponent] forKey:@"SP_BUNDLE_PATH"]; - [env setObject:bundleInputFilePath forKey:@"SP_BUNDLE_INPUT_FILE"]; + [env setObject:[infoPath stringByDeletingLastPathComponent] forKey:SPBundleShellVariableBundlePath]; + [env setObject:bundleInputFilePath forKey:SPBundleShellVariableInputFilePath]; + [env setObject:SPBundleScopeGeneral forKey:SPBundleShellVariableScope]; - NSError *inputFileError = nil; NSString *input = @""; - if([inputAction isEqualToString:SPBundleInputSourceSelectedTableRowsAsTab]) { - input = [self rowsAsTabStringWithHeaders:YES onlySelectedRows:YES]; - } - else if([inputAction isEqualToString:SPBundleInputSourceSelectedTableRowsAsCsv]) { - input = [self rowsAsCsvStringWithHeaders:YES onlySelectedRows:YES]; - } - else if([inputAction isEqualToString:SPBundleInputSourceSelectedTableRowsAsSqlInsert]) { - input = [self rowsAsSqlInsertsOnlySelectedRows:YES]; - } - else if([inputAction isEqualToString:SPBundleInputSourceTableRowsAsTab]) { - input = [self rowsAsTabStringWithHeaders:YES onlySelectedRows:NO]; - } - else if([inputAction isEqualToString:SPBundleInputSourceTableRowsAsCsv]) { - input = [self rowsAsCsvStringWithHeaders:YES onlySelectedRows:NO]; - } - else if([inputAction isEqualToString:SPBundleInputSourceTableRowsAsSqlInsert]) { - input = [self rowsAsSqlInsertsOnlySelectedRows:NO]; - } - + NSError *inputFileError = nil; if(input == nil) input = @""; [input writeToFile:bundleInputFilePath atomically:YES @@ -795,7 +781,7 @@ if(inputFileError != nil) { NSString *errorMessage = [inputFileError localizedDescription]; - SPBeginAlertSheet(NSLocalizedString(@"Bundle Error", @"bundle error"), NSLocalizedString(@"OK", @"OK button"), nil, nil, [NSApp mainWindow], self, nil, nil, + SPBeginAlertSheet(NSLocalizedString(@"Bundle Error", @"bundle 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]; return; @@ -807,15 +793,53 @@ contextInfo:[NSDictionary dictionaryWithObjectsAndKeys: ([cmdData objectForKey:SPBundleFileNameKey])?:@"-", @"name", NSLocalizedString(@"General", @"general menu item label"), @"scope", + uuid, SPBundleFileInternalexecutionUUID, nil] error:&err]; [[NSFileManager defaultManager] removeItemAtPath:bundleInputFilePath error:nil]; + NSString *action = [[cmdData objectForKey:SPBundleFileOutputActionKey] lowercaseString]; + + // Redirect due exit code + if(err != nil) { + if([err code] == SPBundleRedirectActionNone) { + action = SPBundleOutputActionNone; + err = nil; + } + else if([err code] == SPBundleRedirectActionReplaceSection) { + action = SPBundleOutputActionReplaceSelection; + err = nil; + } + else if([err code] == SPBundleRedirectActionReplaceContent) { + action = SPBundleOutputActionReplaceContent; + err = nil; + } + else if([err code] == SPBundleRedirectActionInsertAsText) { + action = SPBundleOutputActionInsertAsText; + err = nil; + } + else if([err code] == SPBundleRedirectActionInsertAsSnippet) { + action = SPBundleOutputActionInsertAsSnippet; + err = nil; + } + else if([err code] == SPBundleRedirectActionShowAsHTML) { + action = SPBundleOutputActionShowAsHTML; + err = nil; + } + else if([err code] == SPBundleRedirectActionShowAsTextTooltip) { + action = SPBundleOutputActionShowAsTextTooltip; + err = nil; + } + else if([err code] == SPBundleRedirectActionShowAsHTMLTooltip) { + action = SPBundleOutputActionShowAsHTMLTooltip; + err = nil; + } + } + if(err == nil && output) { if([cmdData objectForKey:SPBundleFileOutputActionKey] && [[cmdData objectForKey:SPBundleFileOutputActionKey] length] && ![[cmdData objectForKey:SPBundleFileOutputActionKey] isEqualToString:SPBundleOutputActionNone]) { - NSString *action = [[cmdData objectForKey:SPBundleFileOutputActionKey] lowercaseString]; NSPoint pos = [NSEvent mouseLocation]; pos.y -= 16; @@ -1302,7 +1326,9 @@ if([cmdData objectForKey:SPBundleFileCategoryKey] && [[cmdData objectForKey:SPBundleFileCategoryKey] length]) [aDict setObject:[cmdData objectForKey:SPBundleFileCategoryKey] forKey:SPBundleFileCategoryKey]; - [aDict setObject:[cmdData objectForKey:SPBundleFileKeyEquivalentKey] forKey:@"key"]; + if([cmdData objectForKey:SPBundleFileKeyEquivalentKey] && [[cmdData objectForKey:SPBundleFileKeyEquivalentKey] length]) + [aDict setObject:[cmdData objectForKey:SPBundleFileKeyEquivalentKey] forKey:@"key"]; + for(NSString* scope in scopes) [[bundleItems objectForKey:scope] addObject:aDict]; } @@ -1409,7 +1435,7 @@ [mItem setTag:1000000 + i++]; [mItem setRepresentedObject:[NSDictionary dictionaryWithObjectsAndKeys: scope, @"scope", - [item objectForKey:@"key"], @"key", nil]]; + ([item objectForKey:@"key"])?:@"", @"key", nil]]; if([item objectForKey:SPBundleFileCategoryKey]) { [[categoryMenus objectAtIndex:[bundleCategories indexOfObject:[item objectForKey:SPBundleFileCategoryKey]]] addItem:mItem]; @@ -1431,16 +1457,42 @@ - (IBAction)bundleCommandDispatcher:(id)sender { - BOOL checkForKeyEquivalents = ([[NSApp currentEvent] type] == NSKeyDown) ? YES : NO; + NSEvent *event = [NSApp currentEvent]; + BOOL checkForKeyEquivalents = ([event type] == NSKeyDown) ? YES : NO; + + id firstResponder = [[NSApp mainWindow] firstResponder]; NSString *scope = [[sender representedObject] objectForKey:@"scope"]; NSString *keyEqKey = nil; NSMutableArray *assignedKeyEquivalents = nil; if(checkForKeyEquivalents) { + + // Get the current scope in order to find out which command with a specific key + // should run + if([firstResponder respondsToSelector:@selector(executeBundleItemForInputField:)]) + scope = SPBundleScopeInputField; + else if([firstResponder respondsToSelector:@selector(executeBundleItemForDataTable:)]) + scope = SPBundleScopeDataTable; + else + scope = SPBundleScopeGeneral; + keyEqKey = [[sender representedObject] objectForKey:@"key"]; + assignedKeyEquivalents = [NSMutableArray array]; [assignedKeyEquivalents setArray:[[bundleKeyEquivalents objectForKey:scope] objectForKey:keyEqKey]]; + // Fall back to general scope and check for key + if(![assignedKeyEquivalents count]) { + scope = SPBundleScopeGeneral; + [assignedKeyEquivalents setArray:[[bundleKeyEquivalents objectForKey:scope] objectForKey:keyEqKey]]; + } + // Nothing found thus bail + if(![assignedKeyEquivalents count]) { + NSBeep(); + return; + } + + // Sort if more than one found if([assignedKeyEquivalents count] > 1) { NSSortDescriptor *aSortDescriptor = [[[NSSortDescriptor alloc] initWithKey:@"title" ascending:YES selector:@selector(caseInsensitiveCompare:)] autorelease]; NSArray *sorted = [assignedKeyEquivalents sortedArrayUsingDescriptors:[NSArray arrayWithObject:aSortDescriptor]]; @@ -1448,8 +1500,6 @@ } } - id firstResponder = [[NSApp mainWindow] firstResponder]; - if([scope isEqualToString:SPBundleScopeInputField] && [firstResponder respondsToSelector:@selector(executeBundleItemForInputField:)]) { if(checkForKeyEquivalents && [assignedKeyEquivalents count]) { NSInteger idx = 0; @@ -1489,7 +1539,7 @@ } } else if([scope isEqualToString:SPBundleScopeGeneral]) { - if(checkForKeyEquivalents && [assignedKeyEquivalents objectForKey:keyEqKey]) { + if(checkForKeyEquivalents && [assignedKeyEquivalents count]) { NSInteger idx = 0; if([assignedKeyEquivalents count] > 1) idx = [SPChooseMenuItemDialog withItems:assignedKeyEquivalents atPosition:[NSEvent mouseLocation]]; @@ -1500,7 +1550,7 @@ NSMenuItem *aMenuItem = [[[NSMenuItem alloc] init] autorelease]; [aMenuItem setTag:0]; [aMenuItem setToolTip:[eq objectForKey:@"path"]]; - [[[NSApp mainWindow] firstResponder] executeBundleItemForApp:aMenuItem]; + [self executeBundleItemForApp:aMenuItem]; } } } else { diff --git a/Source/SPBundleCommandTextView.h b/Source/SPBundleCommandTextView.h index 78e6a02a..119121da 100644 --- a/Source/SPBundleCommandTextView.h +++ b/Source/SPBundleCommandTextView.h @@ -38,10 +38,11 @@ - (NSUInteger)characterIndexOfPoint:(NSPoint)aPoint; - (void)insertFileContentOfFile:(NSString *)aPath; - (void)saveChangedFontInUserDefaults; -- (void) setTabStops; +- (void)setTabStops; - (BOOL)shiftSelectionRight; - (BOOL)shiftSelectionLeft; - (void)commentOut; +- (BOOL)wrapSelectionWithPrefix:(unichar)prefix; @end diff --git a/Source/SPBundleCommandTextView.m b/Source/SPBundleCommandTextView.m index d5a649bb..8a5bf620 100644 --- a/Source/SPBundleCommandTextView.m +++ b/Source/SPBundleCommandTextView.m @@ -337,7 +337,7 @@ [super cut:sender]; } -- (void) setTabStops +- (void)setTabStops { NSFont *tvFont = [self font]; NSInteger i; @@ -395,22 +395,86 @@ [paragraphStyle release]; } +/** + * If the textview has a selection, wrap it with the supplied prefix and suffix strings; + * return whether or not any wrap was performed. + */ +- (BOOL)wrapSelectionWithPrefix:(unichar)prefix +{ + + NSRange currentRange = [self selectedRange]; + + // Only proceed if a selection is active + if (currentRange.length == 0 || ![self isEditable]) + return NO; + + NSString *matchingCharacter; + NSString *prefixStr = nil; + + // Set matchingCharacter due to prefix. + switch (prefix) + { + case '(': + matchingCharacter = @")"; + break; + case '"': + matchingCharacter = @"\""; + break; + case '`': + matchingCharacter = @"`"; + break; + case '\'': + matchingCharacter = @"'"; + break; + case '{': + matchingCharacter = @"}"; + break; + case '[': + matchingCharacter = @"]"; + break; + case 0x201c: + prefixStr = @"“"; + matchingCharacter = @"”"; + break; + case 0x2018: + prefixStr = @"‘"; + matchingCharacter = @"’"; + break; + default: + return NO; + } + + NSString *selString = [[self string] substringWithRange:currentRange]; + NSString *replaceString; + if(prefixStr != nil) + replaceString = [NSString stringWithFormat:@"%@%@%@", prefixStr, selString, matchingCharacter]; + else + replaceString = [NSString stringWithFormat:@"%c%@%@", prefix, selString, matchingCharacter]; + + [self breakUndoCoalescing]; + + // Replace the current selection with the selected string wrapped in prefix and suffix + [self insertText:replaceString]; + + // Re-select original selection + NSRange innerSelectionRange = NSMakeRange(currentRange.location+1, [selString length]); + [self setSelectedRange:innerSelectionRange]; + + return YES; +} + - (void)keyDown:(NSEvent *)theEvent { long allFlags = (NSShiftKeyMask|NSControlKeyMask|NSAlternateKeyMask|NSCommandKeyMask); - // Check if user pressed ⌥ to allow composing of accented characters. - // e.g. for US keyboard "⌥u a" to insert ä - // or for non-US keyboards to allow to enter dead keys - // e.g. for German keyboard ` is a dead key, press space to enter ` - if (([theEvent modifierFlags] & allFlags) == NSAlternateKeyMask || [[theEvent characters] length] == 0) - { + NSString *characters = [theEvent characters]; + NSString *charactersIgnMod = [theEvent charactersIgnoringModifiers]; + if(![characters length]) { [super keyDown: theEvent]; return; } - - NSString *charactersIgnMod = [theEvent charactersIgnoringModifiers]; + unichar insertedCharacter = [characters characterAtIndex:0]; long curFlags = ([theEvent modifierFlags] & allFlags); if(curFlags & NSCommandKeyMask) { @@ -452,6 +516,11 @@ [[self delegate] setDoGroupDueToChars]; } + // Check to see whether several characters are selected, and if so, wrap them with + // the auto-paired characters. This returns false if the selection has zero length. + if ([self wrapSelectionWithPrefix:insertedCharacter]) + return; + [super keyDown: theEvent]; } diff --git a/Source/SPBundleEditorController.h b/Source/SPBundleEditorController.h index 7cc36de4..d586e5bc 100644 --- a/Source/SPBundleEditorController.h +++ b/Source/SPBundleEditorController.h @@ -106,6 +106,8 @@ BOOL selectionChanged; NSUndoManager *esUndoManager; + NSArray *shellVariableSuggestions; + } - (IBAction)inputPopupButtonChanged:(id)sender; @@ -123,6 +125,7 @@ - (IBAction)saveAndCloseWindow:(id)sender; - (IBAction)reloadBundles:(id)sender; - (IBAction)metaButtonChanged:(id)sender; +- (IBAction)performClose:(id)sender; - (BOOL)saveBundle:(NSDictionary*)bundle atPath:(NSString*)aPath; - (BOOL)cancelRowEditing; diff --git a/Source/SPBundleEditorController.m b/Source/SPBundleEditorController.m index 2eb58edc..4091e606 100644 --- a/Source/SPBundleEditorController.m +++ b/Source/SPBundleEditorController.m @@ -95,6 +95,8 @@ [triggerGeneralArray release]; [withBlobDataTableArray release]; + [shellVariableSuggestions release]; + if(touchedBundleArray) [touchedBundleArray release], touchedBundleArray = nil; if(commandBundleTree) [commandBundleTree release], commandBundleTree = nil; if(sortDescriptor) [sortDescriptor release], sortDescriptor = nil; @@ -306,6 +308,48 @@ [commandBundleTreeController setSortDescriptors:[NSArray arrayWithObjects:sortDescriptor, nil]]; + shellVariableSuggestions = [[NSArray arrayWithObjects: + @"SP_ALL_DATABASES", + @"SP_ALL_FUNCTIONS", + @"SP_ALL_PROCEDURES", + @"SP_ALL_TABLES", + @"SP_ALL_VIEWS", + @"SP_APP_RESOURCES_DIRECTORY", + @"SP_BUNDLE_EXIT_INSERT_AS_SNIPPET", + @"SP_BUNDLE_EXIT_INSERT_AS_TEXT", + @"SP_BUNDLE_EXIT_NONE", + @"SP_BUNDLE_EXIT_REPLACE_CONTENT", + @"SP_BUNDLE_EXIT_REPLACE_SELECTION", + @"SP_BUNDLE_EXIT_SHOW_AS_HTML", + @"SP_BUNDLE_EXIT_SHOW_AS_HTML_TOOLTIP", + @"SP_BUNDLE_EXIT_SHOW_AS_TEXT_TOOLTIP", + @"SP_BUNDLE_INPUT", + @"SP_BUNDLE_INPUT_TABLE_METADATA", + @"SP_BUNDLE_PATH", + @"SP_BUNDLE_SCOPE", + @"SP_CURRENT_HOST", + @"SP_CURRENT_LINE", + @"SP_CURRENT_PORT", + @"SP_CURRENT_QUERY", + @"SP_CURRENT_USER", + @"SP_CURRENT_WORD", + @"SP_DATABASE_ENCODING", + @"SP_ICON_FILE", + @"SP_PROCESS_ID", + @"SP_QUERY_FILE", + @"SP_QUERY_RESULT_FILE", + @"SP_QUERY_RESULT_META_FILE", + @"SP_QUERY_RESULT_STATUS_FILE", + @"SP_RDBMS_TYPE", + @"SP_RDBMS_VERSION", + @"SP_SELECTED_DATABASE", + @"SP_SELECTED_ROW_INDICES", + @"SP_SELECTED_TABLE", + @"SP_SELECTED_TABLES", + @"SP_USED_QUERY_FOR_TABLE", + nil + ] retain]; + [self _initTree]; } @@ -662,6 +706,9 @@ */ - (IBAction)removeCommandBundle:(id)sender { + + [commandsOutlineView abortEditing]; + NSAlert *alert = [NSAlert alertWithMessageText:NSLocalizedString(@"Remove selected Bundle?", @"remove selected bundle message") defaultButton:NSLocalizedString(@"Remove", @"remove button") alternateButton:NSLocalizedString(@"Cancel", @"cancel button") @@ -745,6 +792,12 @@ } +- (IBAction)performClose:(id)sender +{ + [self _initTree]; + [self close]; +} + /** * Save all touched bundles to disk and close the Bundle Editor window */ @@ -1451,10 +1504,23 @@ cycleCounter = 0; } - [self performSelector:@selector(setAllowedUndo) withObject:nil afterDelay:0.09]; + [self performSelector:@selector(setAllowedUndo) withObject:nil afterDelay:0.0005]; } } +/** + * Add shell variable names to the completion list + */ +- (NSArray *)textView:(NSTextView *)textView completions:(NSArray *)words forPartialWordRange:(NSRange)charRange indexOfSelectedItem:(NSInteger *)index +{ + + NSMutableArray *suggestions = [NSMutableArray array]; + NSPredicate *predicate = [NSPredicate predicateWithFormat:@"SELF BEGINSWITH %@ ", [[textView string] substringWithRange:charRange]]; + [suggestions addObjectsFromArray:[shellVariableSuggestions filteredArrayUsingPredicate:predicate]]; + [suggestions addObjectsFromArray:words]; + return suggestions; + +} #pragma mark - #pragma mark UndoManager methods diff --git a/Source/SPConstants.h b/Source/SPConstants.h index 393c8fba..09763e45 100644 --- a/Source/SPConstants.h +++ b/Source/SPConstants.h @@ -469,6 +469,7 @@ extern NSString *SPBundleFileInputSourceFallBackKey; extern NSString *SPBundleFileOutputActionKey; extern NSString *SPBundleFileKeyEquivalentKey; extern NSString *SPBundleFileInternalKeyEquivalentKey; +extern NSString *SPBundleFileInternalexecutionUUID; extern NSString *SPBundleFileTooltipKey; extern NSString *SPBundleFileDisabledKey; extern NSString *SPBundleFileAuthorKey; @@ -482,8 +483,31 @@ extern NSString *SPBundleInternPathToFileKey; extern NSString *SPBundleInternKeyEquivalentKey; extern NSString *SPBundleFileName; extern NSString *SPBundleTaskInputFilePath; +extern NSString *SPBundleTaskOutputFilePath; extern NSString *SPBundleTaskScriptCommandFilePath; extern NSString *SPBundleTaskCopyBlobFileDirectory; +extern NSString *SPBundleTaskTableMetaDataFilePath; + +extern NSString *SPBundleShellVariableInputFilePath; +extern NSString *SPBundleShellVariableOutputFilePath; +extern NSString *SPBundleShellVariableBundlePath; +extern NSString *SPBundleShellVariableBlobFileDirectory; +extern NSString *SPBundleShellVariableQueryFile; +extern NSString *SPBundleShellVariableQueryResultFile; +extern NSString *SPBundleShellVariableQueryResultStatusFile; +extern NSString *SPBundleShellVariableQueryResultMetaFile; +extern NSString *SPBundleShellVariableInputTableMetaData; +extern NSString *SPBundleShellVariableScope; + +extern const NSInteger SPBundleRedirectActionNone; +extern const NSInteger SPBundleRedirectActionReplaceSection; +extern const NSInteger SPBundleRedirectActionReplaceContent; +extern const NSInteger SPBundleRedirectActionInsertAsText; +extern const NSInteger SPBundleRedirectActionInsertAsSnippet; +extern const NSInteger SPBundleRedirectActionShowAsHTML; +extern const NSInteger SPBundleRedirectActionShowAsTextTooltip; +extern const NSInteger SPBundleRedirectActionShowAsHTMLTooltip; +extern const NSInteger SPBundleRedirectActionLastCode; // sequel URL scheme extern NSString *SPURLSchemeQueryInputPathHeader; diff --git a/Source/SPConstants.m b/Source/SPConstants.m index c7adb047..1ef054bb 100644 --- a/Source/SPConstants.m +++ b/Source/SPConstants.m @@ -281,6 +281,7 @@ NSString *SPBundleFileInputSourceFallBackKey = @"input_fallback"; NSString *SPBundleFileOutputActionKey = @"output"; NSString *SPBundleFileKeyEquivalentKey = @"keyEquivalent"; NSString *SPBundleFileInternalKeyEquivalentKey = @"internalKeyEquivalent"; +NSString *SPBundleFileInternalexecutionUUID = @"exeUUID"; NSString *SPBundleFileTooltipKey = @"tooltip"; NSString *SPBundleFileDisabledKey = @"disabled"; NSString *SPBundleFileAuthorKey = @"author"; @@ -294,9 +295,32 @@ NSString *SPBundleInternPathToFileKey = @"path"; NSString *SPBundleInternKeyEquivalentKey = @"keyEquivalent"; NSString *SPBundleFileName = @"command.plist"; -NSString *SPBundleTaskInputFilePath = @"/tmp/SP_BUNDLE_TASK_INPUT"; -NSString *SPBundleTaskScriptCommandFilePath = @"/tmp/SP_SCRIPT_COMMAND"; -NSString *SPBundleTaskCopyBlobFileDirectory = @"/tmp/SP_COPY_BLOB_FILES"; +NSString *SPBundleTaskInputFilePath = @"/tmp/SP_BUNDLE_INPUT"; +NSString *SPBundleTaskOutputFilePath = @"/tmp/SP_BUNDLE_OUTPUT"; +NSString *SPBundleTaskScriptCommandFilePath = @"/tmp/SP_BUNDLE_SCRIPT_COMMAND"; +NSString *SPBundleTaskCopyBlobFileDirectory = @"/tmp/SP_BUNDLE_COPY_BLOB_FILES"; +NSString *SPBundleTaskTableMetaDataFilePath = @"/tmp/SP_BUNDLE_TABLE_META_DATA"; + +NSString *SPBundleShellVariableInputFilePath = @"SP_BUNDLE_INPUT"; +NSString *SPBundleShellVariableOutputFilePath = @"SP_BUNDLE_OUTPUT"; +NSString *SPBundleShellVariableBundlePath = @"SP_BUNDLE_PATH"; +NSString *SPBundleShellVariableBlobFileDirectory = @"SP_BUNDLE_BLOB_FILES_DIRECTORY"; +NSString *SPBundleShellVariableQueryFile = @"SP_QUERY_FILE"; +NSString *SPBundleShellVariableQueryResultFile = @"SP_QUERY_RESULT_FILE"; +NSString *SPBundleShellVariableQueryResultStatusFile = @"SP_QUERY_RESULT_STATUS_FILE"; +NSString *SPBundleShellVariableQueryResultMetaFile = @"SP_QUERY_RESULT_META_FILE"; +NSString *SPBundleShellVariableInputTableMetaData = @"SP_BUNDLE_INPUT_TABLE_METADATA"; +NSString *SPBundleShellVariableScope = @"SP_BUNDLE_SCOPE"; + +const NSInteger SPBundleRedirectActionNone = 200; +const NSInteger SPBundleRedirectActionReplaceSection = 201; +const NSInteger SPBundleRedirectActionReplaceContent = 202; +const NSInteger SPBundleRedirectActionInsertAsText = 203; +const NSInteger SPBundleRedirectActionInsertAsSnippet = 204; +const NSInteger SPBundleRedirectActionShowAsHTML = 205; +const NSInteger SPBundleRedirectActionShowAsTextTooltip = 207; +const NSInteger SPBundleRedirectActionShowAsHTMLTooltip = 208; +const NSInteger SPBundleRedirectActionLastCode = 208; // sequel URL scheme NSString *SPURLSchemeQueryInputPathHeader = @"/tmp/SP_QUERY_"; diff --git a/Source/SPCopyTable.m b/Source/SPCopyTable.m index 493c3fb4..58339976 100644 --- a/Source/SPCopyTable.m +++ b/Source/SPCopyTable.m @@ -922,6 +922,178 @@ NSInteger kBlobAsImageFile = 4; } +/** + * Only have the copy menu item enabled when row(s) are selected in + * supported tables. + */ +- (BOOL) validateMenuItem:(NSMenuItem*)anItem +{ + NSInteger menuItemTag = [anItem tag]; + + // Don't validate anything other than the copy commands + if (menuItemTag != MENU_EDIT_COPY && menuItemTag != MENU_EDIT_COPY_WITH_COLUMN && menuItemTag != MENU_EDIT_COPY_AS_SQL) { + return YES; + } + + // Don't enable menus for relations or triggers - no action to take yet + if ([[self delegate] isKindOfClass:[SPTableRelations class]] || [[self delegate] isKindOfClass:[SPTableTriggers class]]) { + return NO; + } + + // Enable the Copy [with column names] commands if a row is selected + if (menuItemTag == MENU_EDIT_COPY || menuItemTag == MENU_EDIT_COPY_WITH_COLUMN) { + return ([self numberOfSelectedRows] > 0); + } + + // Enable the Copy as SQL commands if rows are selected and column definitions are available + if (menuItemTag == MENU_EDIT_COPY_AS_SQL) { + return (columnDefinitions != nil && [self numberOfSelectedRows] > 0); + } + + return NO; +} + +/** + * Trap the enter, escape, tab and arrow keys, overriding default behaviour and continuing/ending editing, + * only within the current row. + */ +- (BOOL) control:(NSControl *)control textView:(NSTextView *)textView doCommandBySelector:(SEL)command +{ + + NSUInteger row, column; + + row = [self editedRow]; + column = [self editedColumn]; + + // Trap tab key + // -- for handling of blob fields and to check if it's editable look at [[self delegate] control:textShouldBeginEditing:] + if ( [textView methodForSelector:command] == [textView methodForSelector:@selector(insertTab:)] ) + { + [[control window] makeFirstResponder:control]; + + // Save the current line if it's the last field in the table + if ( [self numberOfColumns] - 1 == column ) { + if([[self delegate] respondsToSelector:@selector(addRowToDB)]) + [[self delegate] addRowToDB]; + [[self window] makeFirstResponder:self]; + } else { + // Select the next field for editing + [self editColumn:column+1 row:row withEvent:nil select:YES]; + } + + return YES; + } + + // Trap shift-tab key + else if ( [textView methodForSelector:command] == [textView methodForSelector:@selector(insertBacktab:)] ) + { + [[control window] makeFirstResponder:control]; + + // Save the current line if it's the last field in the table + if ( column < 1 ) { + if([[self delegate] respondsToSelector:@selector(addRowToDB)]) + [[self delegate] addRowToDB]; + [[self window] makeFirstResponder:self]; + } else { + // Select the previous field for editing + [self editColumn:column-1 row:row withEvent:nil select:YES]; + } + + return YES; + } + + // Trap enter key + else if ( [textView methodForSelector:command] == [textView methodForSelector:@selector(insertNewline:)] ) + { + // If enum field is edited RETURN selects the new value instead of saving the entire row + if([self isCellComplex]) + return YES; + + [[control window] makeFirstResponder:control]; + if([[self delegate] isKindOfClass:[SPTableContent class]] && ![self isCellEditingMode] && [[self delegate] respondsToSelector:@selector(addRowToDB)]) + [[self delegate] addRowToDB]; + return YES; + + } + + // Trap down arrow key + else if ( [textView methodForSelector:command] == [textView methodForSelector:@selector(moveDown:)] ) + { + + // If enum field is edited ARROW key navigates through the popup list + if([self isCellComplex]) + return NO; + + NSUInteger newRow = row+1; + if (newRow>=[[self delegate] numberOfRowsInTableView:self]) return YES; //check if we're already at the end of the list + + [[control window] makeFirstResponder:control]; + if([[self delegate] isKindOfClass:[SPTableContent class]] && ![self isCellEditingMode] && [[self delegate] respondsToSelector:@selector(addRowToDB)]) + [[self delegate] addRowToDB]; + + if (newRow>=[[self delegate] numberOfRowsInTableView:self]) return YES; //check again. addRowToDB could reload the table and change the number of rows + if (tableStorage && column>=[tableStorage columnCount]) return YES; //the column count could change too + + [self selectRowIndexes:[NSIndexSet indexSetWithIndex:newRow] byExtendingSelection:NO]; + [self editColumn:column row:newRow withEvent:nil select:YES]; + return YES; + } + + // Trap up arrow key + else if ( [textView methodForSelector:command] == [textView methodForSelector:@selector(moveUp:)] ) + { + + // If enum field is edited ARROW key navigates through the popup list + if([self isCellComplex]) + return NO; + + if (row==0) return YES; //already at the beginning of the list + NSUInteger newRow = row-1; + + [[control window] makeFirstResponder:control]; + if([[self delegate] isKindOfClass:[SPTableContent class]] && ![self isCellEditingMode] && [[self delegate] respondsToSelector:@selector(addRowToDB)]) + [[self delegate] addRowToDB]; + + if (newRow>=[[self delegate] numberOfRowsInTableView:self]) return YES; // addRowToDB could reload the table and change the number of rows + if (tableStorage && column>=[tableStorage columnCount]) return YES; //the column count could change too + + [self selectRowIndexes:[NSIndexSet indexSetWithIndex:newRow] byExtendingSelection:NO]; + [self editColumn:column row:newRow withEvent:nil select:YES]; + return YES; + } + + return NO; +} + +- (void) keyDown:(NSEvent *)theEvent +{ + + // RETURN or ENTER invoke editing mode for selected row + // by calling tableView:shouldEditTableColumn: to validate + + if([self numberOfSelectedRows] == 1 && ([theEvent keyCode] == 36 || [theEvent keyCode] == 76)) { + [self editColumn:0 row:[self selectedRow] withEvent:nil select:YES]; + return; + } + + // Check if ESCAPE is hit and use it to cancel row editing if supported + if ([theEvent keyCode] == 53 && [[self delegate] respondsToSelector:@selector(cancelRowEditing)]) + { + if ([[self delegate] cancelRowEditing]) return; + } + + else if ([theEvent keyCode] == 48 && ([[self delegate] isKindOfClass:[SPCustomQuery class]] + || [[self delegate] isKindOfClass:[SPTableContent class]])) { + [self editColumn:0 row:[self selectedRow] withEvent:nil select:YES]; + return; + } + + [super keyDown:theEvent]; +} + +#pragma mark - +#pragma mark Bundle Command Support + - (IBAction)executeBundleItemForDataTable:(id)sender { NSInteger idx = [sender tag] - 1000000; @@ -964,6 +1136,7 @@ NSInteger kBlobAsImageFile = 4; NSError *err = nil; NSString *uuid = [NSString stringWithNewUUID]; NSString *bundleInputFilePath = [NSString stringWithFormat:@"%@_%@", SPBundleTaskInputFilePath, uuid]; + NSString *bundleInputTableMetaDataFilePath = [NSString stringWithFormat:@"%@_%@", SPBundleTaskTableMetaDataFilePath, uuid]; [[NSFileManager defaultManager] removeItemAtPath:bundleInputFilePath error:nil]; @@ -973,12 +1146,15 @@ NSInteger kBlobAsImageFile = 4; inputFallBackAction = [[cmdData objectForKey:SPBundleFileInputSourceFallBackKey] lowercaseString]; NSMutableDictionary *env = [NSMutableDictionary dictionary]; - [env setObject:[infoPath stringByDeletingLastPathComponent] forKey:@"SP_BUNDLE_PATH"]; - [env setObject:bundleInputFilePath forKey:@"SP_BUNDLE_INPUT_FILE"]; + [env setObject:[infoPath stringByDeletingLastPathComponent] forKey:SPBundleShellVariableBundlePath]; + [env setObject:bundleInputFilePath forKey:SPBundleShellVariableInputFilePath]; if([[self delegate] respondsToSelector:@selector(usedQuery)] && [[self delegate] usedQuery]) [env setObject:[[self delegate] usedQuery] forKey:@"SP_USED_QUERY_FOR_TABLE"]; + [env setObject:bundleInputTableMetaDataFilePath forKey:SPBundleShellVariableInputTableMetaData]; + [env setObject:SPBundleScopeDataTable forKey:SPBundleShellVariableScope]; + if([self numberOfSelectedRows]) { NSMutableArray *sel = [NSMutableArray array]; NSIndexSet *selectedRows = [self selectedRowIndexes]; @@ -1006,7 +1182,7 @@ NSInteger kBlobAsImageFile = 4; if(blobHandling != kBlobExclude) { NSString *bundleBlobFilePath = [NSString stringWithFormat:@"%@_%@", SPBundleTaskCopyBlobFileDirectory, uuid]; - [env setObject:bundleBlobFilePath forKey:@"SP_BUNDLE_BLOB_FILES_DIRECTORY"]; + [env setObject:bundleBlobFilePath forKey:SPBundleShellVariableBlobFileDirectory]; [self setCopyBlobFileDirectory:bundleBlobFilePath]; } else { [self setCopyBlobFileDirectory:@""]; @@ -1045,21 +1221,100 @@ NSInteger kBlobAsImageFile = 4; return; } + NSMutableString *tableMetaData = [NSMutableString string]; + if([[self delegate] isKindOfClass:[SPCustomQuery class]]) { + NSArray *defs = [[self delegate] dataColumnDefinitions]; + for(NSDictionary* col in defs) { + [tableMetaData appendFormat:@"%@\t", [col objectForKey:@"type"]]; + [tableMetaData appendFormat:@"%@\t", [col objectForKey:@"typegrouping"]]; + [tableMetaData appendFormat:@"%@\t", ([col objectForKey:@"char_length"]) ? : @""]; + [tableMetaData appendFormat:@"%@\t", [col objectForKey:@"UNSIGNED_FLAG"]]; + [tableMetaData appendFormat:@"%@\t", [col objectForKey:@"AUTO_INCREMENT_FLAG"]]; + [tableMetaData appendFormat:@"%@\t", [col objectForKey:@"PRI_KEY_FLAG"]]; + [tableMetaData appendString:@"\n"]; + } + } + else if([[self delegate] isKindOfClass:[SPTableContent class]]) { + NSArray *defs = [[self delegate] dataColumnDefinitions]; + for(NSDictionary* col in defs) { + [tableMetaData appendFormat:@"%@\t", [col objectForKey:@"type"]]; + [tableMetaData appendFormat:@"%@\t", [col objectForKey:@"typegrouping"]]; + [tableMetaData appendFormat:@"%@\t", ([col objectForKey:@"length"]) ? : @""]; + [tableMetaData appendFormat:@"%@\t", [col objectForKey:@"unsigned"]]; + [tableMetaData appendFormat:@"%@\t", [col objectForKey:@"autoincrement"]]; + [tableMetaData appendFormat:@"%@\t", ([col objectForKey:@"isprimarykey"]) ? : @"0"]; + [tableMetaData appendFormat:@"%@\n", [col objectForKey:@"comment"]]; + } + } + + inputFileError = nil; + [tableMetaData writeToFile:bundleInputTableMetaDataFilePath + atomically:YES + encoding:NSUTF8StringEncoding + error:&inputFileError]; + + if(inputFileError != nil) { + NSString *errorMessage = [inputFileError localizedDescription]; + SPBeginAlertSheet(NSLocalizedString(@"Bundle Error", @"bundle 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]; + return; + } + + NSString *output = [cmd runBashCommandWithEnvironment:env atCurrentDirectoryPath:nil callerInstance:[[NSApp delegate] frontDocument] contextInfo:[NSDictionary dictionaryWithObjectsAndKeys: ([cmdData objectForKey:SPBundleFileNameKey])?:@"-", @"name", NSLocalizedString(@"Data Table", @"data table menu item label"), @"scope", + uuid, SPBundleFileInternalexecutionUUID, nil] error:&err]; [[NSFileManager defaultManager] removeItemAtPath:bundleInputFilePath error:nil]; + NSString *action = [[cmdData objectForKey:SPBundleFileOutputActionKey] lowercaseString]; + + // Redirect due exit code + if(err != nil) { + if([err code] == SPBundleRedirectActionNone) { + action = SPBundleOutputActionNone; + err = nil; + } + else if([err code] == SPBundleRedirectActionReplaceSection) { + action = SPBundleOutputActionReplaceSelection; + err = nil; + } + else if([err code] == SPBundleRedirectActionReplaceContent) { + action = SPBundleOutputActionReplaceContent; + err = nil; + } + else if([err code] == SPBundleRedirectActionInsertAsText) { + action = SPBundleOutputActionInsertAsText; + err = nil; + } + else if([err code] == SPBundleRedirectActionInsertAsSnippet) { + action = SPBundleOutputActionInsertAsSnippet; + err = nil; + } + else if([err code] == SPBundleRedirectActionShowAsHTML) { + action = SPBundleOutputActionShowAsHTML; + err = nil; + } + else if([err code] == SPBundleRedirectActionShowAsTextTooltip) { + action = SPBundleOutputActionShowAsTextTooltip; + err = nil; + } + else if([err code] == SPBundleRedirectActionShowAsHTMLTooltip) { + action = SPBundleOutputActionShowAsHTMLTooltip; + err = nil; + } + } + if(err == nil && output) { if([cmdData objectForKey:SPBundleFileOutputActionKey] && [[cmdData objectForKey:SPBundleFileOutputActionKey] length] && ![[cmdData objectForKey:SPBundleFileOutputActionKey] isEqualToString:SPBundleOutputActionNone]) { - NSString *action = [[cmdData objectForKey:SPBundleFileOutputActionKey] lowercaseString]; NSPoint pos = [NSEvent mouseLocation]; pos.y -= 16; @@ -1104,175 +1359,6 @@ NSInteger kBlobAsImageFile = 4; } -/** - * Only have the copy menu item enabled when row(s) are selected in - * supported tables. - */ -- (BOOL) validateMenuItem:(NSMenuItem*)anItem -{ - NSInteger menuItemTag = [anItem tag]; - - // Don't validate anything other than the copy commands - if (menuItemTag != MENU_EDIT_COPY && menuItemTag != MENU_EDIT_COPY_WITH_COLUMN && menuItemTag != MENU_EDIT_COPY_AS_SQL) { - return YES; - } - - // Don't enable menus for relations or triggers - no action to take yet - if ([[self delegate] isKindOfClass:[SPTableRelations class]] || [[self delegate] isKindOfClass:[SPTableTriggers class]]) { - return NO; - } - - // Enable the Copy [with column names] commands if a row is selected - if (menuItemTag == MENU_EDIT_COPY || menuItemTag == MENU_EDIT_COPY_WITH_COLUMN) { - return ([self numberOfSelectedRows] > 0); - } - - // Enable the Copy as SQL commands if rows are selected and column definitions are available - if (menuItemTag == MENU_EDIT_COPY_AS_SQL) { - return (columnDefinitions != nil && [self numberOfSelectedRows] > 0); - } - - return NO; -} - -/** - * Trap the enter, escape, tab and arrow keys, overriding default behaviour and continuing/ending editing, - * only within the current row. - */ -- (BOOL) control:(NSControl *)control textView:(NSTextView *)textView doCommandBySelector:(SEL)command -{ - - NSUInteger row, column; - - row = [self editedRow]; - column = [self editedColumn]; - - // Trap tab key - // -- for handling of blob fields and to check if it's editable look at [[self delegate] control:textShouldBeginEditing:] - if ( [textView methodForSelector:command] == [textView methodForSelector:@selector(insertTab:)] ) - { - [[control window] makeFirstResponder:control]; - - // Save the current line if it's the last field in the table - if ( [self numberOfColumns] - 1 == column ) { - if([[self delegate] respondsToSelector:@selector(addRowToDB)]) - [[self delegate] addRowToDB]; - [[self window] makeFirstResponder:self]; - } else { - // Select the next field for editing - [self editColumn:column+1 row:row withEvent:nil select:YES]; - } - - return YES; - } - - // Trap shift-tab key - else if ( [textView methodForSelector:command] == [textView methodForSelector:@selector(insertBacktab:)] ) - { - [[control window] makeFirstResponder:control]; - - // Save the current line if it's the last field in the table - if ( column < 1 ) { - if([[self delegate] respondsToSelector:@selector(addRowToDB)]) - [[self delegate] addRowToDB]; - [[self window] makeFirstResponder:self]; - } else { - // Select the previous field for editing - [self editColumn:column-1 row:row withEvent:nil select:YES]; - } - - return YES; - } - - // Trap enter key - else if ( [textView methodForSelector:command] == [textView methodForSelector:@selector(insertNewline:)] ) - { - // If enum field is edited RETURN selects the new value instead of saving the entire row - if([self isCellComplex]) - return YES; - - [[control window] makeFirstResponder:control]; - if([[self delegate] isKindOfClass:[SPTableContent class]] && ![self isCellEditingMode] && [[self delegate] respondsToSelector:@selector(addRowToDB)]) - [[self delegate] addRowToDB]; - return YES; - - } - - // Trap down arrow key - else if ( [textView methodForSelector:command] == [textView methodForSelector:@selector(moveDown:)] ) - { - - // If enum field is edited ARROW key navigates through the popup list - if([self isCellComplex]) - return NO; - - NSUInteger newRow = row+1; - if (newRow>=[[self delegate] numberOfRowsInTableView:self]) return YES; //check if we're already at the end of the list - - [[control window] makeFirstResponder:control]; - if([[self delegate] isKindOfClass:[SPTableContent class]] && ![self isCellEditingMode] && [[self delegate] respondsToSelector:@selector(addRowToDB)]) - [[self delegate] addRowToDB]; - - if (newRow>=[[self delegate] numberOfRowsInTableView:self]) return YES; //check again. addRowToDB could reload the table and change the number of rows - if (tableStorage && column>=[tableStorage columnCount]) return YES; //the column count could change too - - [self selectRowIndexes:[NSIndexSet indexSetWithIndex:newRow] byExtendingSelection:NO]; - [self editColumn:column row:newRow withEvent:nil select:YES]; - return YES; - } - - // Trap up arrow key - else if ( [textView methodForSelector:command] == [textView methodForSelector:@selector(moveUp:)] ) - { - - // If enum field is edited ARROW key navigates through the popup list - if([self isCellComplex]) - return NO; - - if (row==0) return YES; //already at the beginning of the list - NSUInteger newRow = row-1; - - [[control window] makeFirstResponder:control]; - if([[self delegate] isKindOfClass:[SPTableContent class]] && ![self isCellEditingMode] && [[self delegate] respondsToSelector:@selector(addRowToDB)]) - [[self delegate] addRowToDB]; - - if (newRow>=[[self delegate] numberOfRowsInTableView:self]) return YES; // addRowToDB could reload the table and change the number of rows - if (tableStorage && column>=[tableStorage columnCount]) return YES; //the column count could change too - - [self selectRowIndexes:[NSIndexSet indexSetWithIndex:newRow] byExtendingSelection:NO]; - [self editColumn:column row:newRow withEvent:nil select:YES]; - return YES; - } - - return NO; -} - -- (void) keyDown:(NSEvent *)theEvent -{ - - // RETURN or ENTER invoke editing mode for selected row - // by calling tableView:shouldEditTableColumn: to validate - - if([self numberOfSelectedRows] == 1 && ([theEvent keyCode] == 36 || [theEvent keyCode] == 76)) { - [self editColumn:0 row:[self selectedRow] withEvent:nil select:YES]; - return; - } - - // Check if ESCAPE is hit and use it to cancel row editing if supported - if ([theEvent keyCode] == 53 && [[self delegate] respondsToSelector:@selector(cancelRowEditing)]) - { - if ([[self delegate] cancelRowEditing]) return; - } - - else if ([theEvent keyCode] == 48 && ([[self delegate] isKindOfClass:[SPCustomQuery class]] - || [[self delegate] isKindOfClass:[SPTableContent class]])) { - [self editColumn:0 row:[self selectedRow] withEvent:nil select:YES]; - return; - } - - [super keyDown:theEvent]; -} - #pragma mark - - (void) awakeFromNib diff --git a/Source/SPCustomQuery.h b/Source/SPCustomQuery.h index 439ec8e3..f4c2440d 100644 --- a/Source/SPCustomQuery.h +++ b/Source/SPCustomQuery.h @@ -216,6 +216,7 @@ - (void) updateTableView; - (NSIndexSet *) resultSelectedRowIndexes; - (NSRect) resultViewport; +- (NSArray *)dataColumnDefinitions; - (void) setResultSelectedRowIndexesToRestore:(NSIndexSet *)theIndexSet; - (void) setResultViewportToRestore:(NSRect)theViewport; - (void) storeCurrentResultViewForRestoration; diff --git a/Source/SPCustomQuery.m b/Source/SPCustomQuery.m index 5e1a85e4..ef38461c 100644 --- a/Source/SPCustomQuery.m +++ b/Source/SPCustomQuery.m @@ -1558,6 +1558,14 @@ } /** + * Provide a getter for the custom query result table's current viewport + */ +- (NSArray *)dataColumnDefinitions +{ + return cqColumnDefinition; +} + +/** * Set the selected row indexes to restore on next custom query result table load */ - (void) setResultSelectedRowIndexesToRestore:(NSIndexSet *)theIndexSet diff --git a/Source/SPDatabaseDocument.m b/Source/SPDatabaseDocument.m index 4e36c5e1..f1ac803f 100644 --- a/Source/SPDatabaseDocument.m +++ b/Source/SPDatabaseDocument.m @@ -4691,6 +4691,28 @@ NSArray *columnDefinition = [theResult fetchResultFieldsStructure]; + // Write table meta data + NSMutableString *tableMetaData = [NSMutableString string]; + for(NSDictionary* col in columnDefinition) { + [tableMetaData appendFormat:@"%@\t", [col objectForKey:@"type"]]; + [tableMetaData appendFormat:@"%@\t", [col objectForKey:@"typegrouping"]]; + [tableMetaData appendFormat:@"%@\t", ([col objectForKey:@"char_length"]) ? : @""]; + [tableMetaData appendFormat:@"%@\t", [col objectForKey:@"UNSIGNED_FLAG"]]; + [tableMetaData appendFormat:@"%@\t", [col objectForKey:@"AUTO_INCREMENT_FLAG"]]; + [tableMetaData appendFormat:@"%@\t", [col objectForKey:@"PRI_KEY_FLAG"]]; + [tableMetaData appendString:@"\n"]; + } + NSError *err = nil; + [tableMetaData writeToFile:metaFileName + atomically:YES + encoding:NSUTF8StringEncoding + error:&err]; + if(err != nil) { + NSLog(@"Error while writing “%@”", tableMetaData); + NSBeep(); + return; + } + // write data NSInteger i, j; NSArray *theRow; diff --git a/Source/SPNarrowDownCompletion.m b/Source/SPNarrowDownCompletion.m index cdb5c51d..81f4e28b 100644 --- a/Source/SPNarrowDownCompletion.m +++ b/Source/SPNarrowDownCompletion.m @@ -115,6 +115,7 @@ if(self = [super initWithContentRect:NSMakeRect(0,0,maxWindowWidth,0) styleMask:NSBorderlessWindowMask backing:NSBackingStoreBuffered defer:YES]) { mutablePrefix = [NSMutableString new]; + originalFilterString = [NSMutableString new]; textualInputCharacters = [[NSMutableCharacterSet alphanumericCharacterSet] retain]; caseSensitive = YES; filtered = nil; @@ -124,8 +125,6 @@ suggestions = nil; autocompletePlaceholderWasInserted = NO; prefs = [NSUserDefaults standardUserDefaults]; - originalFilterString = [[NSMutableString alloc] init]; - [originalFilterString setString:@""]; tableFont = [NSUnarchiver unarchiveObjectWithData:[[NSUserDefaults standardUserDefaults] dataForKey:SPCustomQueryEditorFont]]; [self setupInterface]; @@ -222,13 +221,13 @@ { // Set filter string - if(aUserString) + if (aUserString) { [mutablePrefix appendString:aUserString]; + [originalFilterString appendString:aUserString]; + } autoCompletionMode = autoComplete; - if(autoCompletionMode) - [originalFilterString appendString:aUserString]; oneColumnMode = oneColumn; isQueryingDatabaseStructure = isQueryingDBStructure; @@ -800,13 +799,15 @@ // e.g. for US keyboard "⌥u a" to insert ä if (([event modifierFlags] & (NSShiftKeyMask|NSControlKeyMask|NSAlternateKeyMask|NSCommandKeyMask)) == NSAlternateKeyMask || [[event characters] length] == 0) { - if(autoCompletionMode) { - if (autocompletePlaceholderWasInserted) [self removeAutocompletionPlaceholderUsingFastMethod:YES]; + if (autocompletePlaceholderWasInserted) [self removeAutocompletionPlaceholderUsingFastMethod:YES]; + + if (autoCompletionMode) { [theView setCompletionIsOpen:NO]; [self close]; [NSApp sendEvent:event]; break; } + [NSApp sendEvent: event]; if(commaInsertionMode) @@ -845,28 +846,31 @@ } else if(key == NSBackspaceCharacter || key == NSDeleteCharacter) { - if(autoCompletionMode) { - if (autocompletePlaceholderWasInserted) [self removeAutocompletionPlaceholderUsingFastMethod:NO]; + if (autocompletePlaceholderWasInserted) [self removeAutocompletionPlaceholderUsingFastMethod:NO]; + + if (autoCompletionMode) { [NSApp sendEvent:event]; break; } + [NSApp sendEvent:event]; if([mutablePrefix length] == 0 || commaInsertionMode) break; spaceCounter = 0; [mutablePrefix deleteCharactersInRange:NSMakeRange([mutablePrefix length]-1, 1)]; + [originalFilterString deleteCharactersInRange:NSMakeRange([originalFilterString length]-1, 1)]; theCharRange.length--; theParseRange.length--; [self filter]; } else if([textualInputCharacters characterIsMember:key]) { + if (autocompletePlaceholderWasInserted) [self removeAutocompletionPlaceholderUsingFastMethod:YES]; - if(autoCompletionMode) { + if (autoCompletionMode) { [theView setCompletionIsOpen:NO]; [self close]; - if (autocompletePlaceholderWasInserted) [self removeAutocompletionPlaceholderUsingFastMethod:YES]; [NSApp sendEvent:event]; return; } @@ -879,6 +883,7 @@ spaceCounter++; [mutablePrefix appendString:[event characters]]; + [originalFilterString appendString:[event characters]]; theCharRange.length++; theParseRange.length++; [self filter]; @@ -898,9 +903,7 @@ [self completeAndInsertSnippet]; } else { if(!NSPointInRect([NSEvent mouseLocation], [self frame])) { - if(autoCompletionMode) { - if (autocompletePlaceholderWasInserted) [self removeAutocompletionPlaceholderUsingFastMethod:YES]; - } + if (autocompletePlaceholderWasInserted) [self removeAutocompletionPlaceholderUsingFastMethod:YES]; if(cursorMovedLeft) [theView performSelector:@selector(moveRight:)]; [NSApp sendEvent:event]; break; @@ -915,7 +918,7 @@ } // If the autocomplete menu is open, but the placeholder is still present, it needs removing. - if (autoCompletionMode && autocompletePlaceholderWasInserted) [self removeAutocompletionPlaceholderUsingFastMethod:NO]; + if (autocompletePlaceholderWasInserted) [self removeAutocompletionPlaceholderUsingFastMethod:NO]; [theView setCompletionIsOpen:NO]; [self close]; @@ -948,7 +951,6 @@ if ([originalFilterString length] < [curMatch length]) { NSUInteger currentSelectionPosition = [theView selectedRange].location; NSString* toInsert = [curMatch substringFromIndex:[originalFilterString length]]; - [mutablePrefix appendString:toInsert]; theCharRange.length += [toInsert length] - currentAutocompleteLength; theParseRange.length += [toInsert length]; [theView insertText:[toInsert lowercaseString]]; diff --git a/Source/SPStringAdditions.m b/Source/SPStringAdditions.m index a1b0daf8..97339201 100644 --- a/Source/SPStringAdditions.m +++ b/Source/SPStringAdditions.m @@ -462,20 +462,21 @@ NSMutableArray *scriptHeaderArguments = [NSMutableArray array]; NSString *scriptPath = @""; - NSString *stdoutFilePath = [NSString stringWithFormat:@"/tmp/SP_BUNDLE_OUTPUT_FILE_%@", [NSString stringWithNewUUID]]; - NSString *scriptFilePath = [NSString stringWithFormat:@"%@_%@", SPBundleTaskScriptCommandFilePath, [NSString stringWithNewUUID]]; + NSString *uuid = (contextInfo && [contextInfo objectForKey:SPBundleFileInternalexecutionUUID]) ? [contextInfo objectForKey:@"exeUUID"] : [NSString stringWithNewUUID]; + NSString *stdoutFilePath = [NSString stringWithFormat:@"%@_%@", SPBundleTaskOutputFilePath, uuid]; + NSString *scriptFilePath = [NSString stringWithFormat:@"%@_%@", SPBundleTaskScriptCommandFilePath, uuid]; [fm removeItemAtPath:scriptFilePath error:nil]; [fm removeItemAtPath:stdoutFilePath error:nil]; if([[NSApp delegate] lastBundleBlobFilesDirectory] != nil) [fm removeItemAtPath:[[NSApp delegate] lastBundleBlobFilesDirectory] error:nil]; - if([shellEnvironment objectForKey:@"SP_BUNDLE_BLOB_FILES_DIRECTORY"]) - [[NSApp delegate] setLastBundleBlobFilesDirectory:[shellEnvironment objectForKey:@"SP_BUNDLE_BLOB_FILES_DIRECTORY"]]; + if([shellEnvironment objectForKey:SPBundleShellVariableBlobFileDirectory]) + [[NSApp delegate] setLastBundleBlobFilesDirectory:[shellEnvironment objectForKey:SPBundleShellVariableBlobFileDirectory]]; // Parse first line for magic header #! ; if found save the script content and run the command after #! with that file. // This allows to write perl, ruby, osascript scripts natively. - if([self length] > 3 && [self hasPrefix:@"#!"] && [shellEnvironment objectForKey:@"SP_BUNDLE_PATH"]) { + if([self length] > 3 && [self hasPrefix:@"#!"] && [shellEnvironment objectForKey:SPBundleShellVariableBundlePath]) { NSRange firstLineRange = NSMakeRange(2, [self rangeOfString:@"\n"].location - 2); @@ -519,38 +520,66 @@ [theEnv setDictionary:shellEnvironment]; [theEnv setObject:[[NSBundle mainBundle] pathForResource:@"appicon" ofType:@"icns"] forKey:@"SP_ICON_FILE"]; + [theEnv setObject:[NSString stringWithFormat:@"%@/Contents/Resources", [[NSBundle mainBundle] bundlePath]] forKey:@"SP_APP_RESOURCES_DIRECTORY"]; + [theEnv setObject:[NSNumber numberWithInteger:SPBundleRedirectActionNone] forKey:@"SP_BUNDLE_EXIT_NONE"]; + [theEnv setObject:[NSNumber numberWithInteger:SPBundleRedirectActionReplaceSection] forKey:@"SP_BUNDLE_EXIT_REPLACE_SELECTION"]; + [theEnv setObject:[NSNumber numberWithInteger:SPBundleRedirectActionReplaceContent] forKey:@"SP_BUNDLE_EXIT_REPLACE_CONTENT"]; + [theEnv setObject:[NSNumber numberWithInteger:SPBundleRedirectActionInsertAsText] forKey:@"SP_BUNDLE_EXIT_INSERT_AS_TEXT"]; + [theEnv setObject:[NSNumber numberWithInteger:SPBundleRedirectActionInsertAsSnippet] forKey:@"SP_BUNDLE_EXIT_INSERT_AS_SNIPPET"]; + [theEnv setObject:[NSNumber numberWithInteger:SPBundleRedirectActionShowAsHTML] forKey:@"SP_BUNDLE_EXIT_SHOW_AS_HTML"]; + [theEnv setObject:[NSNumber numberWithInteger:SPBundleRedirectActionShowAsTextTooltip] forKey:@"SP_BUNDLE_EXIT_SHOW_AS_TEXT_TOOLTIP"]; + [theEnv setObject:[NSNumber numberWithInteger:SPBundleRedirectActionShowAsHTMLTooltip] forKey:@"SP_BUNDLE_EXIT_SHOW_AS_HTML_TOOLTIP"]; // Create and set an unique process ID for each SPDatabaseDocument which has to passed // for each sequelpro:// scheme command as user to be able to identify the url scheme command. // Furthermore this id is used to communicate with the called command as file name. - NSString *processID = [NSString stringWithNewUUID]; - [theEnv setObject:processID forKey:@"SP_PROCESS_ID"]; id doc = nil; if([[[NSApp mainWindow] delegate] respondsToSelector:@selector(selectedTableDocument)]) doc = [[[NSApp mainWindow] delegate] selectedTableDocument]; + // Check if connected + if([[doc connectionID] isEqualToString:@"_"]) + doc = nil; + else { + for (NSWindow *aWindow in [NSApp orderedWindows]) { + if([[[[aWindow windowController] class] description] isEqualToString:@"SPWindowController"]) { + if([[[aWindow windowController] documents] count] && [[[[[[aWindow windowController] documents] objectAtIndex:0] class] description] isEqualToString:@"SPDatabaseDocument"]) { + // Check if connected + if(![[[[[aWindow windowController] documents] objectAtIndex:0] connectionID] isEqualToString:@"_"]) + doc = [[[aWindow windowController] documents] objectAtIndex:0]; + else + doc = nil; + } + } + if(doc) break; + } + } + if(doc != nil) { - [doc setProcessID:processID]; - [theEnv setObject:[NSString stringWithFormat:@"%@%@", SPURLSchemeQueryInputPathHeader, processID] forKey:@"SP_QUERY_FILE"]; - [theEnv setObject:[NSString stringWithFormat:@"%@%@", SPURLSchemeQueryResultPathHeader, processID] forKey:@"SP_QUERY_RESULT_FILE"]; - [theEnv setObject:[NSString stringWithFormat:@"%@%@", SPURLSchemeQueryResultStatusPathHeader, processID] forKey:@"SP_QUERY_RESULT_STATUS_FILE"]; - [theEnv setObject:[NSString stringWithFormat:@"%@%@", SPURLSchemeQueryResultMetaPathHeader, processID] forKey:@"SP_QUERY_RESULT_META_FILE"]; + [doc setProcessID:uuid]; + + [theEnv setObject:uuid forKey:@"SP_PROCESS_ID"]; + [theEnv setObject:[NSString stringWithFormat:@"%@%@", SPURLSchemeQueryInputPathHeader, uuid] forKey:SPBundleShellVariableQueryFile]; + [theEnv setObject:[NSString stringWithFormat:@"%@%@", SPURLSchemeQueryResultPathHeader, uuid] forKey:SPBundleShellVariableQueryResultFile]; + [theEnv setObject:[NSString stringWithFormat:@"%@%@", SPURLSchemeQueryResultStatusPathHeader, uuid] forKey:SPBundleShellVariableQueryResultStatusFile]; + [theEnv setObject:[NSString stringWithFormat:@"%@%@", SPURLSchemeQueryResultMetaPathHeader, uuid] forKey:SPBundleShellVariableQueryResultMetaFile]; if([doc shellVariables]) [theEnv addEntriesFromDictionary:[doc shellVariables]]; - if(theEnv != nil && [theEnv count]) - [bashTask setEnvironment:theEnv]; } + if(theEnv != nil && [theEnv count]) + [bashTask setEnvironment:theEnv]; + if(path != nil) [bashTask setCurrentDirectoryPath:path]; - else if([shellEnvironment objectForKey:@"SP_BUNDLE_PATH"] && [fm fileExistsAtPath:[shellEnvironment objectForKey:@"SP_BUNDLE_PATH"] isDirectory:&isDir] && isDir) - [bashTask setCurrentDirectoryPath:[shellEnvironment objectForKey:@"SP_BUNDLE_PATH"]]; + else if([shellEnvironment objectForKey:SPBundleShellVariableBundlePath] && [fm fileExistsAtPath:[shellEnvironment objectForKey:SPBundleShellVariableBundlePath] isDirectory:&isDir] && isDir) + [bashTask setCurrentDirectoryPath:[shellEnvironment objectForKey:SPBundleShellVariableBundlePath]]; - // STDOUT will be redirected to /tmp/SP_BUNDLE_OUTPUT_FILE in order to avoid nasty pipe programming due to block size reading - if([shellEnvironment objectForKey:@"SP_BUNDLE_INPUT_FILE"]) - [bashTask setArguments:[NSArray arrayWithObjects:@"-c", [NSString stringWithFormat:@"%@ > %@ < %@", [scriptHeaderArguments componentsJoinedByString:@" "], stdoutFilePath, [shellEnvironment objectForKey:@"SP_BUNDLE_INPUT_FILE"]], nil]]; + // STDOUT will be redirected to SPBundleTaskOutputFilePath in order to avoid nasty pipe programming due to block size reading + if([shellEnvironment objectForKey:SPBundleShellVariableInputFilePath]) + [bashTask setArguments:[NSArray arrayWithObjects:@"-c", [NSString stringWithFormat:@"%@ > %@ < %@", [scriptHeaderArguments componentsJoinedByString:@" "], stdoutFilePath, [shellEnvironment objectForKey:SPBundleShellVariableInputFilePath]], nil]]; else [bashTask setArguments:[NSArray arrayWithObjects:@"-c", [NSString stringWithFormat:@"%@ > %@", [scriptHeaderArguments componentsJoinedByString:@" "], stdoutFilePath], nil]]; @@ -601,14 +630,16 @@ // Remove files [fm removeItemAtPath:scriptFilePath error:nil]; - if([theEnv objectForKey:@"SP_QUERY_FILE"]) - [fm removeItemAtPath:[theEnv objectForKey:@"SP_QUERY_FILE"] error:nil]; - if([theEnv objectForKey:@"SP_QUERY_RESULT_FILE"]) - [fm removeItemAtPath:[theEnv objectForKey:@"SP_QUERY_RESULT_FILE"] error:nil]; - if([theEnv objectForKey:@"SP_QUERY_RESULT_STATUS_FILE"]) - [fm removeItemAtPath:[theEnv objectForKey:@"SP_QUERY_RESULT_STATUS_FILE"] error:nil]; - if([theEnv objectForKey:@"SP_QUERY_RESULT_META_FILE"]) - [fm removeItemAtPath:[theEnv objectForKey:@"SP_QUERY_RESULT_META_FILE"] error:nil]; + if([theEnv objectForKey:SPBundleShellVariableQueryFile]) + [fm removeItemAtPath:[theEnv objectForKey:SPBundleShellVariableQueryFile] error:nil]; + if([theEnv objectForKey:SPBundleShellVariableQueryResultFile]) + [fm removeItemAtPath:[theEnv objectForKey:SPBundleShellVariableQueryResultFile] error:nil]; + if([theEnv objectForKey:SPBundleShellVariableQueryResultStatusFile]) + [fm removeItemAtPath:[theEnv objectForKey:SPBundleShellVariableQueryResultStatusFile] error:nil]; + if([theEnv objectForKey:SPBundleShellVariableQueryResultMetaFile]) + [fm removeItemAtPath:[theEnv objectForKey:SPBundleShellVariableQueryResultMetaFile] error:nil]; + if([theEnv objectForKey:SPBundleShellVariableInputTableMetaData]) + [fm removeItemAtPath:[theEnv objectForKey:SPBundleShellVariableInputTableMetaData] error:nil]; // If return from bash re-activate Sequel Pro [NSApp activateIgnoringOtherApps:YES]; @@ -617,7 +648,7 @@ NSData *errdata = [stderr_file readDataToEndOfFile]; // Check STDERR - if([errdata length]) { + if([errdata length] && (status < SPBundleRedirectActionNone || status > SPBundleRedirectActionLastCode)) { [fm removeItemAtPath:stdoutFilePath error:nil]; if(status == 9 || userTerminated) return @""; @@ -658,7 +689,10 @@ } else { NSBeep(); } - return @""; + if(status > SPBundleRedirectActionNone && status <= SPBundleRedirectActionLastCode) + return stdout; + else + return @""; } } else { NSLog(@"Couldn't read return string from “%@” by using UTF-8 encoding.", self); diff --git a/Source/SPTableContent.h b/Source/SPTableContent.h index 96058a0f..1dc4caf9 100644 --- a/Source/SPTableContent.h +++ b/Source/SPTableContent.h @@ -218,6 +218,7 @@ - (NSRect) viewport; - (CGFloat) tablesListWidth; - (NSDictionary *) filterSettings; +- (NSArray *)dataColumnDefinitions; - (void) setSortColumnNameToRestore:(NSString *)theSortColumnName isAscending:(BOOL)isAscending; - (void) setPageToRestore:(NSUInteger)thePage; - (void) setSelectedRowIndexesToRestore:(NSIndexSet *)theIndexSet; diff --git a/Source/SPTableContent.m b/Source/SPTableContent.m index 483ab35d..4f466470 100644 --- a/Source/SPTableContent.m +++ b/Source/SPTableContent.m @@ -3169,6 +3169,14 @@ } /** + * Retrieve the data column definitions + */ +- (NSArray *)dataColumnDefinitions +{ + return dataColumns; +} + +/** * Set the sort column and sort order to restore on next table load */ - (void) setSortColumnNameToRestore:(NSString *)theSortColumnName isAscending:(BOOL)isAscending diff --git a/Source/SPTableStructure.m b/Source/SPTableStructure.m index 79a0a0a2..f57a881f 100644 --- a/Source/SPTableStructure.m +++ b/Source/SPTableStructure.m @@ -1015,8 +1015,9 @@ else if ([[theRow objectForKey:@"default"] length] && [theRowType isEqualToString:@"BIT"]) { [queryString appendFormat:@"\n DEFAULT %@", [theRow objectForKey:@"default"]]; } - // Suppress appending DEFAULT clause for any numerics, date, time fields if default is empty to avoid error messages - else if (![[theRow objectForKey:@"default"] length] && ([fieldValidation isFieldTypeNumeric:theRowType] || [fieldValidation isFieldTypeDate:theRowType])) { + // Suppress appending DEFAULT clause for any numerics, date, time fields if default is empty to avoid error messages; + // also don't specify a default for TEXT/BLOB or geometry fields to avoid strict mode errors + else if (![[theRow objectForKey:@"default"] length] && ([fieldValidation isFieldTypeNumeric:theRowType] || [fieldValidation isFieldTypeDate:theRowType] || [theRowType hasSuffix:@"TEXT"] || [theRowType hasSuffix:@"BLOB"] || [fieldValidation isFieldTypeGeometry:theRowType])) { ; } // Otherwise, use the provided default diff --git a/Source/SPTextViewAdditions.m b/Source/SPTextViewAdditions.m index 10f3f2e5..6ca111b5 100644 --- a/Source/SPTextViewAdditions.m +++ b/Source/SPTextViewAdditions.m @@ -527,7 +527,8 @@ NSString *inputAction = @""; NSString *inputFallBackAction = @""; NSError *err = nil; - NSString *bundleInputFilePath = [NSString stringWithFormat:@"%@_%@", SPBundleTaskInputFilePath, [NSString stringWithNewUUID]]; + NSString *uuid = [NSString stringWithNewUUID]; + NSString *bundleInputFilePath = [NSString stringWithFormat:@"%@_%@", SPBundleTaskInputFilePath, uuid]; NSRange currentWordRange, currentSelectionRange, currentLineRange, currentQueryRange; @@ -573,8 +574,9 @@ } NSMutableDictionary *env = [NSMutableDictionary dictionary]; - [env setObject:[infoPath stringByDeletingLastPathComponent] forKey:@"SP_BUNDLE_PATH"]; - [env setObject:bundleInputFilePath forKey:@"SP_BUNDLE_INPUT_FILE"]; + [env setObject:[infoPath stringByDeletingLastPathComponent] forKey:SPBundleShellVariableBundlePath]; + [env setObject:bundleInputFilePath forKey:SPBundleShellVariableInputFilePath]; + [env setObject:SPBundleScopeInputField forKey:SPBundleShellVariableScope]; if(selfIsQueryEditor && [[self delegate] currentQueryRange].length) [env setObject:[[self string] substringWithRange:[[self delegate] currentQueryRange]] forKey:@"SP_CURRENT_QUERY"]; @@ -609,15 +611,53 @@ contextInfo:[NSDictionary dictionaryWithObjectsAndKeys: ([cmdData objectForKey:SPBundleFileNameKey])?:@"-", @"name", NSLocalizedString(@"Input Field", @"input field menu item label"), @"scope", + uuid, SPBundleFileInternalexecutionUUID, nil] error:&err]; [[NSFileManager defaultManager] removeItemAtPath:bundleInputFilePath error:nil]; + NSString *action = [[cmdData objectForKey:SPBundleFileOutputActionKey] lowercaseString]; + + // Redirect due exit code + if(err != nil) { + if([err code] == SPBundleRedirectActionNone) { + action = SPBundleOutputActionNone; + err = nil; + } + else if([err code] == SPBundleRedirectActionReplaceSection) { + action = SPBundleOutputActionReplaceSelection; + err = nil; + } + else if([err code] == SPBundleRedirectActionReplaceContent) { + action = SPBundleOutputActionReplaceContent; + err = nil; + } + else if([err code] == SPBundleRedirectActionInsertAsText) { + action = SPBundleOutputActionInsertAsText; + err = nil; + } + else if([err code] == SPBundleRedirectActionInsertAsSnippet) { + action = SPBundleOutputActionInsertAsSnippet; + err = nil; + } + else if([err code] == SPBundleRedirectActionShowAsHTML) { + action = SPBundleOutputActionShowAsHTML; + err = nil; + } + else if([err code] == SPBundleRedirectActionShowAsTextTooltip) { + action = SPBundleOutputActionShowAsTextTooltip; + err = nil; + } + else if([err code] == SPBundleRedirectActionShowAsHTMLTooltip) { + action = SPBundleOutputActionShowAsHTMLTooltip; + err = nil; + } + } + if(err == nil && output) { if([cmdData objectForKey:SPBundleFileOutputActionKey] && [[cmdData objectForKey:SPBundleFileOutputActionKey] length] && ![[cmdData objectForKey:SPBundleFileOutputActionKey] isEqualToString:SPBundleOutputActionNone]) { - NSString *action = [[cmdData objectForKey:SPBundleFileOutputActionKey] lowercaseString]; if([action isEqualToString:SPBundleOutputActionShowAsTextTooltip]) { [SPTooltip showWithObject:output]; |