diff --git a/runtime/doc/gui_mac.txt b/runtime/doc/gui_mac.txt index 720147af31..bcd42d9a0e 100644 --- a/runtime/doc/gui_mac.txt +++ b/runtime/doc/gui_mac.txt @@ -463,8 +463,7 @@ is not used. Hint: The |:macaction| command supports command-line completion so you can enter ":maca" to see a list of all available actions. -Here is a random assortment of actions from Actions.plist which might be -useful. +Here are some of the actions from Actions.plist which might be useful. Action Description ~ fileOpen: Show "File Open" dialog diff --git a/src/MacVim/MMAppController.h b/src/MacVim/MMAppController.h index a4a1b94b40..cd5cfcfa59 100644 --- a/src/MacVim/MMAppController.h +++ b/src/MacVim/MMAppController.h @@ -17,7 +17,7 @@ @class SUUpdater; -@interface MMAppController : NSObject { +@interface MMAppController : NSObject { NSConnection *connection; NSMutableArray *vimControllers; NSString *openSelectionString; @@ -62,6 +62,7 @@ - (IBAction)selectPreviousWindow:(id)sender; - (IBAction)orderFrontPreferencePanel:(id)sender; - (IBAction)openWebsite:(id)sender; +- (IBAction)showVimHelp:(id)sender withCmd:(NSString *)cmd; - (IBAction)showVimHelp:(id)sender; - (IBAction)checkForUpdates:(id)sender; - (IBAction)zoomAll:(id)sender; @@ -69,4 +70,10 @@ - (IBAction)stayInBack:(id)sender; - (IBAction)stayLevelNormal:(id)sender; +- (NSArray *)localizedTitlesForItem:(id)item; +- (void)searchForItemsWithSearchString:(NSString *)searchString + resultLimit:(NSInteger)resultLimit + matchedItemHandler:(void (^)(NSArray *items))handleMatchedItems; +- (void)performActionForItem:(id)item; + @end diff --git a/src/MacVim/MMAppController.m b/src/MacVim/MMAppController.m index 28248bb52d..1b17048b53 100644 --- a/src/MacVim/MMAppController.m +++ b/src/MacVim/MMAppController.m @@ -300,6 +300,9 @@ - (id)init [connection release]; connection = nil; } + // Register help search handler to support search Vim docs via the Help menu + [NSApp registerUserInterfaceItemSearchHandler:self]; + #if !DISABLE_SPARKLE // Sparkle is enabled (this is the default). Initialize it. It will // automatically check for update. @@ -951,6 +954,9 @@ - (void)refreshMainMenu NSMenu *windowsMenu = [mainMenu findWindowsMenu]; [NSApp setWindowsMenu:windowsMenu]; + + NSMenu *helpMenu = [mainMenu findHelpMenu]; + [NSApp setHelpMenu:helpMenu]; } - (NSArray *)filterOpenFiles:(NSArray *)filenames @@ -1150,10 +1156,11 @@ - (IBAction)fileOpen:(id)sender NSInteger result = [panel runModal]; #if (MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_10) - if (NSModalResponseOK == result) { + if (NSModalResponseOK == result) #else - if (NSOKButton == result) { + if (NSOKButton == result) #endif + { // NOTE: -[NSOpenPanel filenames] is deprecated on 10.7 so use // -[NSOpenPanel URLs] instead. The downside is that we have to check // that each URL is really a path first. @@ -1234,15 +1241,20 @@ - (IBAction)openWebsite:(id)sender [NSURL URLWithString:MMWebsiteString]]; } -- (IBAction)showVimHelp:(id)sender +- (IBAction)showVimHelp:(id)sender withCmd:(NSString *)cmd { ASLogDebug(@"Open window with Vim help"); - // Open a new window with the help window maximized. + // Open a new window with only the help window shown. [self launchVimProcessWithArguments:[NSArray arrayWithObjects: - @"-c", @":h gui_mac", @"-c", @":res", nil] + @"-c", cmd, @"-c", @":only", nil] workingDirectory:nil]; } +- (IBAction)showVimHelp:(id)sender +{ + [self showVimHelp:sender withCmd:@":h gui_mac"]; +} + - (IBAction)checkForUpdates:(id)sender { #if !DISABLE_SPARKLE @@ -1421,6 +1433,99 @@ - (NSArray *)serverList return array; } +// Begin NSUserInterfaceItemSearching implementation +- (NSArray *)localizedTitlesForItem:(id)item +{ + return item; +} + +- (void)searchForItemsWithSearchString:(NSString *)searchString + resultLimit:(NSInteger)resultLimit + matchedItemHandler:(void (^)(NSArray *items))handleMatchedItems +{ + // Search documentation tags and provide the results in a pair of (file + // name, tag name). Currently lazily parse the Vim's doc tags, and reuse + // that in future searches. + // + // Does not support plugins for now, as different Vim instances could have + // different plugins loaded. Theoretically it's possible to query the + // current Vim instance for what plugins are loaded and the tags associated + // with them but it's tricky especially since this function is not invoked + // on the main thread. Just providing Vim's builtin docs should be mostly + // good enough. + + static BOOL parsed = NO; + static NSMutableArray *parsedLineComponents = nil; + + @synchronized (self) { + if (!parsed) { + parsedLineComponents = [[NSMutableArray alloc]init]; + + NSString *tagsFilePath = [[[NSBundle mainBundle] resourcePath] + stringByAppendingPathComponent:@"vim/runtime/doc/tags"]; + NSString *fileContent = [NSString stringWithContentsOfFile:tagsFilePath encoding:NSUTF8StringEncoding error:NULL]; + NSArray *lines = [fileContent componentsSeparatedByString:@"\n"]; + + for (NSString *line in lines) { + NSArray *components = [line componentsSeparatedByString:@"\t"]; + if ([components count] < 2) { + continue; + } + [parsedLineComponents addObject:components]; + } + + parsed = YES; + } + } + + // Use a simple search algorithm where the string is split by whitespace and each word has to match + // substring in the tag. Don't do fuzzy matching or regex for simplicity for now. + NSArray *searchStrings = [searchString componentsSeparatedByString:@" "]; + + NSMutableArray *ret = [[[NSMutableArray alloc]init] autorelease]; + for (NSArray *line in parsedLineComponents) { + BOOL found = YES; + for (NSString *curSearchString in searchStrings) { + if (![line[0] localizedCaseInsensitiveContainsString:curSearchString]) { + found = NO; + break; + } + } + if (found) { + // We flip the ordering because we want it to look like "file_name.txt > tag_name" in the results. + NSArray *foundObject = @[line[1], line[0]]; + + if ([searchStrings count] == 1 && [searchString localizedCaseInsensitiveCompare:line[0]] == NSOrderedSame) { + // Exact match has highest priority. + [ret insertObject:foundObject atIndex:0]; + } + else { + // Don't do any other prioritization for now. May add more sophisticated sorting/heuristics + // in the future. + [ret addObject:foundObject]; + } + } + } + + // Return the results to callback. + handleMatchedItems(ret); +} + +- (void)performActionForItem:(id)item +{ + // When opening a help page, either open a new Vim instance, or reuse the + // existing one. + MMVimController *vimController = [self keyVimController]; + if (vimController == nil) { + [self showVimHelp:self withCmd:[NSString stringWithFormat: + @":help %@", item[1]]]; + return; + } + [vimController addVimInput:[NSString stringWithFormat: + @":help %@", item[1]]]; +} +// End NSUserInterfaceItemSearching + @end // MMAppController diff --git a/src/MacVim/Miscellaneous.h b/src/MacVim/Miscellaneous.h index 4d0d17e88d..176378e043 100644 --- a/src/MacVim/Miscellaneous.h +++ b/src/MacVim/Miscellaneous.h @@ -126,6 +126,7 @@ enum { - (NSMenu *)findApplicationMenu; - (NSMenu *)findServicesMenu; - (NSMenu *)findFileMenu; +- (NSMenu *)findHelpMenu; @end diff --git a/src/MacVim/Miscellaneous.m b/src/MacVim/Miscellaneous.m index 415c0d8337..93f4586d7f 100644 --- a/src/MacVim/Miscellaneous.m +++ b/src/MacVim/Miscellaneous.m @@ -178,6 +178,11 @@ - (NSMenu *)findFileMenu return [self findMenuContainingItemWithAction:@selector(performClose:)]; } +- (NSMenu *)findHelpMenu +{ + return [self findMenuContainingItemWithAction:@selector(openWebsite:)]; +} + @end // NSMenu (MMExtras)