From f57a0e3d61633787df856dc2c0f60976807900a4 Mon Sep 17 00:00:00 2001 From: Bjorn Winckler Date: Sat, 4 Aug 2007 17:19:44 +0000 Subject: [PATCH] If a menu item is bound to ':action', the corresponding NSMenuItem has that action set as its action message (instead of the default 'vimMenuItemAction:'). git-svn-id: http://macvim.googlecode.com/svn/trunk@73 96c4425d-ca35-0410-94e5-3396d5c13a8f --- MMBackend.h | 3 ++- MMBackend.m | 6 ++++- MMVimController.m | 26 ++++++++++++++------ gui_macvim.m | 62 +++++++++++++++++++++++++++++++++++------------ 4 files changed, 72 insertions(+), 25 deletions(-) diff --git a/MMBackend.h b/MMBackend.h index aa5db08907..6a15f2ea50 100644 --- a/MMBackend.h +++ b/MMBackend.h @@ -73,7 +73,8 @@ atIndex:(int)index; - (void)addMenuItemWithTag:(int)tag parent:(int)parentTag name:(char *)name tip:(char *)tip icon:(char *)icon - keyEquivalent:(int)key modifiers:(int)mods atIndex:(int)index; + keyEquivalent:(int)key modifiers:(int)mods + action:(NSString *)action atIndex:(int)index; - (void)removeMenuItemWithTag:(int)tag; - (void)enableMenuItemWithTag:(int)tag state:(int)enabled; - (void)showToolbar:(int)enable flags:(int)flags; diff --git a/MMBackend.m b/MMBackend.m index ab32a31142..c30214419a 100644 --- a/MMBackend.m +++ b/MMBackend.m @@ -569,7 +569,8 @@ static int specialKeyToNSKey(int key); - (void)addMenuItemWithTag:(int)tag parent:(int)parentTag name:(char *)name tip:(char *)tip icon:(char *)icon - keyEquivalent:(int)key modifiers:(int)mods atIndex:(int)index + keyEquivalent:(int)key modifiers:(int)mods + action:(NSString *)action atIndex:(int)index { //NSLog(@"addMenuItemWithTag:%d parent:%d name:%s tip:%s atIndex:%d", tag, // parentTag, name, tip, index); @@ -578,6 +579,7 @@ static int specialKeyToNSKey(int key); int tiplen = tip ? strlen(tip) : 0; int iconlen = icon ? strlen(icon) : 0; int eventFlags = vimModMaskToEventModifierFlags(mods); + int actionlen = [action lengthOfBytesUsingEncoding:NSUTF8StringEncoding]; NSMutableData *data = [NSMutableData data]; key = specialKeyToNSKey(key); @@ -590,6 +592,8 @@ static int specialKeyToNSKey(int key); if (tiplen > 0) [data appendBytes:tip length:tiplen]; [data appendBytes:&iconlen length:sizeof(int)]; if (iconlen > 0) [data appendBytes:icon length:iconlen]; + [data appendBytes:&actionlen length:sizeof(int)]; + if (actionlen > 0) [data appendBytes:[action UTF8String] length:actionlen]; [data appendBytes:&index length:sizeof(int)]; [data appendBytes:&key length:sizeof(int)]; [data appendBytes:&eventFlags length:sizeof(int)]; diff --git a/MMVimController.m b/MMVimController.m index b63ccf1950..bdbd7f5c61 100644 --- a/MMVimController.m +++ b/MMVimController.m @@ -30,7 +30,8 @@ static NSString *DefaultToolbarImageName = @"Attention"; atIndex:(int)idx; - (void)addMenuItemWithTag:(int)tag parent:(NSMenu *)parent title:(NSString *)title tip:(NSString *)tip - keyEquivalent:(int)key modifiers:(int)mask atIndex:(int)idx; + keyEquivalent:(int)key modifiers:(int)mask + action:(NSString *)action atIndex:(int)idx; - (void)updateMainMenu; - (NSToolbarItem *)toolbarItemForTag:(int)tag index:(int *)index; - (IBAction)toolbarAction:(id)sender; @@ -569,7 +570,7 @@ static NSMenuItem *findMenuItemWithTagInMenu(NSMenu *root, int tag) [title release]; } else if (AddMenuItemMsgID == msgid) { - NSString *title = nil, *tip = nil, *icon = nil; + NSString *title = nil, *tip = nil, *icon = nil, *action = nil; const void *bytes = [data bytes]; int tag = *((int*)bytes); bytes += sizeof(int); int parentTag = *((int*)bytes); bytes += sizeof(int); @@ -591,6 +592,13 @@ static NSMenuItem *findMenuItemWithTagInMenu(NSMenu *root, int tag) encoding:NSUTF8StringEncoding]; bytes += iconlen; } + int actionlen = *((int*)bytes); bytes += sizeof(int); + if (actionlen > 0) { + action = [[NSString alloc] initWithBytes:(void*)bytes + length:actionlen + encoding:NSUTF8StringEncoding]; + bytes += actionlen; + } int idx = *((int*)bytes); bytes += sizeof(int); if (idx < 0) idx = 0; int key = *((int*)bytes); bytes += sizeof(int); @@ -604,12 +612,14 @@ static NSMenuItem *findMenuItemWithTagInMenu(NSMenu *root, int tag) } else { NSMenu *parent = [self menuForTag:parentTag]; [self addMenuItemWithTag:tag parent:parent title:title tip:tip - keyEquivalent:key modifiers:mask atIndex:idx]; + keyEquivalent:key modifiers:mask action:action + atIndex:idx]; } [title release]; [tip release]; [icon release]; + [action release]; } else if (RemoveMenuItemMsgID == msgid) { const void *bytes = [data bytes]; int tag = *((int*)bytes); bytes += sizeof(int); @@ -891,21 +901,23 @@ static NSMenuItem *findMenuItemWithTagInMenu(NSMenu *root, int tag) - (void)addMenuItemWithTag:(int)tag parent:(NSMenu *)parent title:(NSString *)title tip:(NSString *)tip - keyEquivalent:(int)key modifiers:(int)mask atIndex:(int)idx + keyEquivalent:(int)key modifiers:(int)mask + action:(NSString *)action atIndex:(int)idx { if (parent) { NSMenuItem *item = nil; if (title) { item = [[[NSMenuItem alloc] init] autorelease]; [item setTitle:title]; - [item setAction:@selector(vimMenuItemAction:)]; + // TODO: Check that 'action' is a valid action (nothing will happen + // if it isn't, but it would be nice with a warning). + if (action) [item setAction:NSSelectorFromString(action)]; + else [item setAction:@selector(vimMenuItemAction:)]; if (tip) [item setToolTip:tip]; if (key != 0) { NSString *keyString = [NSString stringWithFormat:@"%C", key]; - //NSLog(@"Set key equivalent %@ (code=0x%x, mods=%d)", - // keyString, key, mask); [item setKeyEquivalent:keyString]; [item setKeyEquivalentModifierMask:mask]; } diff --git a/gui_macvim.m b/gui_macvim.m index 93bc130792..e332338d63 100644 --- a/gui_macvim.m +++ b/gui_macvim.m @@ -14,6 +14,8 @@ #import "vim.h" +static BOOL gui_cocoa_is_valid_action(NSString *action); + // -- Initialization -------------------------------------------------------- @@ -582,6 +584,26 @@ gui_mch_add_menu_item(vimmenu_T *menu, int idx) char *tip = menu->strings[MENU_INDEX_TIP] ? (char*)menu->strings[MENU_INDEX_TIP] : (char*)menu->actext; + // HACK! Check if menu is mapped to ':action actionName:'; if so, pass the + // action along so that MacVim can bind the menu item to this action. This + // means that if a menu item maps to an action in normal mode, then all + // other modes will also use the same action. + NSString *action = nil; + char_u *map_str = menu->strings[MENU_INDEX_NORMAL]; + if (map_str) { + NSString *mapping = [NSString stringWithCString:(char*)map_str + encoding:NSUTF8StringEncoding]; + NSArray *parts = [mapping componentsSeparatedByString:@" "]; + if ([parts count] >=2 + && [[parts objectAtIndex:0] isEqual:@":action"]) { + action = [parts objectAtIndex:1]; + action = [action stringByTrimmingCharactersInSet: + [NSCharacterSet whitespaceAndNewlineCharacterSet]]; + if (!gui_cocoa_is_valid_action(action)) + action = nil; + } + } + [[MMBackend sharedInstance] addMenuItemWithTag:(int)menu parent:(int)menu->parent @@ -590,6 +612,7 @@ gui_mch_add_menu_item(vimmenu_T *menu, int idx) icon:(char*)icon keyEquivalent:menu->ke_key modifiers:menu->ke_mods + action:action atIndex:idx]; } @@ -861,29 +884,14 @@ gui_mch_set_scrollbar_thumb( ex_action(eap) exarg_T *eap; { - static NSDictionary *actionDict = nil; - if (!gui.in_use) { EMSG(_("E???: Command only available in GUI mode")); return; } - if (!actionDict) { - NSBundle *mainBundle = [NSBundle mainBundle]; - NSString *path = [mainBundle pathForResource:@"Actions" - ofType:@"plist"]; - if (path) { - actionDict = [[NSDictionary alloc] initWithContentsOfFile:path]; - } else { - // Allocate bogus dictionary so that error only pops up once. - actionDict = [NSDictionary new]; - EMSG(_("E???: Failed to load action dictionary")); - } - } - NSString *name = [NSString stringWithCString:(char*)eap->arg encoding:NSUTF8StringEncoding]; - if ([actionDict objectForKey:name]) { + if (gui_cocoa_is_valid_action(name)) { [[MMBackend sharedInstance] executeActionWithName:name]; } else { EMSG2(_("E???: \"%s\" is not a valid action"), eap->arg); @@ -1244,3 +1252,25 @@ gui_mch_toggle_tearoffs(int enable) mch_set_mouse_shape(int shape) { } + + + static BOOL +gui_cocoa_is_valid_action(NSString *action) +{ + static NSDictionary *actionDict = nil; + + if (!actionDict) { + NSBundle *mainBundle = [NSBundle mainBundle]; + NSString *path = [mainBundle pathForResource:@"Actions" + ofType:@"plist"]; + if (path) { + actionDict = [[NSDictionary alloc] initWithContentsOfFile:path]; + } else { + // Allocate bogus dictionary so that error only pops up once. + actionDict = [NSDictionary new]; + EMSG(_("E???: Failed to load action dictionary")); + } + } + + return [actionDict objectForKey:action] != nil; +}