From 8e8f563178d60aac24dfdf733d75ce8f31f3d5bf Mon Sep 17 00:00:00 2001 From: Bjorn Winckler Date: Sun, 11 Nov 2007 20:27:03 +0100 Subject: [PATCH] Support file-open check for multiple files When dropping multiple files, make sure none of the files are already open. If all files were already open, then select the window and tab of the first file that was open. If at least one file was not already open, then simply ignore the open files and open the unopened ones. Also don't check if files exists inside application:openFiles: since files that are passed here are assumed to already exists. The existence check has been moved to the system services message openFile:userData:error:. --- src/MacVim/MMAppController.m | 212 +++++++++++++++++++++-------------- src/MacVim/MacVim.h | 7 ++ src/MacVim/MacVim.m | 22 +++- 3 files changed, 158 insertions(+), 83 deletions(-) diff --git a/src/MacVim/MMAppController.m b/src/MacVim/MMAppController.m index 25b7f1018e..4a15f451d1 100644 --- a/src/MacVim/MMAppController.m +++ b/src/MacVim/MMAppController.m @@ -50,6 +50,8 @@ static NSTimeInterval MMReplyTimeout = 5; - (MMVimController *)keyVimController; - (MMVimController *)topmostVimController; - (void)launchVimProcessWithArguments:(NSArray *)args; +- (NSArray *)filterFilesAndNotify:(NSArray *)files; +- (NSArray *)filterOpenFilesAndRaiseFirst:(NSArray *)filenames; @end @interface NSMenu (MMExtras) @@ -155,84 +157,19 @@ static NSTimeInterval MMReplyTimeout = 5; - (void)application:(NSApplication *)sender openFiles:(NSArray *)filenames { - // Go trough 'filenames' array and make sure each file exists. - NSString *firstMissingFile = nil; - NSMutableArray *files = [NSMutableArray array]; - int i, count = [filenames count]; - for (i = 0; i < count; ++i) { - NSString *name = [filenames objectAtIndex:i]; - if ([[NSFileManager defaultManager] fileExistsAtPath:name]) { - [files addObject:name]; - } else if (!firstMissingFile) { - firstMissingFile = name; - } - } + filenames = [self filterOpenFilesAndRaiseFirst:filenames]; + if ([filenames count]) { + MMVimController *vc; + BOOL openInTabs = [[NSUserDefaults standardUserDefaults] + boolForKey:MMOpenFilesInTabsKey]; - if (firstMissingFile) { - NSAlert *alert = [[NSAlert alloc] init]; - [alert addButtonWithTitle:@"OK"]; - - NSString *text; - if ([files count] >= count-1) { - [alert setMessageText:@"File not found"]; - text = [NSString stringWithFormat:@"Could not open file with " - "name %@.", firstMissingFile]; + if (openInTabs && (vc = [self topmostVimController])) { + [vc dropFiles:filenames]; } else { - [alert setMessageText:@"Multiple files not found"]; - text = [NSString stringWithFormat:@"Could not open file with " - "name %@, and %d other files.", firstMissingFile, - count-[files count]-1]; + NSMutableArray *args = [NSMutableArray arrayWithObject:@"-p"]; + [args addObjectsFromArray:filenames]; + [self launchVimProcessWithArguments:args]; } - - [alert setInformativeText:text]; - [alert setAlertStyle:NSWarningAlertStyle]; - - [alert runModal]; - [alert release]; - - [NSApp replyToOpenOrPrint:NSApplicationDelegateReplyFailure]; - return; - } - - if ([files count] == 1) { - // Check if the file is already open...if so raise that window. - i, count = [vimControllers count]; - for (i = 0; i < count; ++i) { - MMVimController *controller = [vimControllers objectAtIndex:i]; - id proxy = [controller backendProxy]; - NSString *file = [[files objectAtIndex:0] - stringByEscapingSpecialFilenameCharacters]; - - @try { - NSString *expr = [NSString stringWithFormat: - @"bufloaded(\"%@\")", file]; - NSString *eval = [proxy evaluateExpression:expr]; - if ([eval isEqual:@"1"]) { - // TODO: Select the tab with 'file' open. - NSString *input = [NSString stringWithFormat:@"" - ":let oldswb=&swb|let &swb=\"useopen,usetab\"|" - "tab sb %@|let &swb=oldswb|unl oldswb|" - "cal foreground()|redr|f", file]; - [controller addVimInput:input]; - return; - } - } - @catch (NSException *e) { - // Do nothing ... - } - } - } - - MMVimController *vc; - BOOL openInTabs = [[NSUserDefaults standardUserDefaults] - boolForKey:MMOpenFilesInTabsKey]; - - if (openInTabs && (vc = [self topmostVimController])) { - [vc dropFiles:files]; - } else { - NSMutableArray *args = [NSMutableArray arrayWithObject:@"-p"]; - [args addObjectsFromArray:files]; - [self launchVimProcessWithArguments:args]; } [NSApp replyToOpenOrPrint:NSApplicationDelegateReplySuccess]; @@ -528,14 +465,18 @@ static NSTimeInterval MMReplyTimeout = 5; [NSCharacterSet whitespaceAndNewlineCharacterSet]]; string = [string stringByStandardizingPath]; - MMVimController *vc = nil; - if (userData && [userData isEqual:@"Tab"]) - vc = [self topmostVimController]; + NSArray *filenames = [self filterFilesAndNotify: + [NSArray arrayWithObject:string]]; + if ([filenames count] > 0) { + MMVimController *vc = nil; + if (userData && [userData isEqual:@"Tab"]) + vc = [self topmostVimController]; - if (vc) { - [vc dropFiles:[NSArray arrayWithObject:string]]; - } else { - [self application:NSApp openFiles:[NSArray arrayWithObject:string]]; + if (vc) { + [vc dropFiles:filenames]; + } else { + [self application:NSApp openFiles:filenames]; + } } } @@ -614,6 +555,113 @@ static NSTimeInterval MMReplyTimeout = 5; [NSTask launchedTaskWithLaunchPath:shell arguments:shellArgs]; } +- (NSArray *)filterFilesAndNotify:(NSArray *)filenames +{ + // Go trough 'filenames' array and make sure each file exists. Present + // warning dialog if some file was missing. + + NSString *firstMissingFile = nil; + NSMutableArray *files = [NSMutableArray array]; + unsigned i, count = [filenames count]; + + for (i = 0; i < count; ++i) { + NSString *name = [filenames objectAtIndex:i]; + if ([[NSFileManager defaultManager] fileExistsAtPath:name]) { + [files addObject:name]; + } else if (!firstMissingFile) { + firstMissingFile = name; + } + } + + if (firstMissingFile) { + NSAlert *alert = [[NSAlert alloc] init]; + [alert addButtonWithTitle:@"OK"]; + + NSString *text; + if ([files count] >= count-1) { + [alert setMessageText:@"File not found"]; + text = [NSString stringWithFormat:@"Could not open file with " + "name %@.", firstMissingFile]; + } else { + [alert setMessageText:@"Multiple files not found"]; + text = [NSString stringWithFormat:@"Could not open file with " + "name %@, and %d other files.", firstMissingFile, + count-[files count]-1]; + } + + [alert setInformativeText:text]; + [alert setAlertStyle:NSWarningAlertStyle]; + + [alert runModal]; + [alert release]; + + [NSApp replyToOpenOrPrint:NSApplicationDelegateReplyFailure]; + } + + return files; +} + +- (NSArray *)filterOpenFilesAndRaiseFirst:(NSArray *)filenames +{ + // Check if any of the files in the 'filenames' array are open in any Vim + // process. Remove the files that are open from the 'filenames' array and + // return it. If all files were filtered out, then raise the first file in + // the Vim process it is open. + + MMVimController *raiseController = nil; + NSString *raiseFile = nil; + NSMutableArray *files = [filenames mutableCopy]; + NSString *expr = [NSString stringWithFormat: + @"map([\"%@\"],\"bufloaded(v:val)\")", + [files componentsJoinedByString:@"\",\""]]; + unsigned i, count = [vimControllers count]; + + for (i = 0; i < count && [files count]; ++i) { + MMVimController *controller = [vimControllers objectAtIndex:i]; + id proxy = [controller backendProxy]; + + @try { + NSString *eval = [proxy evaluateExpression:expr]; + NSIndexSet *idxSet = [NSIndexSet indexSetWithVimList:eval]; + if ([idxSet count]) { + if (!raiseFile) { + // Remember the file and which Vim that has it open so that + // we can raise it later on. + raiseController = controller; + raiseFile = [files objectAtIndex:[idxSet firstIndex]]; + [[raiseFile retain] autorelease]; + } + + // Remove all the files that were open in this Vim process and + // create a new expression to evaluate. + [files removeObjectsAtIndexes:idxSet]; + expr = [NSString stringWithFormat: + @"map([\"%@\"],\"bufloaded(v:val)\")", + [files componentsJoinedByString:@"\",\""]]; + } + } + @catch (NSException *e) { + // Do nothing ... + } + } + + if (![files count] && raiseFile) { + // Raise the window containing the first file that was already open, + // and make sure that the tab containing that file is selected. Only + // do this if there are no more files to open, otherwise sometimes the + // window with 'raiseFile' will be raised, other times it might be the + // window that will open with the files in the 'files' array. + raiseFile = [raiseFile stringByEscapingSpecialFilenameCharacters]; + NSString *input = [NSString stringWithFormat:@"" + ":let oldswb=&swb|let &swb=\"useopen,usetab\"|" + "tab sb %@|let &swb=oldswb|unl oldswb|" + "cal foreground()|redr|f", raiseFile]; + [raiseController addVimInput:input]; + } + + return files; +} + @end // MMAppController (Private) diff --git a/src/MacVim/MacVim.h b/src/MacVim/MacVim.h index 6d610d12c5..1a77024d02 100644 --- a/src/MacVim/MacVim.h +++ b/src/MacVim/MacVim.h @@ -224,3 +224,10 @@ ATSFontContainerRef loadFonts(); @interface NSString (MMExtras) - (NSString *)stringByEscapingSpecialFilenameCharacters; @end + + + + +@interface NSIndexSet (MMExtras) ++ (id)indexSetWithVimList:(NSString *)list; +@end diff --git a/src/MacVim/MacVim.m b/src/MacVim/MacVim.m index 33afe4c5e7..45504ab4c0 100644 --- a/src/MacVim/MacVim.m +++ b/src/MacVim/MacVim.m @@ -167,5 +167,25 @@ loadFonts() return [string autorelease]; } - @end // NSString (MMExtras) + + + +@implementation NSIndexSet (MMExtras) + ++ (id)indexSetWithVimList:(NSString *)list +{ + NSMutableIndexSet *idxSet = [NSMutableIndexSet indexSet]; + NSArray *array = [list componentsSeparatedByString:@"\n"]; + unsigned i, count = [array count]; + + for (i = 0; i < count; ++i) { + NSString *entry = [array objectAtIndex:i]; + if ([entry intValue] > 0) + [idxSet addIndex:i]; + } + + return idxSet; +} + +@end // NSIndexSet (MMExtras)