Skip to content
Browse files

More file opening options (plus quickstart feature)

The preferences panel allow for more ways to open files from other
applications.  This is controlled by three user preferences:
  - MMOpenInCurrentWindow
  - MMOpenLayout
  - MMVerticalSplit
These options are also respected when dropping files on a window.

The quickstart feature is currently disabled by default and can be
enabled by setting the user default MMPreloadCacheSize to a positive
integer.  With it enabled, new windows open more or less
instantaneously.
  • Loading branch information...
1 parent e43b739 commit 5c2795baae92307942b2229709c99227c45498b9 @b4winckler committed Aug 1, 2008
View
17 runtime/doc/gui_mac.txt
@@ -1,4 +1,4 @@
-*gui_mac.txt* For Vim version 7.2b. Last change: 2008 May 25
+*gui_mac.txt* For Vim version 7.2b. Last change: 2008 Jul 12
VIM REFERENCE MANUAL by Bjorn Winckler
@@ -167,10 +167,14 @@ use Mac OS X System Services to open files in MacVim, see |macvim-services|.
There are essentially two ways to start MacVim from Terminal: either call the
Vim binary with the -g switch >
/Applications/MacVim.app/Contents/MacOS/Vim -g file ...
-or use the "open" command (which is of limited use since it cannot be used to
-pass parameters to Vim) >
+or use the "open" command (this method can not be used to pass parameters to
+Vim) >
open -a MacVim file ...
-<
+The advantage of using the latter method is that the settings relating to file
+opening in the preferences panel are respected, and files open significantly
+faster if preloading of Vim processes is enabled (i.e. if the user default
+MMPreloadCacheSize is positive, see |macvim-user-defaults|).
+
*mvim*
To save yourself from having to type the entire path to the Vim binary each
time you start MacVim, you could create an alias such as >
@@ -212,8 +216,9 @@ is sent back to the server application.
Some settings are global to the MacVim application and would not make sense as
Vim options. These settings are stored in a user default database and can be
-accessed via the "MacVim/Preferences..." menu item.
+accessed via the "MacVim.Preferences..." menu item.
+ *macvim-user-defaults*
Not all entries in the user defaults database are exposed via the preference
panel, usually because they should not be changed by the user under normal
circumstances. These options can still be changed with the "defaults" command
@@ -231,6 +236,7 @@ MMDialogsTrackPwd open/save dialogs track the Vim pwd [bool]
MMLoginShellArgument login shell parameter [string]
MMLoginShellCommand which shell to use to launch Vim [string]
MMNoFontSubstitution disable automatic font substitution [bool]
+MMPreloadCacheSize number of Vim processes to preload [int]
MMTabMaxWidth maximum width of a tab [int]
MMTabMinWidth minimum width of a tab [int]
MMTabOptimumWidth default width of a tab [int]
@@ -240,6 +246,7 @@ MMTextInsetRight text area offset in pixels [int]
MMTextInsetTop text area offset in pixels [int]
MMTexturedWindow use brushed metal window (Tiger only) [bool]
MMTranslateCtrlClick interpret ctrl-click as right-click [bool]
+MMVerticalSplit files open in vertical splits [bool]
MMZoomBoth zoom button maximizes both directions [bool]
As an example, if you have more than one mouse button and would wish to free
View
2 src/MacVim/Actions.plist
@@ -26,6 +26,8 @@
<string></string>
<key>fontSizeUp:</key>
<string></string>
+ <key>forceNewWindow:</key>
+ <string></string>
<key>hide:</key>
<string></string>
<key>hideOtherApplications:</key>
View
40 src/MacVim/English.lproj/MainMenu.nib/classes.nib
@@ -13,6 +13,8 @@
<string>id</string>
<key>fontSizeUp</key>
<string>id</string>
+ <key>forceNewWindow</key>
+ <string>id</string>
<key>newWindow</key>
<string>id</string>
<key>openWebsite</key>
@@ -39,11 +41,24 @@
</dict>
<dict>
<key>CLASS</key>
- <string>NSMenu</string>
+ <string>RBSplitView</string>
<key>LANGUAGE</key>
<string>ObjC</string>
+ <key>OUTLETS</key>
+ <dict>
+ <key>delegate</key>
+ <string>id</string>
+ </dict>
<key>SUPERCLASS</key>
- <string>NSObject</string>
+ <string>RBSplitSubview</string>
+ </dict>
+ <dict>
+ <key>CLASS</key>
+ <string>RBSplitSubview</string>
+ <key>LANGUAGE</key>
+ <string>ObjC</string>
+ <key>SUPERCLASS</key>
+ <string>NSView</string>
</dict>
<dict>
<key>ACTIONS</key>
@@ -63,6 +78,27 @@
<string>NSObject</string>
</dict>
<dict>
+ <key>CLASS</key>
+ <string>NSMenu</string>
+ <key>LANGUAGE</key>
+ <string>ObjC</string>
+ <key>SUPERCLASS</key>
+ <string>NSObject</string>
+ </dict>
+ <dict>
+ <key>ACTIONS</key>
+ <dict>
+ <key>didAdjustSubviews</key>
+ <string>RBSplitView</string>
+ <key>willAdjustSubviews</key>
+ <string>RBSplitView</string>
+ </dict>
+ <key>CLASS</key>
+ <string>NSObject</string>
+ <key>LANGUAGE</key>
+ <string>ObjC</string>
+ </dict>
+ <dict>
<key>ACTIONS</key>
<dict>
<key>checkForUpdates</key>
View
4 src/MacVim/English.lproj/MainMenu.nib/info.nib
@@ -10,10 +10,10 @@
<integer>5</integer>
<key>IBOpenObjects</key>
<array>
- <integer>29</integer>
+ <integer>218</integer>
</array>
<key>IBSystem Version</key>
- <string>9D34</string>
+ <string>9E17</string>
<key>targetFramework</key>
<string>IBCocoaFramework</string>
</dict>
View
BIN src/MacVim/English.lproj/MainMenu.nib/keyedobjects.nib
Binary file not shown.
View
46 src/MacVim/English.lproj/Preferences.nib/classes.nib
@@ -9,6 +9,8 @@
<dict>
<key>installOdb</key>
<string>id</string>
+ <key>openInCurrentWindowSelectionChanged</key>
+ <string>id</string>
<key>uninstallOdb</key>
<string>id</string>
</dict>
@@ -26,6 +28,8 @@
<string>NSButton</string>
<key>integrationPreferences</key>
<string>NSView</string>
+ <key>layoutPopUpButton</key>
+ <string>NSPopUpButton</string>
<key>obdBundleVersionLabel</key>
<string>NSTextField</string>
<key>uninstallOdbButton</key>
@@ -36,13 +40,55 @@
</dict>
<dict>
<key>CLASS</key>
+ <string>RBSplitView</string>
+ <key>LANGUAGE</key>
+ <string>ObjC</string>
+ <key>OUTLETS</key>
+ <dict>
+ <key>delegate</key>
+ <string>id</string>
+ </dict>
+ <key>SUPERCLASS</key>
+ <string>RBSplitSubview</string>
+ </dict>
+ <dict>
+ <key>CLASS</key>
+ <string>RBSplitSubview</string>
+ <key>LANGUAGE</key>
+ <string>ObjC</string>
+ <key>SUPERCLASS</key>
+ <string>NSView</string>
+ </dict>
+ <dict>
+ <key>CLASS</key>
+ <string>NSMenu</string>
+ <key>LANGUAGE</key>
+ <string>ObjC</string>
+ <key>SUPERCLASS</key>
+ <string>NSObject</string>
+ </dict>
+ <dict>
+ <key>CLASS</key>
<string>FirstResponder</string>
<key>LANGUAGE</key>
<string>ObjC</string>
<key>SUPERCLASS</key>
<string>NSObject</string>
</dict>
<dict>
+ <key>ACTIONS</key>
+ <dict>
+ <key>didAdjustSubviews</key>
+ <string>RBSplitView</string>
+ <key>willAdjustSubviews</key>
+ <string>RBSplitView</string>
+ </dict>
+ <key>CLASS</key>
+ <string>NSObject</string>
+ <key>LANGUAGE</key>
+ <string>ObjC</string>
+ </dict>
+ <dict>
<key>CLASS</key>
<string>DBPrefsWindowController</string>
<key>LANGUAGE</key>
View
3 src/MacVim/English.lproj/Preferences.nib/info.nib
@@ -10,11 +10,10 @@
<integer>5</integer>
<key>IBOpenObjects</key>
<array>
- <integer>191</integer>
<integer>115</integer>
</array>
<key>IBSystem Version</key>
- <string>9C31</string>
+ <string>9E17</string>
<key>targetFramework</key>
<string>IBCocoaFramework</string>
</dict>
View
BIN src/MacVim/English.lproj/Preferences.nib/keyedobjects.nib
Binary file not shown.
View
4 src/MacVim/MMAppController.h
@@ -25,6 +25,8 @@
NSMenu *defaultMainMenu;
NSMenuItem *appMenuItemTemplate;
NSMenuItem *recentFilesMenuItem;
+ NSMutableArray *cachedVimControllers;
+ int preloadPid;
#ifdef MM_ENABLE_PLUGINS
NSMenuItem *plugInMenuItem;
@@ -38,13 +40,15 @@
- (void)removeVimController:(id)controller;
- (void)windowControllerWillOpen:(MMWindowController *)windowController;
- (void)setMainMenu:(NSMenu *)mainMenu;
+- (NSArray *)filterOpenFiles:(NSArray *)filenames;
#ifdef MM_ENABLE_PLUGINS
- (void)addItemToPlugInMenu:(NSMenuItem *)item;
- (void)removeItemFromPlugInMenu:(NSMenuItem *)item;
#endif
- (IBAction)newWindow:(id)sender;
+- (IBAction)forceNewWindow:(id)sender;
- (IBAction)fileOpen:(id)sender;
- (IBAction)selectNextWindow:(id)sender;
- (IBAction)selectPreviousWindow:(id)sender;
View
566 src/MacVim/MMAppController.m
@@ -94,7 +94,7 @@ - (MMVimController *)topmostVimController;
- (int)launchVimProcessWithArguments:(NSArray *)args;
- (NSArray *)filterFilesAndNotify:(NSArray *)files;
- (NSArray *)filterOpenFiles:(NSArray *)filenames
- arguments:(NSDictionary *)args;
+ openFilesDict:(NSDictionary **)openFiles;
#if MM_HANDLE_XCODE_MOD_EVENT
- (void)handleXcodeModEvent:(NSAppleEventDescriptor *)event
replyEvent:(NSAppleEventDescriptor *)reply;
@@ -103,7 +103,12 @@ - (int)findLaunchingProcessWithoutArguments;
- (MMVimController *)findUntitledWindow;
- (NSMutableDictionary *)extractArgumentsFromOdocEvent:
(NSAppleEventDescriptor *)desc;
-- (void)passArguments:(NSDictionary *)args toVimController:(MMVimController*)vc;
+- (void)scheduleVimControllerPreloadAfterDelay:(NSTimeInterval)delay;
+- (void)preloadVimController:(id)sender;
+- (int)maxPreloadCacheSize;
+- (MMVimController *)takeVimControllerFromCache;
+- (void)clearPreloadCache;
+- (BOOL)openVimControllerWithArguments:(NSDictionary *)arguments;
#ifdef MM_ENABLE_PLUGINS
- (void)removePlugInMenu;
@@ -131,7 +136,7 @@ + (void)initialize
[NSNumber numberWithFloat:1], MMCellWidthMultiplierKey,
[NSNumber numberWithFloat:-1], MMBaselineOffsetKey,
[NSNumber numberWithBool:YES], MMTranslateCtrlClickKey,
- [NSNumber numberWithBool:NO], MMOpenFilesInTabsKey,
+ [NSNumber numberWithInt:0], MMOpenInCurrentWindowKey,
[NSNumber numberWithBool:NO], MMNoFontSubstitutionKey,
[NSNumber numberWithBool:NO], MMLoginShellKey,
[NSNumber numberWithBool:NO], MMAtsuiRendererKey,
@@ -145,6 +150,9 @@ + (void)initialize
#ifdef MM_ENABLE_PLUGINS
[NSNumber numberWithBool:YES], MMShowLeftPlugInContainerKey,
#endif
+ [NSNumber numberWithInt:3], MMOpenLayoutKey,
+ [NSNumber numberWithBool:NO], MMVerticalSplitKey,
+ [NSNumber numberWithInt:0], MMPreloadCacheSizeKey,
nil];
[[NSUserDefaults standardUserDefaults] registerDefaults:dict];
@@ -155,48 +163,50 @@ + (void)initialize
- (id)init
{
- if ((self = [super init])) {
- fontContainerRef = loadFonts();
+ if (!(self = [super init])) return nil;
- vimControllers = [NSMutableArray new];
- pidArguments = [NSMutableDictionary new];
+ fontContainerRef = loadFonts();
+
+ vimControllers = [NSMutableArray new];
+ cachedVimControllers = [NSMutableArray new];
+ preloadPid = -1;
+ pidArguments = [NSMutableDictionary new];
#ifdef MM_ENABLE_PLUGINS
- NSString *plugInTitle = NSLocalizedString(@"Plug-In",
- @"Plug-In menu title");
- plugInMenuItem = [[NSMenuItem alloc] initWithTitle:plugInTitle
- action:NULL
- keyEquivalent:@""];
- NSMenu *submenu = [[NSMenu alloc] initWithTitle:plugInTitle];
- [plugInMenuItem setSubmenu:submenu];
- [submenu release];
+ NSString *plugInTitle = NSLocalizedString(@"Plug-In",
+ @"Plug-In menu title");
+ plugInMenuItem = [[NSMenuItem alloc] initWithTitle:plugInTitle
+ action:NULL
+ keyEquivalent:@""];
+ NSMenu *submenu = [[NSMenu alloc] initWithTitle:plugInTitle];
+ [plugInMenuItem setSubmenu:submenu];
+ [submenu release];
#endif
- // NOTE: Do not use the default connection since the Logitech Control
- // Center (LCC) input manager steals and this would cause MacVim to
- // never open any windows. (This is a bug in LCC but since they are
- // unlikely to fix it, we graciously give them the default connection.)
- connection = [[NSConnection alloc] initWithReceivePort:[NSPort port]
- sendPort:nil];
- [connection setRootObject:self];
- [connection setRequestTimeout:MMRequestTimeout];
- [connection setReplyTimeout:MMReplyTimeout];
-
- // NOTE: When the user is resizing the window the AppKit puts the run
- // loop in event tracking mode. Unless the connection listens to
- // request in this mode, live resizing won't work.
- [connection addRequestMode:NSEventTrackingRunLoopMode];
-
- // NOTE! If the name of the connection changes here it must also be
- // updated in MMBackend.m.
- NSString *name = [NSString stringWithFormat:@"%@-connection",
- [[NSBundle mainBundle] bundleIdentifier]];
- //NSLog(@"Registering connection with name '%@'", name);
- if (![connection registerName:name]) {
- NSLog(@"FATAL ERROR: Failed to register connection with name '%@'",
- name);
- [connection release]; connection = nil;
- }
+ // NOTE: Do not use the default connection since the Logitech Control
+ // Center (LCC) input manager steals and this would cause MacVim to
+ // never open any windows. (This is a bug in LCC but since they are
+ // unlikely to fix it, we graciously give them the default connection.)
+ connection = [[NSConnection alloc] initWithReceivePort:[NSPort port]
+ sendPort:nil];
+ [connection setRootObject:self];
+ [connection setRequestTimeout:MMRequestTimeout];
+ [connection setReplyTimeout:MMReplyTimeout];
+
+ // NOTE: When the user is resizing the window the AppKit puts the run
+ // loop in event tracking mode. Unless the connection listens to
+ // request in this mode, live resizing won't work.
+ [connection addRequestMode:NSEventTrackingRunLoopMode];
+
+ // NOTE! If the name of the connection changes here it must also be
+ // updated in MMBackend.m.
+ NSString *name = [NSString stringWithFormat:@"%@-connection",
+ [[NSBundle mainBundle] bundleIdentifier]];
+ //NSLog(@"Registering connection with name '%@'", name);
+ if (![connection registerName:name]) {
+ NSLog(@"FATAL ERROR: Failed to register connection with name '%@'",
+ name);
+ [connection release]; connection = nil;
}
return self;
@@ -209,6 +219,7 @@ - (void)dealloc
[connection release]; connection = nil;
[pidArguments release]; pidArguments = nil;
[vimControllers release]; vimControllers = nil;
+ [cachedVimControllers release]; cachedVimControllers = nil;
[openSelectionString release]; openSelectionString = nil;
[recentFilesMenuItem release]; recentFilesMenuItem = nil;
[defaultMainMenu release]; defaultMainMenu = nil;
@@ -275,6 +286,8 @@ - (void)applicationDidFinishLaunching:(NSNotification *)notification
#ifdef MM_ENABLE_PLUGINS
[[MMPlugInManager sharedManager] loadAllPlugIns];
#endif
+
+ [self scheduleVimControllerPreloadAfterDelay:2];
}
- (BOOL)applicationShouldOpenUntitledFile:(NSApplication *)sender
@@ -320,7 +333,7 @@ - (void)application:(NSApplication *)sender openFiles:(NSArray *)filenames
{
// Opening files works like this:
// a) extract ODB/Xcode/Spotlight parameters from the current Apple event
- // b) filter out any already open files (see filterOpenFiles::)
+ // b) filter out any already open files
// c) open any remaining files
//
// A file is opened in an untitled window if there is one (it may be
@@ -332,79 +345,141 @@ - (void)application:(NSApplication *)sender openFiles:(NSArray *)filenames
// arguments for each launching process can be looked up by its PID (in the
// pidArguments dictionary).
+ if (!(filenames && [filenames count] > 0))
+ return;
+
+ //
+ // a) Extract ODB/Xcode/Spotlight parameters from the current Apple event
+ //
NSMutableDictionary *arguments = [self extractArgumentsFromOdocEvent:
[[NSAppleEventManager sharedAppleEventManager] currentAppleEvent]];
- // Filter out files that are already open
- filenames = [self filterOpenFiles:filenames arguments:arguments];
+ //
+ // b) Filter out any already open files
+ //
+ NSString *firstFile = [filenames objectAtIndex:0];
+ MMVimController *firstController = nil;
+ NSDictionary *openFilesDict = nil;
+ filenames = [self filterOpenFiles:filenames openFilesDict:&openFilesDict];
- // Open any files that remain
- if ([filenames count]) {
- MMVimController *vc;
- BOOL openInTabs = [[NSUserDefaults standardUserDefaults]
- boolForKey:MMOpenFilesInTabsKey];
+ // Pass arguments to vim controllers that had files open.
+ id key;
+ NSEnumerator *e = [openFilesDict keyEnumerator];
- [arguments setObject:filenames forKey:@"filenames"];
- [arguments setObject:[NSNumber numberWithBool:YES] forKey:@"openFiles"];
+ // (Indicate that we do not wish to open any files at the moment.)
+ [arguments setObject:[NSNumber numberWithBool:YES] forKey:@"dontOpen"];
- // Add file names to "Recent Files" menu.
- int i, count = [filenames count];
- for (i = 0; i < count; ++i) {
- // Don't add files that are being edited remotely (using ODB).
- if ([arguments objectForKey:@"remoteID"]) continue;
+ while ((key = [e nextObject])) {
+ NSArray *files = [openFilesDict objectForKey:key];
+ [arguments setObject:files forKey:@"filenames"];
- [[NSDocumentController sharedDocumentController]
- noteNewRecentFilePath:[filenames objectAtIndex:i]];
- }
+ MMVimController *vc = [key pointerValue];
+ [vc passArguments:arguments];
- if ((openInTabs && (vc = [self topmostVimController]))
- || (vc = [self findUntitledWindow])) {
- // Open files in an already open window.
- [[[vc windowController] window] makeKeyAndOrderFront:self];
- [self passArguments:arguments toVimController:vc];
- } else {
- // Open files in a launching Vim process or start a new process.
- int pid = [self findLaunchingProcessWithoutArguments];
- if (!pid) {
- // Pass the filenames to the process straight away.
- //
- // TODO: It would be nicer if all arguments were passed to the
- // Vim process in connectBackend::, but if we don't pass the
- // filename arguments here, the window 'flashes' once when it
- // opens. This is due to the 'welcome' screen first being
- // displayed, then quickly thereafter the files are opened.
- NSArray *fileArgs = [NSArray arrayWithObject:@"-p"];
- fileArgs = [fileArgs arrayByAddingObjectsFromArray:filenames];
-
- pid = [self launchVimProcessWithArguments:fileArgs];
-
- if (-1 == pid) {
- // TODO: Notify user of failure?
- [NSApp replyToOpenOrPrint:
- NSApplicationDelegateReplyFailure];
- return;
- }
-
- // Make sure these files aren't opened again when
- // connectBackend:pid: is called.
- [arguments setObject:[NSNumber numberWithBool:NO]
- forKey:@"openFiles"];
- }
+ // If this controller holds the first file, then remember it for later.
+ if ([files containsObject:firstFile])
+ firstController = vc;
+ }
- // TODO: If the Vim process fails to start, or if it changes PID,
- // then the memory allocated for these parameters will leak.
- // Ensure that this cannot happen or somehow detect it.
+ if ([filenames count] == 0) {
+ // 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 when there are no more files to open, otherwise sometimes
+ // the window with 'firstFile' will be raised, other times it might be
+ // the window that will open with the files in the 'filenames' array.
+ firstFile = [firstFile stringByEscapingSpecialFilenameCharacters];
+ NSString *input = [NSString stringWithFormat:@"<C-\\><C-N>"
+ ":let oldswb=&swb|let &swb=\"useopen,usetab\"|"
+ "tab sb %@|let &swb=oldswb|unl oldswb|"
+ "cal foreground()|redr|f<CR>", firstFile];
+
+ [firstController addVimInput:input];
+
+ [NSApp replyToOpenOrPrint:NSApplicationDelegateReplySuccess];
+ return;
+ }
+
+ // Add filenames to "Recent Files" menu, unless they are being edited
+ // remotely (using ODB).
+ if ([arguments objectForKey:@"remoteID"] == nil) {
+ [[NSDocumentController sharedDocumentController]
+ noteNewRecentFilePaths:filenames];
+ }
- if ([arguments count] > 0)
- [pidArguments setObject:arguments
- forKey:[NSNumber numberWithInt:pid]];
+ //
+ // c) Open any remaining files
+ //
+ MMVimController *vc;
+ NSUserDefaults *ud = [NSUserDefaults standardUserDefaults];
+ BOOL openInCurrentWindow = [ud boolForKey:MMOpenInCurrentWindowKey];
+
+ // The meaning of "layout" is defined by the WIN_* defines in main.c.
+ int layout = [ud integerForKey:MMOpenLayoutKey];
+ BOOL splitVert = [ud boolForKey:MMVerticalSplitKey];
+ if (splitVert && MMLayoutHorizontalSplit == layout)
+ layout = MMLayoutVerticalSplit;
+ if (layout < 0 || (layout > MMLayoutTabs && openInCurrentWindow))
+ layout = MMLayoutTabs;
+
+ [arguments setObject:[NSNumber numberWithInt:layout] forKey:@"layout"];
+ [arguments setObject:filenames forKey:@"filenames"];
+ // (Indicate that files should be opened from now on.)
+ [arguments setObject:[NSNumber numberWithBool:NO] forKey:@"dontOpen"];
+
+ if (openInCurrentWindow && (vc = [self topmostVimController])) {
+ // Open files in an already open window.
+ [[[vc windowController] window] makeKeyAndOrderFront:self];
+ [vc passArguments:arguments];
+ [NSApp replyToOpenOrPrint:NSApplicationDelegateReplySuccess];
+ return;
+ }
+
+ BOOL openOk = YES;
+ int numFiles = [filenames count];
+ if (MMLayoutWindows == layout && numFiles > 1) {
+ // Open one file at a time in a new window, but don't open too many at
+ // once (at most cap+1 windows will open). If the user has increased
+ // the preload cache size we'll take that as a hint that more windows
+ // should be able to open at once.
+ int cap = [self maxPreloadCacheSize] - 1;
+ if (cap < 4) cap = 4;
+ if (cap > numFiles) cap = numFiles;
+
+ int i;
+ for (i = 0; i < cap; ++i) {
+ NSArray *a = [NSArray arrayWithObject:[filenames objectAtIndex:i]];
+ [arguments setObject:a forKey:@"filenames"];
+
+ // NOTE: We have to copy the args since we'll mutate them in the
+ // next loop and the below call may retain the arguments while
+ // waiting for a process to start.
+ NSDictionary *args = [[arguments copy] autorelease];
+
+ openOk = [self openVimControllerWithArguments:args];
+ if (!openOk) break;
}
+
+ // Open remaining files in tabs in a new window.
+ if (openOk && numFiles > cap) {
+ NSRange range = { i, numFiles-cap };
+ NSArray *a = [filenames subarrayWithRange:range];
+ [arguments setObject:a forKey:@"filenames"];
+ [arguments setObject:[NSNumber numberWithInt:MMLayoutTabs]
+ forKey:@"layout"];
+
+ openOk = [self openVimControllerWithArguments:arguments];
+ }
+ } else {
+ // Open all files at once.
+ openOk = [self openVimControllerWithArguments:arguments];
}
- [NSApp replyToOpenOrPrint:NSApplicationDelegateReplySuccess];
- // NSApplicationDelegateReplySuccess = 0,
- // NSApplicationDelegateReplyCancel = 1,
- // NSApplicationDelegateReplyFailure = 2
+ if (openOk) {
+ [NSApp replyToOpenOrPrint:NSApplicationDelegateReplySuccess];
+ } else {
+ // TODO: Notify user of failure?
+ [NSApp replyToOpenOrPrint:NSApplicationDelegateReplyFailure];
+ }
}
- (BOOL)applicationShouldTerminateAfterLastWindowClosed:(NSApplication *)sender
@@ -521,6 +596,10 @@ - (NSApplicationTerminateReply)applicationShouldTerminate:
while ((vc = [e nextObject]))
[vc sendMessage:TerminateNowMsgID data:nil];
+ e = [cachedVimControllers objectEnumerator];
+ while ((vc = [e nextObject]))
+ [vc sendMessage:TerminateNowMsgID data:nil];
+
// Give Vim processes a chance to terminate before MacVim. If they
// haven't terminated by the time applicationWillTerminate: is sent,
// they may be forced to quit (see below).
@@ -553,7 +632,7 @@ - (void)applicationWillTerminate:(NSNotification *)notification
for (i = 0; i < count; ++i) {
MMVimController *controller = [vimControllers objectAtIndex:i];
int pid = [controller pid];
- if (pid > 0)
+ if (-1 != pid)
kill(pid, SIGINT);
}
@@ -585,12 +664,13 @@ - (NSMenuItem *)appMenuItemTemplate
- (void)removeVimController:(id)controller
{
- //NSLog(@"%s%@", _cmd, controller);
+ int idx = [vimControllers indexOfObject:controller];
+ if (NSNotFound == idx)
+ return;
[controller cleanup];
- [[controller windowController] close];
- [vimControllers removeObject:controller];
+ [vimControllers removeObjectAtIndex:idx];
if (![vimControllers count]) {
// The last editor window just closed so restore the main menu back to
@@ -626,6 +706,13 @@ - (void)windowControllerWillOpen:(MMWindowController *)windowController
[win setFrameTopLeftPoint:topLeft];
}
+ if (1 == [vimControllers count]) {
+ // The first window autosaves its position. (The autosaving
+ // features of Cocoa are not used because we need more control over
+ // what is autosaved and when it is restored.)
+ [windowController setWindowAutosaveKey:MMTopLeftPointKey];
+ }
+
if (openSelectionString) {
// TODO: Pass this as a parameter instead! Get rid of
// 'openSelectionString' etc.
@@ -707,6 +794,11 @@ - (void)setMainMenu:(NSMenu *)mainMenu
#endif
}
+- (NSArray *)filterOpenFiles:(NSArray *)filenames
+{
+ return [self filterOpenFiles:filenames openFilesDict:nil];
+}
+
#ifdef MM_ENABLE_PLUGINS
- (void)addItemToPlugInMenu:(NSMenuItem *)item
{
@@ -727,7 +819,25 @@ - (void)removeItemFromPlugInMenu:(NSMenuItem *)item
- (IBAction)newWindow:(id)sender
{
+ // A cached controller requires no loading times and results in the new
+ // window popping up instantaneously. If the cache is empty it may take
+ // 1-2 seconds to start a new Vim process.
+ if ([cachedVimControllers count]) {
+ MMVimController *vc = [self takeVimControllerFromCache];
+ [[vc backendProxy] acknowledgeConnection];
+ } else {
+ [self launchVimProcessWithArguments:nil];
+ }
+}
+
+- (IBAction)forceNewWindow:(id)sender
+{
+ // Open a new window, but clear the preload cache first so that any
+ // subsequent windows opening will have sourced the current .[g]vimrc
+ // files.
+ [self clearPreloadCache];
[self launchVimProcessWithArguments:nil];
+ [self scheduleVimControllerPreloadAfterDelay:2.0];
}
- (IBAction)fileOpen:(id)sender
@@ -827,22 +937,23 @@ - (IBAction)zoomAll:(id)sender
[(NSDistantObject*)backend
setProtocolForProxy:@protocol(MMBackendProtocol)];
- vc = [[[MMVimController alloc]
- initWithBackend:backend pid:pid]
- autorelease];
+ vc = [[[MMVimController alloc] initWithBackend:backend pid:pid]
+ autorelease];
- if (![vimControllers count]) {
- // The first window autosaves its position. (The autosaving
- // features of Cocoa are not used because we need more control over
- // what is autosaved and when it is restored.)
- [[vc windowController] setWindowAutosaveKey:MMTopLeftPointKey];
+ if (preloadPid == pid) {
+ // This backend was preloaded, so add it to the cache and schedule
+ // another vim process to be preloaded.
+ preloadPid = -1;
+ [cachedVimControllers addObject:vc];
+ [self scheduleVimControllerPreloadAfterDelay:1];
+ return vc;
}
[vimControllers addObject:vc];
id args = [pidArguments objectForKey:pidKey];
if (args && [NSNull null] != args)
- [self passArguments:args toVimController:vc];
+ [vc passArguments:args];
// HACK! MacVim does not get activated if it is launched from the
// terminal, so we forcibly activate here unless it is an untitled
@@ -1081,48 +1192,33 @@ - (NSArray *)filterFilesAndNotify:(NSArray *)filenames
}
- (NSArray *)filterOpenFiles:(NSArray *)filenames
- arguments:(NSDictionary *)args
+ openFilesDict:(NSDictionary **)openFiles
{
- // 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. Files that are filtered are sent an odb
- // open event in case theID is not zero.
-
- NSMutableDictionary *localArgs =
- [NSMutableDictionary dictionaryWithDictionary:args];
- MMVimController *raiseController = nil;
- NSString *raiseFile = nil;
+ // Filter out any files in the 'filenames' array that are open and return
+ // all files that are not already open. On return, the 'openFiles'
+ // parameter (if non-nil) will point to a dictionary of open files, indexed
+ // by Vim controller.
+
+ NSMutableDictionary *dict = [NSMutableDictionary dictionary];
NSMutableArray *files = [filenames mutableCopy];
+
+ // TODO: Escape special characters in 'files'?
NSString *expr = [NSString stringWithFormat:
@"map([\"%@\"],\"bufloaded(v:val)\")",
[files componentsJoinedByString:@"\",\""]];
- unsigned i, count = [vimControllers count];
- // Ensure that the files aren't opened when passing arguments.
- [localArgs setObject:[NSNumber numberWithBool:NO] forKey:@"openFiles"];
-
- for (i = 0; i < count && [files count]; ++i) {
- MMVimController *controller = [vimControllers objectAtIndex:i];
+ unsigned i, count = [vimControllers count];
+ for (i = 0; i < count && [files count] > 0; ++i) {
+ MMVimController *vc = [vimControllers objectAtIndex:i];
// Query Vim for which files in the 'files' array are open.
- NSString *eval = [controller evaluateVimExpression:expr];
+ NSString *eval = [vc evaluateVimExpression:expr];
if (!eval) continue;
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];
- }
-
- // Pass (ODB/Xcode/Spotlight) arguments to this process.
- [localArgs setObject:[files objectsAtIndexes:idxSet]
- forKey:@"filenames"];
- [self passArguments:localArgs toVimController:controller];
+ if ([idxSet count] > 0) {
+ [dict setObject:[files objectsAtIndexes:idxSet]
+ forKey:[NSValue valueWithPointer:vc]];
// Remove all the files that were open in this Vim process and
// create a new expression to evaluate.
@@ -1133,20 +1229,8 @@ - (NSArray *)filterOpenFiles:(NSArray *)filenames
}
}
- 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:@"<C-\\><C-N>"
- ":let oldswb=&swb|let &swb=\"useopen,usetab\"|"
- "tab sb %@|let &swb=oldswb|unl oldswb|"
- "cal foreground()|redr|f<CR>", raiseFile];
-
- [raiseController addVimInput:input];
- }
+ if (openFiles != nil)
+ *openFiles = dict;
return files;
}
@@ -1186,7 +1270,7 @@ - (int)findLaunchingProcessWithoutArguments
return [[keys objectAtIndex:0] intValue];
}
- return 0;
+ return -1;
}
- (MMVimController *)findUntitledWindow
@@ -1234,8 +1318,11 @@ - (NSMutableDictionary *)extractArgumentsFromOdocEvent:
[dict setObject:[p stringValue] forKey:@"remotePath"];
p = [odbdesc paramDescriptorForKeyword:keyFileSenderToken];
- if (p)
- [dict setObject:p forKey:@"remotePath"];
+ if (p) {
+ [dict setObject:[NSNumber numberWithUnsignedLong:[p descriptorType]]
+ forKey:@"remoteTokenDescType"];
+ [dict setObject:[p data] forKey:@"remoteTokenData"];
+ }
}
// 2. Extract Xcode parameters (if any)
@@ -1267,39 +1354,6 @@ - (NSMutableDictionary *)extractArgumentsFromOdocEvent:
return dict;
}
-- (void)passArguments:(NSDictionary *)args toVimController:(MMVimController*)vc
-{
- if (!args) return;
-
- // Pass filenames to open if required (the 'openFiles' argument can be used
- // to disallow opening of the files).
- NSArray *filenames = [args objectForKey:@"filenames"];
- if (filenames && [[args objectForKey:@"openFiles"] boolValue]) {
- NSString *tabDrop = buildTabDropCommand(filenames);
- [vc addVimInput:tabDrop];
- }
-
- // Pass ODB data
- if (filenames && [args objectForKey:@"remoteID"]) {
- [vc odbEdit:filenames
- server:[[args objectForKey:@"remoteID"] unsignedIntValue]
- path:[args objectForKey:@"remotePath"]
- token:[args objectForKey:@"remoteToken"]];
- }
-
- // Pass range of lines to select
- if ([args objectForKey:@"selectionRange"]) {
- NSRange selectionRange = NSRangeFromString(
- [args objectForKey:@"selectionRange"]);
- [vc addVimInput:buildSelectRangeCommand(selectionRange)];
- }
-
- // Pass search text
- NSString *searchText = [args objectForKey:@"searchText"];
- if (searchText)
- [vc addVimInput:buildSearchTextCommand(searchText)];
-}
-
#ifdef MM_ENABLE_PLUGINS
- (void)removePlugInMenu
{
@@ -1323,6 +1377,128 @@ - (void)addPlugInMenuToMenu:(NSMenu *)mainMenu
}
#endif
+- (void)scheduleVimControllerPreloadAfterDelay:(NSTimeInterval)delay
+{
+ [self performSelector:@selector(preloadVimController:)
+ withObject:nil
+ afterDelay:delay];
+}
+
+- (void)preloadVimController:(id)sender
+{
+ // We only allow preloading of one Vim process at a time (to avoid hogging
+ // CPU), so schedule another preload in a little while if necessary.
+ if (-1 != preloadPid) {
+ [self scheduleVimControllerPreloadAfterDelay:2];
+ return;
+ }
+
+ if ([cachedVimControllers count] >= [self maxPreloadCacheSize])
+ return;
+
+ preloadPid = [self launchVimProcessWithArguments:
+ [NSArray arrayWithObject:@"--mmwaitforack"]];
+}
+
+- (int)maxPreloadCacheSize
+{
+ // The maximum number of Vim processes to keep in the cache can be
+ // controlled via the user default "MMPreloadCacheSize".
+ int maxCacheSize = [[NSUserDefaults standardUserDefaults]
+ integerForKey:MMPreloadCacheSizeKey];
+ if (maxCacheSize < 0) maxCacheSize = 0;
+ else if (maxCacheSize > 10) maxCacheSize = 10;
+
+ return maxCacheSize;
+}
+
+- (MMVimController *)takeVimControllerFromCache
+{
+ // NOTE: After calling this message the backend corresponding to the
+ // returned vim controller must be sent an acknowledgeConnection message,
+ // else the vim process will be stuck.
+
+ if ([cachedVimControllers count] == 0) return nil;
+
+ MMVimController *vc = [cachedVimControllers objectAtIndex:0];
+ [vimControllers addObject:vc];
+ [cachedVimControllers removeObjectAtIndex:0];
+
+ // Since we've taken one controller from the cache we take the opportunity
+ // to preload another.
+ [self scheduleVimControllerPreloadAfterDelay:1];
+
+ return vc;
+}
+
+- (void)clearPreloadCache
+{
+ if ([cachedVimControllers count] == 0)
+ return;
+
+ // Make sure the preloaded Vim processes get killed or they'll just hang
+ // around being useless until MacVim is terminated.
+ NSEnumerator *e = [cachedVimControllers objectEnumerator];
+ MMVimController *vc;
+ while ((vc = [e nextObject])) {
+ [[NSNotificationCenter defaultCenter] removeObserver:vc];
+ [vc sendMessage:TerminateNowMsgID data:nil];
+ }
+
+ // Since the preloaded processes were killed "prematurely" we have to
+ // manually tell them to cleanup (it is not enough to simply release them
+ // since deallocation and cleanup are separated).
+ [cachedVimControllers makeObjectsPerformSelector:@selector(cleanup)];
+
+ [cachedVimControllers removeAllObjects];
+}
+
+- (BOOL)openVimControllerWithArguments:(NSDictionary *)arguments
+{
+ MMVimController *vc = [self findUntitledWindow];
+ if (vc) {
+ // Open files in an already open window.
+ [[[vc windowController] window] makeKeyAndOrderFront:self];
+ [vc passArguments:arguments];
+
+ // HACK! Change window title so that findUntitledWindow does not think
+ // this window is untitled anymore, in case this method is called
+ // before the arguments have reached the Vim process and it in turn has
+ // responded by setting the window title.
+ //
+ // TODO: When the findUntitledWindow heuristic changes, this has to be
+ // fixed for real.
+ [[vc windowController] setTitle:@""];
+ } else if ([cachedVimControllers count] > 0) {
+ // Open files in a new window using a cached vim controller. This
+ // requires virtually no loading time so the new window will pop up
+ // instantaneously.
+ vc = [self takeVimControllerFromCache];
+ [vc passArguments:arguments];
+ [[vc backendProxy] acknowledgeConnection];
+ } else {
+ // Open files in a launching Vim process or start a new process. This
+ // may take 1-2 seconds so there will be a visible delay before the
+ // window appears on screen.
+ int pid = [self findLaunchingProcessWithoutArguments];
+ if (-1 == pid) {
+ pid = [self launchVimProcessWithArguments:nil];
+ if (-1 == pid)
+ return NO;
+ }
+
+ // TODO: If the Vim process fails to start, or if it changes PID,
+ // then the memory allocated for these parameters will leak.
+ // Ensure that this cannot happen or somehow detect it.
+
+ if ([arguments count] > 0)
+ [pidArguments setObject:arguments
+ forKey:[NSNumber numberWithInt:pid]];
+ }
+
+ return YES;
+}
+
@end // MMAppController (Private)
View
15 src/MacVim/MMBackend.h
@@ -46,6 +46,9 @@
ATSFontContainerRef fontContainerRef;
NSFont *oldWideFont;
BOOL isTerminating;
+ BOOL waitForAck;
+ int initialWindowLayout;
+ BOOL flushDisabled;
}
+ (MMBackend *)sharedInstance;
@@ -56,6 +59,7 @@
- (void)setDefaultColorsBackground:(int)bg foreground:(int)fg;
- (NSConnection *)connection;
- (NSDictionary *)actionDict;
+- (int)initialWindowLayout;
- (void)queueMessage:(int)msgid properties:(NSDictionary *)props;
- (BOOL)checkin;
@@ -123,4 +127,15 @@
- (NSString *)waitForReplyOnPort:(int)port;
- (BOOL)sendReply:(NSString *)reply toPort:(int)port;
+- (BOOL)waitForAck;
+- (void)setWaitForAck:(BOOL)yn;
+- (void)waitForConnectionAcknowledgement;
+
+@end
+
+
+
+@interface NSString (VimStrings)
++ (id)stringWithVimString:(char_u *)s;
+- (char_u *)vimStringSave;
@end
View
487 src/MacVim/MMBackend.m
@@ -39,6 +39,10 @@
((unsigned)( ((col)&0xffffff) \
| ((((unsigned)((((100-(transp))*255)/100)+.5f))&0xff)<<24) ))
+// Values for window layout (must match values in main.c).
+#define WIN_HOR 1 // "-o" horizontally split windows
+#define WIN_VER 2 // "-O" vertically split windows
+#define WIN_TABS 3 // "-p" windows on tab pages
// This constant controls how often the command queue may be flushed. If it is
// too small the app might feel unresponsive; if it is too large there might be
@@ -54,6 +58,7 @@
static int eventModifierFlagsToVimMouseModMask(int modifierFlags);
static int eventButtonNumberToVimMouseButton(int buttonNumber);
+
// In gui_macvim.m
vimmenu_T *menu_for_descriptor(NSArray *desc);
@@ -97,8 +102,9 @@ - (void)handleScrollbarEvent:(NSData *)data;
- (void)handleSetFont:(NSData *)data;
- (void)handleDropFiles:(NSData *)data;
- (void)handleDropString:(NSData *)data;
-- (void)handleOdbEdit:(NSData *)data;
+- (void)startOdbEditWithArguments:(NSDictionary *)args;
- (void)handleXcodeMod:(NSData *)data;
+- (void)handleOpenWithArguments:(NSDictionary *)args;
- (BOOL)checkForModifiedBuffers;
- (void)addInput:(NSString *)input;
@end
@@ -231,6 +237,11 @@ - (NSDictionary *)actionDict
return actionDict;
}
+- (int)initialWindowLayout
+{
+ return initialWindowLayout;
+}
+
- (void)queueMessage:(int)msgid properties:(NSDictionary *)props
{
[self queueMessage:msgid data:[props dictionaryAsData]];
@@ -239,6 +250,14 @@ - (void)queueMessage:(int)msgid properties:(NSDictionary *)props
- (BOOL)checkin
{
if (![self connection]) {
+ if (waitForAck) {
+ // This is a preloaded process and as such should not cause the
+ // MacVim to be opened. We probably got here as a result of the
+ // user quitting MacVim while the process was preloading, so exit
+ // this process too.
+ mch_exit(0);
+ }
+
NSBundle *mainBundle = [NSBundle mainBundle];
#if 0
OSStatus status;
@@ -460,6 +479,12 @@ - (void)update
- (void)flushQueue:(BOOL)force
{
+ // NOTE: This variable allows for better control over when the queue is
+ // flushed. It can be set to YES at the beginning of a sequence of calls
+ // that may potentially add items to the queue, and then restored back to
+ // NO.
+ if (flushDisabled) return;
+
// NOTE! This method gets called a lot; if we were to flush every time it
// got called MacVim would feel unresponsive. So there is a time out which
// ensures that the queue isn't flushed too often.
@@ -540,19 +565,39 @@ - (BOOL)waitForInput:(int)milliseconds
- (void)exit
{
+ // To notify MacVim that this Vim process is exiting we could simply
+ // invalidate the connection and it would automatically receive a
+ // connectionDidDie: notification. However, this notification seems to
+ // take up to 300 ms to arrive which is quite a noticeable delay. Instead
+ // we immediately send a message to MacVim asking it to close the window
+ // belonging to this process, and then we invalidate the connection (in
+ // case the message got lost).
+
+ // Make sure no connectionDidDie: notification is received now that we are
+ // already exiting.
+ [[NSNotificationCenter defaultCenter] removeObserver:self];
+
+ if ([connection isValid]) {
+ @try {
+ int msgid = CloseWindowMsgID;
+ NSData *data = [NSData dataWithBytes:&msgid length:sizeof(int)];
+ NSArray *q = [NSArray arrayWithObjects:data, [NSData data], nil];
+ [frontendProxy processCommandQueue:q];
+ //usleep(10000);
+ }
+ @catch (NSException *e) {
+ NSLog(@"Exception caught when sending CloseWindowMsgID: \"%@\"", e);
+ }
+
+ [connection invalidate];
+ }
+
#ifdef MAC_CLIENTSERVER
// The default connection is used for the client/server code.
[[NSConnection defaultConnection] setRootObject:nil];
[[NSConnection defaultConnection] invalidate];
#endif
- // By invalidating the NSConnection the MMWindowController immediately
- // finds out that the connection is down and as a result
- // [MMWindowController connectionDidDie:] is invoked.
- //NSLog(@"%@ %s", [self className], _cmd);
- [[NSNotificationCenter defaultCenter] removeObserver:self];
- [connection invalidate];
-
if (fontContainerRef) {
ATSFontDeactivate(fontContainerRef, NULL, kATSOptionFlagsDefault);
fontContainerRef = 0;
@@ -1463,6 +1508,48 @@ - (BOOL)sendReply:(NSString *)reply toPort:(int)port
return NO;
}
+- (BOOL)waitForAck
+{
+ return waitForAck;
+}
+
+- (void)setWaitForAck:(BOOL)yn
+{
+ waitForAck = yn;
+}
+
+- (void)waitForConnectionAcknowledgement
+{
+ if (!waitForAck) return;
+
+ while (waitForAck && !got_int && [connection isValid] && !isTerminating) {
+ [[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode
+ beforeDate:[NSDate distantFuture]];
+ //NSLog(@" waitForAck=%d got_int=%d isTerminating=%d isValid=%d",
+ // waitForAck, got_int, isTerminating, [connection isValid]);
+ }
+
+ if (waitForAck) {
+ // Never received a connection acknowledgement, so die.
+ [[NSNotificationCenter defaultCenter] removeObserver:self];
+ [frontendProxy release]; frontendProxy = nil;
+
+ // NOTE: We intentionally do not call mch_exit() since this in turn
+ // will lead to -[MMBackend exit] getting called which we want to
+ // avoid.
+ exit(0);
+ }
+
+ [self processInputQueue];
+ [self openVimWindow];
+}
+
+- (oneway void)acknowledgeConnection
+{
+ //NSLog(@"%s", _cmd);
+ waitForAck = NO;
+}
+
@end // MMBackend
@@ -1558,14 +1645,6 @@ - (void)processInputQueue
- (void)handleInputEvent:(int)msgid data:(NSData *)data
{
- // NOTE: Be careful with what you do in this method. Ideally, a message
- // should be handled by adding something to the input buffer and returning
- // immediately. If you call a Vim function then it should not enter a loop
- // waiting for key presses or in any other way block the process. The
- // reason for this being that only one message can be processed at a time,
- // so if another message is received while processing, then the new message
- // is dropped. See also the comment in processInput:data:.
-
//NSLog(@"%s%s", _cmd, MessageStrings[msgid]);
if (SelectTabMsgID == msgid) {
@@ -1635,10 +1714,10 @@ - (void)handleInputEvent:(int)msgid data:(NSData *)data
const void *bytes = [data bytes];
int shape = *((int*)bytes); bytes += sizeof(int);
update_mouseshape(shape);
- } else if (ODBEditMsgID == msgid) {
- [self handleOdbEdit:data];
} else if (XcodeModMsgID == msgid) {
[self handleXcodeMod:data];
+ } else if (OpenWithArgumentsMsgID == msgid) {
+ [self handleOpenWithArguments:[NSDictionary dictionaryWithData:data]];
} else {
NSLog(@"WARNING: Unknown message received (msgid=%d)", msgid);
}
@@ -1843,6 +1922,8 @@ - (void)connectionDidDie:(NSNotification *)notification
// crashed. In the former case the flag 'isTerminating' is set and we then
// quit cleanly; in the latter case we make sure the swap files are left
// for recovery.
+ //
+ // NOTE: This is not called if a Vim controller invalidates its connection.
//NSLog(@"%s isTerminating=%d", _cmd, isTerminating);
if (isTerminating)
@@ -2022,79 +2103,40 @@ - (void)handleDropFiles:(NSData *)data
if (!data) return;
-#ifdef FEAT_DND
- const void *bytes = [data bytes];
- const void *end = [data bytes] + [data length];
- BOOL forceOpen = *((BOOL*)bytes); bytes += sizeof(BOOL);
- int n = *((int*)bytes); bytes += sizeof(int);
+ NSMutableDictionary *args = [NSMutableDictionary dictionaryWithData:data];
+ if (!args) return;
+
+ id obj = [args objectForKey:@"forceOpen"];
+ BOOL forceOpen = YES;
+ if (obj)
+ forceOpen = [obj boolValue];
+ NSArray *filenames = [args objectForKey:@"filenames"];
+ if (!(filenames && [filenames count] > 0)) return;
+
+#ifdef FEAT_DND
if (!forceOpen && (State & CMDLINE)) {
// HACK! If Vim is in command line mode then the files names
// should be added to the command line, instead of opening the
// files in tabs (unless forceOpen is set). This is taken care of by
// gui_handle_drop().
+ int n = [filenames count];
char_u **fnames = (char_u **)alloc(n * sizeof(char_u *));
if (fnames) {
int i = 0;
- while (bytes < end && i < n) {
- int len = *((int*)bytes); bytes += sizeof(int);
- char_u *s = (char_u*)bytes;
-#ifdef FEAT_MBYTE
- s = CONVERT_FROM_UTF8(s);
-#endif
- fnames[i++] = vim_strsave(s);
-#ifdef FEAT_MBYTE
- CONVERT_FROM_UTF8_FREE(s);
-#endif
- bytes += len;
- }
+ for (i = 0; i < n; ++i)
+ fnames[i] = [[filenames objectAtIndex:i] vimStringSave];
// NOTE! This function will free 'fnames'.
// HACK! It is assumed that the 'x' and 'y' arguments are
// unused when in command line mode.
- gui_handle_drop(0, 0, 0, fnames, i < n ? i : n);
- }
- } else {
- // HACK! I'm not sure how to get Vim to open a list of files in
- // tabs, so instead I create a ':tab drop' command with all the
- // files to open and execute it.
- NSMutableString *cmd = [NSMutableString stringWithString:@":tab drop"];
-
- int i;
- for (i = 0; i < n && bytes < end; ++i) {
- int len = *((int*)bytes); bytes += sizeof(int);
- NSString *file = [NSString stringWithUTF8String:bytes];
- file = [file stringByEscapingSpecialFilenameCharacters];
- bytes += len;
-
- [cmd appendString:@" "];
- [cmd appendString:file];
+ gui_handle_drop(0, 0, 0, fnames, n);
}
-
- // By going to the last tabpage we ensure that the new tabs will
- // appear last (if this call is left out, the taborder becomes
- // messy).
- goto_tabpage(9999);
-
- char_u *s = (char_u*)[cmd UTF8String];
-#ifdef FEAT_MBYTE
- s = CONVERT_FROM_UTF8(s);
-#endif
- do_cmdline_cmd(s);
-#ifdef FEAT_MBYTE
- CONVERT_FROM_UTF8_FREE(s);
-#endif
-
- // Force screen redraw (does it have to be this complicated?).
- // (This code was taken from the end of gui_handle_drop().)
- update_screen(NOT_VALID);
- setcursor();
- out_flush();
- gui_update_cursor(FALSE, FALSE);
- maketitle();
- gui_mch_flush();
- }
+ } else
#endif // FEAT_DND
+ {
+ [self handleOpenWithArguments:args];
+ }
}
- (void)handleDropString:(NSData *)data
@@ -2132,41 +2174,32 @@ - (void)handleDropString:(NSData *)data
#endif // FEAT_DND
}
-- (void)handleOdbEdit:(NSData *)data
+- (void)startOdbEditWithArguments:(NSDictionary *)args
{
#ifdef FEAT_ODB_EDITOR
- const void *bytes = [data bytes];
+ id obj = [args objectForKey:@"remoteID"];
+ if (!obj) return;
- OSType serverID = *((OSType*)bytes); bytes += sizeof(OSType);
-
- char_u *path = NULL;
- int pathLen = *((int*)bytes); bytes += sizeof(int);
- if (pathLen > 0) {
- path = (char_u*)bytes;
- bytes += pathLen;
-#ifdef FEAT_MBYTE
- path = CONVERT_FROM_UTF8(path);
-#endif
- }
+ OSType serverID = [obj unsignedIntValue];
+ NSString *remotePath = [args objectForKey:@"remotePath"];
NSAppleEventDescriptor *token = nil;
- DescType tokenType = *((DescType*)bytes); bytes += sizeof(DescType);
- int descLen = *((int*)bytes); bytes += sizeof(int);
- if (descLen > 0) {
+ NSData *tokenData = [args objectForKey:@"remoteTokenData"];
+ obj = [args objectForKey:@"remoteTokenDescType"];
+ if (tokenData && obj) {
+ DescType tokenType = [obj unsignedLongValue];
token = [NSAppleEventDescriptor descriptorWithDescriptorType:tokenType
- bytes:bytes
- length:descLen];
- bytes += descLen;
+ data:tokenData];
}
- unsigned i, numFiles = *((unsigned*)bytes); bytes += sizeof(unsigned);
+ NSArray *filenames = [args objectForKey:@"filenames"];
+ unsigned i, numFiles = [filenames count];
for (i = 0; i < numFiles; ++i) {
- int len = *((int*)bytes); bytes += sizeof(int);
- char_u *filename = (char_u*)bytes;
-#ifdef FEAT_MBYTE
- filename = CONVERT_FROM_UTF8(filename);
-#endif
- buf_T *buf = buflist_findname(filename);
+ NSString *filename = [filenames objectAtIndex:i];
+ char_u *s = [filename vimStringSave];
+ buf_T *buf = buflist_findname(s);
+ vim_free(s);
+
if (buf) {
if (buf->b_odb_token) {
[(NSAppleEventDescriptor*)(buf->b_odb_token) release];
@@ -2182,21 +2215,13 @@ - (void)handleOdbEdit:(NSData *)data
if (token)
buf->b_odb_token = [token retain];
- if (path)
- buf->b_odb_fname = vim_strsave(path);
+ if (remotePath)
+ buf->b_odb_fname = [remotePath vimStringSave];
} else {
- NSLog(@"WARNING: Could not find buffer '%s' for ODB editing.",
+ NSLog(@"WARNING: Could not find buffer '%@' for ODB editing.",
filename);
}
-
-#ifdef FEAT_MBYTE
- CONVERT_FROM_UTF8_FREE(filename);
-#endif
- bytes += len;
}
-#ifdef FEAT_MBYTE
- CONVERT_FROM_UTF8_FREE(path);
-#endif
#endif // FEAT_ODB_EDITOR
}
@@ -2216,6 +2241,193 @@ - (void)handleXcodeMod:(NSData *)data
#endif
}
+- (void)handleOpenWithArguments:(NSDictionary *)args
+{
+ // ARGUMENT: DESCRIPTION:
+ // -------------------------------------------------------------
+ // filenames list of filenames
+ // dontOpen don't open files specified in above argument
+ // layout which layout to use to open files
+ // selectionRange range to select
+ // searchText string to search for
+ // remoteID ODB parameter
+ // remotePath ODB parameter
+ // remoteTokenDescType ODB parameter
+ // remoteTokenData ODB parameter
+
+ //NSLog(@"%s%@ (starting=%d)", _cmd, args, starting);
+
+ NSArray *filenames = [args objectForKey:@"filenames"];
+ int i, numFiles = filenames ? [filenames count] : 0;
+ BOOL openFiles = ![[args objectForKey:@"dontOpen"] boolValue];
+ int layout = [[args objectForKey:@"layout"] intValue];
+
+ if (starting > 0) {
+ // When Vim is starting we simply add the files to be opened to the
+ // global arglist and Vim will take care of opening them for us.
+ if (openFiles && numFiles > 0) {
+ for (i = 0; i < numFiles; i++) {
+ NSString *fname = [filenames objectAtIndex:i];
+ char_u *p = NULL;
+
+ if (ga_grow(&global_alist.al_ga, 1) == FAIL
+ || (p = [fname vimStringSave]) == NULL)
+ mch_exit(2);
+ else
+ alist_add(&global_alist, p, 2);
+ }
+
+ // Vim will take care of arranging the files added to the arglist
+ // in windows or tabs; all we must do is to specify which layout to
+ // use.
+ initialWindowLayout = layout;
+ }
+ } else {
+ // When Vim is already open we resort to some trickery to open the
+ // files with the specified layout.
+ //
+ // TODO: Figure out a better way to handle this?
+ if (openFiles && numFiles > 0) {
+ BOOL oneWindowInTab = topframe ? YES
+ : (topframe->fr_layout == FR_LEAF);
+ BOOL bufChanged = NO;
+ BOOL bufHasFilename = NO;
+ if (curbuf) {
+ bufChanged = check_changed(curbuf, TRUE, FALSE, FALSE, FALSE);
+ bufHasFilename = curbuf->b_ffname != NULL;
+ }
+
+ // Temporarily disable flushing since the following code may
+ // potentially cause multiple redraws.
+ flushDisabled = YES;
+
+ BOOL onlyOneTab = (first_tabpage->tp_next == NULL);
+ if (WIN_TABS == layout && !onlyOneTab) {
+ // By going to the last tabpage we ensure that the new tabs
+ // will appear last (if this call is left out, the taborder
+ // becomes messy).
+ goto_tabpage(9999);
+ }
+
+ // Make sure we're in normal mode first.
+ [self addInput:@"<C-\\><C-N>"];
+
+ if (numFiles > 1) {
+ // With "split layout" we open a new tab before opening
+ // multiple files if the current tab has more than one window
+ // or if there is exactly one window but whose buffer has a
+ // filename. (The :drop command ensures modified buffers get
+ // their own window.)
+ if ((WIN_HOR == layout || WIN_VER == layout) &&
+ (!oneWindowInTab || bufHasFilename))
+ [self addInput:@":tabnew<CR>"];
+
+ // The files are opened by constructing a ":drop ..." command
+ // and executing it.
+ NSMutableString *cmd = (WIN_TABS == layout)
+ ? [NSMutableString stringWithString:@":tab drop"]
+ : [NSMutableString stringWithString:@":drop"];
+
+ for (i = 0; i < numFiles; ++i) {
+ NSString *file = [filenames objectAtIndex:i];
+ file = [file stringByEscapingSpecialFilenameCharacters];
+ [cmd appendString:@" "];
+ [cmd appendString:file];
+ }
+
+ [self addInput:cmd];
+
+ // Split the view into multiple windows if requested.
+ if (WIN_HOR == layout)
+ [self addInput:@"|sall"];
+ else if (WIN_VER == layout)
+ [self addInput:@"|vert sall"];
+
+ // Adding "|redr|f" ensures a "Hit ENTER" prompt is not shown.
+ [self addInput:@"|redr|f<CR>"];
+ } else {
+ // When opening one file we try to reuse the current window,
+ // but not if its buffer is modified or has a filename.
+ // However, the 'arglist' layout always opens the file in the
+ // current window.
+ NSString *file = [[filenames lastObject]
+ stringByEscapingSpecialFilenameCharacters];
+ NSString *cmd;
+ if (WIN_HOR == layout) {
+ if (!(bufHasFilename || bufChanged))
+ cmd = [NSString stringWithFormat:@":e %@", file];
+ else
+ cmd = [NSString stringWithFormat:@":sp %@", file];
+ } else if (WIN_VER == layout) {
+ if (!(bufHasFilename || bufChanged))
+ cmd = [NSString stringWithFormat:@":e %@", file];
+ else
+ cmd = [NSString stringWithFormat:@":vsp %@", file];
+ } else if (WIN_TABS == layout) {
+ if (oneWindowInTab && !(bufHasFilename || bufChanged))
+ cmd = [NSString stringWithFormat:@":e %@", file];
+ else
+ cmd = [NSString stringWithFormat:@":tabe %@", file];
+ } else {
+ // (The :drop command will split if there is a modified
+ // buffer.)
+ cmd = [NSString stringWithFormat:@":drop %@", file];
+ }
+
+ [self addInput:cmd];
+
+ // Adding "|redr|f" ensures a "Hit ENTER" prompt is not shown.
+ [self addInput:@"|redr|f<CR>"];
+ }
+
+ // Force screen redraw (does it have to be this complicated?).
+ // (This code was taken from the end of gui_handle_drop().)
+ update_screen(NOT_VALID);
+ setcursor();
+ out_flush();
+ gui_update_cursor(FALSE, FALSE);
+ maketitle();
+
+ flushDisabled = NO;
+ gui_mch_flush();
+ }
+ }
+
+ if ([args objectForKey:@"remoteID"]) {
+ // NOTE: We have to delay processing any ODB related arguments since
+ // the file(s) may not be opened until the input buffer is processed.
+ [self performSelectorOnMainThread:@selector(startOdbEditWithArguments:)
+ withObject:args
+ waitUntilDone:NO];
+ }
+
+ NSString *rangeString = [args objectForKey:@"selectionRange"];
+ if (rangeString) {
+ // Build a command line string that will select the given range of
+ // lines. If range.length == 0, then position the cursor on the given
+ // line but do not select.
+ NSRange range = NSRangeFromString(rangeString);
+ NSString *cmd;
+ if (range.length > 0) {
+ cmd = [NSString stringWithFormat:@"<C-\\><C-N>%dGV%dGz.0",
+ NSMaxRange(range), range.location];
+ } else {
+ cmd = [NSString stringWithFormat:@"<C-\\><C-N>%dGz.0",
+ range.location];
+ }
+
+ [self addInput:cmd];
+ }
+
+ NSString *searchText = [args objectForKey:@"searchText"];
+ if (searchText) {
+ // TODO: Searching is an exclusive motion, so if the pattern would
+ // match on row 0 column 0 then this pattern will miss that match.
+ [self addInput:[NSString stringWithFormat:@"<C-\\><C-N>gg/\\c%@<CR>",
+ searchText]];
+ }
+}
+
- (BOOL)checkForModifiedBuffers
{
buf_T *buf;
@@ -2445,6 +2657,8 @@ static int eventButtonNumberToVimMouseButton(int buttonNumber)
? mouseButton[buttonNumber] : -1;
}
+
+
// This function is modeled after the VimToPython function found in if_python.c
// NB This does a deep copy by value, it does not lookup references like the
// VimToPython function does. This is because I didn't want to deal with the
@@ -2581,3 +2795,50 @@ static id evalExprCocoa(NSString * expr, NSString ** errstr)
return res;
}
+
+
+
+
+@implementation NSString (VimStrings)
+
++ (id)stringWithVimString:(char_u *)s
+{
+ // This method ensures a non-nil string is returned. If 's' cannot be
+ // converted to a utf-8 string it is assumed to be latin-1. If conversion
+ // still fails an empty NSString is returned.
+ NSString *string = nil;
+ if (s) {
+#ifdef FEAT_MBYTE
+ s = CONVERT_TO_UTF8(s);
+#endif
+ string = [NSString stringWithUTF8String:(char*)s];
+ if (!string) {
+ // HACK! Apparently 's' is not a valid utf-8 string, maybe it is
+ // latin-1?
+ string = [NSString stringWithCString:(char*)s
+ encoding:NSISOLatin1StringEncoding];
+ }
+#ifdef FEAT_MBYTE
+ CONVERT_TO_UTF8_FREE(s);
+#endif
+ }
+
+ return string != nil ? string : [NSString string];
+}
+
+- (char_u *)vimStringSave
+{
+ char_u *s = (char_u*)[self UTF8String], *ret = NULL;
+
+#ifdef FEAT_MBYTE
+ s = CONVERT_FROM_UTF8(s);
+#endif
+ ret = vim_strsave(s);
+#ifdef FEAT_MBYTE
+ CONVERT_FROM_UTF8_FREE(s);
+#endif
+
+ return ret;
+}
+
+@end // NSString (VimStrings)
View
3 src/MacVim/MMFullscreenWindow.m
@@ -28,6 +28,7 @@
#import "MMVimController.h"
#import "MMVimView.h"
#import "MMWindowController.h"
+#import "Miscellaneous.h"
#import <Carbon/Carbon.h>
#import <PSMTabBarControl.h>
@@ -83,6 +84,8 @@ - (MMFullscreenWindow *)initWithWindow:(NSWindow *)t view:(MMVimView *)v
- (void)dealloc
{
+ LOG_DEALLOC
+
[target release]; target = nil;
[view release]; view = nil;
View
5 src/MacVim/MMPreferenceController.h
@@ -16,6 +16,8 @@
IBOutlet NSView *generalPreferences;
IBOutlet NSView *integrationPreferences;
+ // General pane
+ IBOutlet NSPopUpButton *layoutPopUpButton;
// Integration pane
NSDictionary *supportedOdbEditors;
@@ -26,6 +28,9 @@
}
+// General pane
+- (IBAction)openInCurrentWindowSelectionChanged:(id)sender;
+
// Integration pane
- (IBAction)installOdb:(id)sender;
- (IBAction)uninstallOdb:(id)sender;
View
9 src/MacVim/MMPreferenceController.m
@@ -194,6 +194,15 @@ - (BOOL)validateMenuItem:(NSMenuItem *)item
return YES;
}
+- (IBAction)openInCurrentWindowSelectionChanged:(id)sender
+{
+ BOOL openInCurrentWindowSelected = ([[sender selectedCell] tag] != 0);
+ BOOL useWindowsLayout =
+ ([[layoutPopUpButton selectedItem] tag] == MMLayoutWindows);
+ if (openInCurrentWindowSelected && useWindowsLayout)
+ [layoutPopUpButton selectItemWithTag:MMLayoutTabs];
+}
+
#pragma mark -
#pragma mark Integration pane
View
2 src/MacVim/MMTextStorage.m
@@ -84,7 +84,7 @@ - (id)init
- (void)dealloc
{
- //NSLog(@"MMTextStorage dealloc");
+ LOG_DEALLOC
#if MM_USE_ROW_CACHE
if (rowCache) {
View
2 src/MacVim/MMTextView.m
@@ -131,7 +131,7 @@ - (id)initWithFrame:(NSRect)frame
- (void)dealloc
{
- //NSLog(@"MMTextView dealloc");
+ LOG_DEALLOC
if (markedText) {
imRange = NSMakeRange(0, 0);
View
3 src/MacVim/MMVimController.h
@@ -51,8 +51,7 @@
- (void)cleanup;
- (void)dropFiles:(NSArray *)filenames forceOpen:(BOOL)force;
- (void)dropString:(NSString *)string;
-- (void)odbEdit:(NSArray *)filenames server:(OSType)theID path:(NSString *)path
- token:(NSAppleEventDescriptor *)token;
+- (void)passArguments:(NSDictionary *)args;
- (void)sendMessage:(int)msgid data:(NSData *)data;
- (BOOL)sendMessageNow:(int)msgid data:(NSData *)data
timeout:(NSTimeInterval)timeout;
View
98 src/MacVim/MMVimController.m
@@ -93,6 +93,7 @@ - (void)popupMenuWithDescriptor:(NSArray *)desc
column:(NSNumber *)col;
- (void)popupMenuWithAttributes:(NSDictionary *)attrs;
- (void)connectionDidDie:(NSNotification *)notification;
+- (void)scheduleClose;
@end
@@ -153,8 +154,7 @@ - (id)initWithBackend:(id)backend pid:(int)processIdentifier
- (void)dealloc
{
- //NSLog(@"%@ %s", [self className], _cmd);
-
+ LOG_DEALLOC
isInitialized = NO;
@@ -220,24 +220,20 @@ - (int)pid
- (void)dropFiles:(NSArray *)filenames forceOpen:(BOOL)force
{
- unsigned i, numberOfFiles = [filenames count];
- NSMutableData *data = [NSMutableData data];
-
- [data appendBytes:&force length:sizeof(BOOL)];
- [data appendBytes:&numberOfFiles length:sizeof(int)];
+ NSUserDefaults *ud = [NSUserDefaults standardUserDefaults];
- for (i = 0; i < numberOfFiles; ++i) {
- NSString *file = [filenames objectAtIndex:i];
- int len = [file lengthOfBytesUsingEncoding:NSUTF8StringEncoding];
+ // Default to opening in tabs if layout is invalid or set to "windows".
+ int layout = [ud integerForKey:MMOpenLayoutKey];
+ if (layout < 0 || layout > MMLayoutTabs)
+ layout = MMLayoutTabs;
- if (len > 0) {
- ++len; // include NUL as well
- [data appendBytes:&len length:sizeof(int)];
- [data appendBytes:[file UTF8String] length:len];
- }
- }
+ NSDictionary *args = [NSDictionary dictionaryWithObjectsAndKeys:
+ [NSNumber numberWithInt:layout], @"layout",
+ filenames, @"filenames",
+ [NSNumber numberWithBool:force], @"forceOpen",
+ nil];
- [self sendMessage:DropFilesMsgID data:data];
+ [self sendMessage:DropFilesMsgID data:[args dictionaryAsData]];
}
- (void)dropString:(NSString *)string
@@ -253,57 +249,11 @@ - (void)dropString:(NSString *)string
}
}
-- (void)odbEdit:(NSArray *)filenames server:(OSType)theID path:(NSString *)path
- token:(NSAppleEventDescriptor *)token
+- (void)passArguments:(NSDictionary *)args
{
- int len;
- unsigned i, numberOfFiles = [filenames count];
- NSMutableData *data = [NSMutableData data];
-
- if (0 == numberOfFiles || 0 == theID)
- return;
-
- [data appendBytes:&theID length:sizeof(theID)];
-
- if (path && [path length] > 0) {
- len = [path lengthOfBytesUsingEncoding:NSUTF8StringEncoding] + 1;
- [data appendBytes:&len length:sizeof(int)];
- [data appendBytes:[path UTF8String] length:len];
- } else {
- len = 0;
- [data appendBytes:&len length:sizeof(int)];
- }
-
- if (token) {
- DescType tokenType = [token descriptorType];
- NSData *tokenData = [token data];
- len = [tokenData length];
-
- [data appendBytes:&tokenType length:sizeof(tokenType)];
- [data appendBytes:&len length:sizeof(int)];
- if (len > 0)
- [data appendBytes:[tokenData bytes] length:len];
- } else {
- DescType tokenType = 0;
- len = 0;
- [data appendBytes:&tokenType length:sizeof(tokenType)];
- [data appendBytes:&len length:sizeof(int)];
- }
+ if (!args) return;
- [data appendBytes:&numberOfFiles length:sizeof(int)];
-
- for (i = 0; i < numberOfFiles; ++i) {
- NSString *file = [filenames objectAtIndex:i];
- len = [file lengthOfBytesUsingEncoding:NSUTF8StringEncoding];
-
- if (len > 0) {
- ++len; // include NUL as well
- [data appendBytes:&len length:sizeof(unsigned)];
- [data appendBytes:[file UTF8String] length:len];
- }
- }
-
- [self sendMessage:ODBEditMsgID data:data];
+ [self sendMessage:OpenWithArgumentsMsgID data:[args dictionaryAsData]];
}
- (void)sendMessage:(int)msgid data:(NSData *)data
@@ -408,12 +358,13 @@ - (id)backendProxy
- (void)cleanup
{
- //NSLog(@"%@ %s", [self className], _cmd);
if (!isInitialized) return;
isInitialized = NO;
[toolbar setDelegate:nil];
[[NSNotificationCenter defaultCenter] removeObserver:self];
+ //[[backendProxy connectionForProxy] invalidate];
+ //[windowController close];
[windowController cleanup];
}
@@ -935,6 +886,8 @@ - (void)handleMessage:(int)msgid data:(NSData *)data
[vimState release];
vimState = [dict retain];
}
+ } else if (CloseWindowMsgID == msgid) {
+ [self scheduleClose];
// IMPORTANT: When adding a new message, make sure to update
// isUnsafeMessage() if necessary!
} else {
@@ -1366,8 +1319,12 @@ - (void)popupMenuWithAttributes:(NSDictionary *)attrs
- (void)connectionDidDie:(NSNotification *)notification
{
//NSLog(@"%@ %s%@", [self className], _cmd, notification);
+ [self scheduleClose];
+}
- // NOTE! This notification can arrive at pretty much anytime, e.g. while
+- (void)scheduleClose
+{
+ // NOTE! This message can arrive at pretty much anytime, e.g. while
// the run loop is the 'event tracking' mode. This means that Cocoa may
// well be in the middle of processing some message while this message is
// received. If we were to remove the vim controller straight away we may
@@ -1382,11 +1339,6 @@ - (void)connectionDidDie:(NSNotification *)notification
NSDefaultRunLoopMode]];
}
-- (NSString *)description
-{
- return [NSString stringWithFormat:@"%@ : isInitialized=%d inProcessCommandQueue=%d mainMenu=%@ popupMenuItems=%@ toolbar=%@", [self className], isInitialized, inProcessCommandQueue, mainMenu, popupMenuItems, toolbar];
-}
-
@end // MMVimController (Private)
View
2 src/MacVim/MMVimView.m
@@ -149,6 +149,8 @@ - (MMVimView *)initWithFrame:(NSRect)frame
- (void)dealloc
{
+ LOG_DEALLOC
+
[tabBarControl release]; tabBarControl = nil;
[tabView release]; tabView = nil;
[scrollbars release]; scrollbars = nil;
View
3 src/MacVim/MMWindow.m
@@ -27,6 +27,7 @@
*/
#import "MMWindow.h"
+#import "Miscellaneous.h"
@@ -62,6 +63,8 @@ - (id)initWithContentRect:(NSRect)rect
- (void)dealloc
{
+ LOG_DEALLOC
+
// TODO: Is there any reason why we would want the following call?
//[tablineSeparator removeFromSuperviewWithoutNeedingDisplay];
[tablineSeparator release]; tablineSeparator = nil;
View
2 src/MacVim/MMWindowController.m
@@ -197,7 +197,7 @@ - (id)initWithVimController:(MMVimController *)controller
- (void)dealloc
{
- //NSLog(@"%@ %s", [self className], _cmd);
+ LOG_DEALLOC
[decoratedWindow release]; decoratedWindow = nil;
[windowAutosaveKey release]; windowAutosaveKey = nil;
View
8 src/MacVim/MacVim.h
@@ -39,6 +39,7 @@
- (id)evaluateExpressionCocoa:(in bycopy NSString *)expr
errorString:(out bycopy NSString **)errstr;
- (BOOL)starRegisterToPasteboard:(byref NSPasteboard *)pboard;
+- (oneway void)acknowledgeConnection;
@end
//
@@ -162,13 +163,14 @@ enum {
AddInputMsgID,
SetPreEditPositionMsgID,
TerminateNowMsgID,
- ODBEditMsgID,
XcodeModMsgID,
LiveResizeMsgID,
EnableAntialiasMsgID,
DisableAntialiasMsgID,
SetVimStateMsgID,
SetDocumentFilenameMsgID,
+ OpenWithArgumentsMsgID,
+ CloseWindowMsgID,
};
@@ -231,6 +233,10 @@ ATSFontContainerRef loadFonts();
- (NSData *)dictionaryAsData;
@end
+@interface NSMutableDictionary (MMExtras)
++ (id)dictionaryWithData:(NSData *)data;
+@end
+
View
21 src/MacVim/MacVim.m
@@ -70,13 +70,14 @@
"AddInputMsgID",
"SetPreEditPositionMsgID",
"TerminateNowMsgID",
- "ODBEditMsgID",
"XcodeModMsgID",
"LiveResizeMsgID",
"EnableAntialiasMsgID",
"DisableAntialiasMsgID",
"SetVimStateMsgID",
"SetDocumentFilenameMsgID",
+ "OpenWithArgumentsMsgID",
+ "CloseWindowMsgID",
};
@@ -214,3 +215,21 @@ - (NSData *)dictionaryAsData
}
@end
+
+
+
+
+@implementation NSMutableDictionary (MMExtras)
+
++ (id)dictionaryWithData:(NSData *)data
+{
+ id plist = [NSPropertyListSerialization
+ propertyListFromData:data
+ mutabilityOption:NSPropertyListMutableContainers
+ format:NULL
+ errorDescription:NULL];
+
+ return [plist isKindOfClass:[NSMutableDictionary class]] ? plist : nil;
+}
+
+@end
View
32