mirror of
https://github.com/macvim-dev/macvim.git
synced 2026-06-11 15:37:29 +02:00
ODB Editor protocol (aka 'external editor') support
Programs that support ODB asks MacVim to open files. When a file is written or closed, MacVim notifies the program of these events. (At the moment the 'Burl' parameter is parsed but ignored. The 'RdEV' parameter is ignored.)
This commit is contained in:
@@ -102,6 +102,10 @@ window, unless Vim is in command-line mode. In command-line mode the names of
|
||||
the files are added to the command line. Holding down modifier keys whilst
|
||||
dragging is not supported.
|
||||
|
||||
If a file is dropped on the Dock icon, it is always opened in a new tab
|
||||
regardless of the mode Vim is currently in. The same holds if you
|
||||
double-click on a file in the Finder.
|
||||
|
||||
*macvim-default-menu*
|
||||
The default menu in MacVim has been changed to conform better with the Apple
|
||||
Human Interface Guidelines (HIG). At the moment this breaks the localized
|
||||
|
||||
@@ -531,7 +531,7 @@
|
||||
<key>CFBundleIconFile</key>
|
||||
<string>vim_gloss</string>
|
||||
<key>CFBundleIdentifier</key>
|
||||
<string>org.vim.MacVim</string>
|
||||
<string>org.vim.MacVim-odb</string>
|
||||
<key>CFBundleInfoDictionaryVersion</key>
|
||||
<string>6.0</string>
|
||||
<key>CFBundleName</key>
|
||||
|
||||
@@ -20,6 +20,7 @@
|
||||
NSString *openSelectionString;
|
||||
ATSFontContainerRef fontContainerRef;
|
||||
BOOL untitledWindowOpening;
|
||||
NSMutableDictionary *pidArguments;
|
||||
}
|
||||
|
||||
- (void)removeVimController:(id)controller;
|
||||
|
||||
+141
-17
@@ -32,6 +32,7 @@
|
||||
|
||||
|
||||
|
||||
|
||||
// Default timeout intervals on all connections.
|
||||
static NSTimeInterval MMRequestTimeout = 5;
|
||||
static NSTimeInterval MMReplyTimeout = 5;
|
||||
@@ -49,9 +50,13 @@ static NSTimeInterval MMReplyTimeout = 5;
|
||||
@interface MMAppController (Private)
|
||||
- (MMVimController *)keyVimController;
|
||||
- (MMVimController *)topmostVimController;
|
||||
- (void)launchVimProcessWithArguments:(NSArray *)args;
|
||||
- (int)launchVimProcessWithArguments:(NSArray *)args;
|
||||
- (NSArray *)filterFilesAndNotify:(NSArray *)files;
|
||||
- (NSArray *)filterOpenFilesAndRaiseFirst:(NSArray *)filenames;
|
||||
- (NSArray *)filterOpenFiles:(NSArray *)filenames remote:(OSType)theID
|
||||
path:(NSString *)path
|
||||
token:(NSAppleEventDescriptor *)token;
|
||||
- (void)handleXcodeModEvent:(NSAppleEventDescriptor *)event
|
||||
replyEvent:(NSAppleEventDescriptor *)reply;
|
||||
@end
|
||||
|
||||
@interface NSMenu (MMExtras)
|
||||
@@ -99,6 +104,7 @@ static NSTimeInterval MMReplyTimeout = 5;
|
||||
fontContainerRef = loadFonts();
|
||||
|
||||
vimControllers = [NSMutableArray new];
|
||||
pidArguments = [NSMutableDictionary new];
|
||||
|
||||
// NOTE! If the name of the connection changes here it must also be
|
||||
// updated in MMBackend.m.
|
||||
@@ -128,12 +134,22 @@ static NSTimeInterval MMReplyTimeout = 5;
|
||||
{
|
||||
//NSLog(@"MMAppController dealloc");
|
||||
|
||||
[pidArguments release];
|
||||
[vimControllers release];
|
||||
[openSelectionString release];
|
||||
|
||||
[super dealloc];
|
||||
}
|
||||
|
||||
- (void)applicationWillFinishLaunching:(NSNotification *)notification
|
||||
{
|
||||
[[NSAppleEventManager sharedAppleEventManager]
|
||||
setEventHandler:self
|
||||
andSelector:@selector(handleXcodeModEvent:replyEvent:)
|
||||
forEventClass:'KAHL'
|
||||
andEventID:'MOD '];
|
||||
}
|
||||
|
||||
- (void)applicationDidFinishLaunching:(NSNotification *)notification
|
||||
{
|
||||
[NSApp setServicesProvider:self];
|
||||
@@ -150,26 +166,79 @@ static NSTimeInterval MMReplyTimeout = 5;
|
||||
|
||||
- (BOOL)applicationOpenUntitledFile:(NSApplication *)sender
|
||||
{
|
||||
//NSLog(@"%s NSapp=%@ theApp=%@", _cmd, NSApp, sender);
|
||||
|
||||
[self newWindow:self];
|
||||
return YES;
|
||||
}
|
||||
|
||||
- (void)application:(NSApplication *)sender openFiles:(NSArray *)filenames
|
||||
{
|
||||
filenames = [self filterOpenFilesAndRaiseFirst:filenames];
|
||||
OSType remoteID;
|
||||
NSString *remotePath;
|
||||
NSAppleEventDescriptor *remoteToken;
|
||||
NSAppleEventDescriptor *odbdesc =
|
||||
[[NSAppleEventManager sharedAppleEventManager] currentAppleEvent];
|
||||
|
||||
if (![odbdesc paramDescriptorForKeyword:keyFileSender]) {
|
||||
// The ODB paramaters may hide inside the 'keyAEPropData' descriptor.
|
||||
odbdesc = [odbdesc paramDescriptorForKeyword:keyAEPropData];
|
||||
if (![odbdesc paramDescriptorForKeyword:keyFileSender])
|
||||
odbdesc = nil;
|
||||
}
|
||||
|
||||
if (odbdesc) {
|
||||
remoteID = [[odbdesc paramDescriptorForKeyword:keyFileSender]
|
||||
typeCodeValue];
|
||||
remotePath = [[odbdesc paramDescriptorForKeyword:keyFileCustomPath]
|
||||
stringValue];
|
||||
remoteToken = [[odbdesc paramDescriptorForKeyword:keyFileSenderToken]
|
||||
copy];
|
||||
|
||||
//NSLog(@"ODB parameters: ID=0x%x path=%@ token=%@",
|
||||
// remoteID, remotePath, remoteToken);
|
||||
}
|
||||
|
||||
filenames = [self filterOpenFiles:filenames remote:remoteID path:remotePath
|
||||
token:remoteToken];
|
||||
if ([filenames count]) {
|
||||
MMVimController *vc;
|
||||
BOOL openInTabs = [[NSUserDefaults standardUserDefaults]
|
||||
boolForKey:MMOpenFilesInTabsKey];
|
||||
|
||||
if (openInTabs && (vc = [self topmostVimController])) {
|
||||
[vc dropFiles:filenames];
|
||||
// Open files in tabs in the topmost window.
|
||||
[vc dropFiles:filenames forceOpen:YES];
|
||||
if (odbdesc)
|
||||
[vc odbEdit:filenames server:remoteID path:remotePath
|
||||
token:remoteToken];
|
||||
} else {
|
||||
// Open files in tabs in a new window.
|
||||
NSMutableArray *args = [NSMutableArray arrayWithObject:@"-p"];
|
||||
[args addObjectsFromArray:filenames];
|
||||
[self launchVimProcessWithArguments:args];
|
||||
int pid = [self launchVimProcessWithArguments:args];
|
||||
|
||||
// The Vim process starts asynchronously. Some arguments cannot be
|
||||
// on the command line, so store them in a dictionary and pass them
|
||||
// to the process once it has started.
|
||||
//
|
||||
// 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 (odbdesc) {
|
||||
// The remote token can be arbitrary data so it is cannot
|
||||
// (without encoding it as text) be passed on the command line.
|
||||
NSMutableDictionary *args =
|
||||
[NSMutableDictionary dictionaryWithObjectsAndKeys:
|
||||
filenames, @"filenames",
|
||||
[NSNumber numberWithUnsignedInt:remoteID], @"remoteID",
|
||||
nil];
|
||||
if (remotePath)
|
||||
[args setObject:remotePath forKey:@"remotePath"];
|
||||
if (remoteToken)
|
||||
[args setObject:remoteToken forKey:@"remoteToken"];
|
||||
|
||||
[pidArguments setObject:args
|
||||
forKey:[NSNumber numberWithInt:pid]];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -232,8 +301,12 @@ static NSTimeInterval MMReplyTimeout = 5;
|
||||
return reply;
|
||||
}
|
||||
|
||||
- (void)applicationWillTerminate:(NSNotification *)aNotification
|
||||
- (void)applicationWillTerminate:(NSNotification *)notification
|
||||
{
|
||||
[[NSAppleEventManager sharedAppleEventManager]
|
||||
removeEventHandlerForEventClass:'KAHL'
|
||||
andEventID:'MOD '];
|
||||
|
||||
// This will invalidate all connections (since they were spawned from the
|
||||
// default connection).
|
||||
[[NSConnection defaultConnection] invalidate];
|
||||
@@ -382,8 +455,7 @@ static NSTimeInterval MMReplyTimeout = 5;
|
||||
connectBackend:(byref in id <MMBackendProtocol>)backend
|
||||
pid:(int)pid
|
||||
{
|
||||
//NSLog(@"Frontend got connection request from backend...adding new "
|
||||
// "MMVimController");
|
||||
//NSLog(@"Connect backend (pid=%d)", pid);
|
||||
|
||||
[(NSDistantObject*)backend
|
||||
setProtocolForProxy:@protocol(MMBackendProtocol)];
|
||||
@@ -410,6 +482,21 @@ static NSTimeInterval MMReplyTimeout = 5;
|
||||
|
||||
untitledWindowOpening = NO;
|
||||
|
||||
// Arguments to a new Vim process that cannot be passed on the command line
|
||||
// are stored in a dictionary and passed to the Vim process here.
|
||||
NSNumber *key = [NSNumber numberWithInt:pid];
|
||||
NSDictionary *args = [pidArguments objectForKey:key];
|
||||
if (args) {
|
||||
if ([args objectForKey:@"remoteID"]) {
|
||||
[vc odbEdit:[args objectForKey:@"filenames"]
|
||||
server:[[args objectForKey:@"remoteID"] unsignedIntValue]
|
||||
path:[args objectForKey:@"remotePath"]
|
||||
token:[args objectForKey:@"remoteToken"]];
|
||||
}
|
||||
|
||||
[pidArguments removeObjectForKey:key];
|
||||
}
|
||||
|
||||
return vc;
|
||||
}
|
||||
|
||||
@@ -483,7 +570,7 @@ static NSTimeInterval MMReplyTimeout = 5;
|
||||
vc = [self topmostVimController];
|
||||
|
||||
if (vc) {
|
||||
[vc dropFiles:filenames];
|
||||
[vc dropFiles:filenames forceOpen:YES];
|
||||
} else {
|
||||
[self application:NSApp openFiles:filenames];
|
||||
}
|
||||
@@ -528,7 +615,7 @@ static NSTimeInterval MMReplyTimeout = 5;
|
||||
return nil;
|
||||
}
|
||||
|
||||
- (void)launchVimProcessWithArguments:(NSArray *)args
|
||||
- (int)launchVimProcessWithArguments:(NSArray *)args
|
||||
{
|
||||
NSString *taskPath = nil;
|
||||
NSArray *taskArgs = nil;
|
||||
@@ -536,7 +623,7 @@ static NSTimeInterval MMReplyTimeout = 5;
|
||||
|
||||
if (!path) {
|
||||
NSLog(@"ERROR: Vim executable could not be found inside app bundle!");
|
||||
return;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if ([[NSUserDefaults standardUserDefaults] boolForKey:MMLoginShellKey]) {
|
||||
@@ -577,8 +664,12 @@ static NSTimeInterval MMReplyTimeout = 5;
|
||||
taskArgs = [taskArgs arrayByAddingObjectsFromArray:args];
|
||||
}
|
||||
|
||||
//NSLog(@"Launching: %@ args: %@", taskPath, taskArgs);
|
||||
[NSTask launchedTaskWithLaunchPath:taskPath arguments:taskArgs];
|
||||
NSTask *task =[NSTask launchedTaskWithLaunchPath:taskPath
|
||||
arguments:taskArgs];
|
||||
//NSLog(@"launch %@ with args=%@ (pid=%d)", [task processIdentifier],
|
||||
// taskPath, taskArgs);
|
||||
|
||||
return [task processIdentifier];
|
||||
}
|
||||
|
||||
- (NSArray *)filterFilesAndNotify:(NSArray *)filenames
|
||||
@@ -627,12 +718,15 @@ static NSTimeInterval MMReplyTimeout = 5;
|
||||
return files;
|
||||
}
|
||||
|
||||
- (NSArray *)filterOpenFilesAndRaiseFirst:(NSArray *)filenames
|
||||
- (NSArray *)filterOpenFiles:(NSArray *)filenames remote:(OSType)theID
|
||||
path:(NSString *)path
|
||||
token:(NSAppleEventDescriptor *)token
|
||||
{
|
||||
// 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.
|
||||
// the Vim process it is open. Files that are filtered are sent an odb
|
||||
// open event in case theID is not zero.
|
||||
|
||||
MMVimController *raiseController = nil;
|
||||
NSString *raiseFile = nil;
|
||||
@@ -658,6 +752,11 @@ static NSTimeInterval MMReplyTimeout = 5;
|
||||
[[raiseFile retain] autorelease];
|
||||
}
|
||||
|
||||
// Send an odb open event to the Vim process.
|
||||
if (theID != 0)
|
||||
[controller odbEdit:[files objectsAtIndexes:idxSet]
|
||||
server:theID path:path token:token];
|
||||
|
||||
// Remove all the files that were open in this Vim process and
|
||||
// create a new expression to evaluate.
|
||||
[files removeObjectsAtIndexes:idxSet];
|
||||
@@ -688,6 +787,31 @@ static NSTimeInterval MMReplyTimeout = 5;
|
||||
return files;
|
||||
}
|
||||
|
||||
- (void)handleXcodeModEvent:(NSAppleEventDescriptor *)event
|
||||
replyEvent:(NSAppleEventDescriptor *)reply
|
||||
{
|
||||
#if 0
|
||||
// Xcode sends this event to query MacVim which open files have been
|
||||
// modified.
|
||||
NSLog(@"reply:%@", reply);
|
||||
NSLog(@"event:%@", event);
|
||||
|
||||
NSEnumerator *e = [vimControllers objectEnumerator];
|
||||
id vc;
|
||||
while ((vc = [e nextObject])) {
|
||||
DescType type = [reply descriptorType];
|
||||
unsigned len = [[type data] length];
|
||||
NSMutableData *data = [NSMutableData data];
|
||||
|
||||
[data appendBytes:&type length:sizeof(DescType)];
|
||||
[data appendBytes:&len length:sizeof(unsigned)];
|
||||
[data appendBytes:[reply data] length:len];
|
||||
|
||||
[vc sendMessage:XcodeModMsgID data:data];
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
@end // MMAppController (Private)
|
||||
|
||||
|
||||
|
||||
+109
-2
@@ -85,6 +85,8 @@ enum {
|
||||
- (void)handleSetFont:(NSData *)data;
|
||||
- (void)handleDropFiles:(NSData *)data;
|
||||
- (void)handleDropString:(NSData *)data;
|
||||
- (void)handleOdbEdit:(NSData *)data;
|
||||
- (void)handleXcodeMod:(NSData *)data;
|
||||
- (BOOL)checkForModifiedBuffers;
|
||||
- (void)addInput:(NSString *)input;
|
||||
@end
|
||||
@@ -392,10 +394,12 @@ enum {
|
||||
[[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode
|
||||
beforeDate:[NSDate distantPast]];
|
||||
|
||||
#if 0
|
||||
// Keyboard and mouse input is handled directly, other input is queued and
|
||||
// processed here. This call may enter a blocking loop.
|
||||
if ([inputQueue count] > 0)
|
||||
[self processInputQueue];
|
||||
#endif
|
||||
}
|
||||
|
||||
- (void)flushQueue:(BOOL)force
|
||||
@@ -451,6 +455,8 @@ enum {
|
||||
BOOL yn = inputReceived;
|
||||
inputReceived = NO;
|
||||
|
||||
// Keyboard and mouse input is handled directly, other input is queued and
|
||||
// processed here. This call may enter a blocking loop.
|
||||
if ([inputQueue count] > 0)
|
||||
[self processInputQueue];
|
||||
|
||||
@@ -1586,6 +1592,10 @@ enum {
|
||||
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 {
|
||||
NSLog(@"WARNING: Unknown message received (msgid=%d)", msgid);
|
||||
}
|
||||
@@ -1959,12 +1969,14 @@ enum {
|
||||
#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);
|
||||
|
||||
if (State & CMDLINE) {
|
||||
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. This is taken care of by gui_handle_drop().
|
||||
// files in tabs (unless forceOpen is set). This is taken care of by
|
||||
// gui_handle_drop().
|
||||
char_u **fnames = (char_u **)alloc(n * sizeof(char_u *));
|
||||
if (fnames) {
|
||||
int i = 0;
|
||||
@@ -1990,7 +2002,12 @@ enum {
|
||||
// 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.
|
||||
#if 1
|
||||
NSMutableString *cmd = [NSMutableString stringWithString:@":tab drop"];
|
||||
#else
|
||||
NSMutableString *cmd = [NSMutableString stringWithString:
|
||||
@"<C-\\><C-N>:tab drop"];
|
||||
#endif
|
||||
|
||||
int i;
|
||||
for (i = 0; i < n && bytes < end; ++i) {
|
||||
@@ -2003,6 +2020,7 @@ enum {
|
||||
[cmd appendString:file];
|
||||
}
|
||||
|
||||
#if 1
|
||||
// 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).
|
||||
@@ -2025,6 +2043,11 @@ enum {
|
||||
gui_update_cursor(FALSE, FALSE);
|
||||
maketitle();
|
||||
gui_mch_flush();
|
||||
#else
|
||||
[cmd appendString:@"|redr|f<CR>"];
|
||||
|
||||
[self addInput:cmd];
|
||||
#endif
|
||||
}
|
||||
#endif // FEAT_DND
|
||||
}
|
||||
@@ -2064,6 +2087,90 @@ enum {
|
||||
#endif // FEAT_DND
|
||||
}
|
||||
|
||||
- (void)handleOdbEdit:(NSData *)data
|
||||
{
|
||||
#ifdef FEAT_ODB_EDITOR
|
||||
const void *bytes = [data bytes];
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
NSAppleEventDescriptor *token = nil;
|
||||
DescType tokenType = *((DescType*)bytes); bytes += sizeof(DescType);
|
||||
int descLen = *((int*)bytes); bytes += sizeof(int);
|
||||
if (descLen > 0) {
|
||||
token = [NSAppleEventDescriptor descriptorWithDescriptorType:tokenType
|
||||
bytes:bytes
|
||||
length:descLen];
|
||||
bytes += descLen;
|
||||
}
|
||||
|
||||
unsigned i, numFiles = *((unsigned*)bytes); bytes += sizeof(unsigned);
|
||||
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);
|
||||
if (buf) {
|
||||
if (buf->b_odb_token) {
|
||||
[(NSAppleEventDescriptor*)(buf->b_odb_token) release];
|
||||
buf->b_odb_token = NULL;
|
||||
}
|
||||
|
||||
if (buf->b_odb_fname) {
|
||||
vim_free(buf->b_odb_fname);
|
||||
buf->b_odb_fname = NULL;
|
||||
}
|
||||
|
||||
buf->b_odb_server_id = serverID;
|
||||
|
||||
if (token)
|
||||
buf->b_odb_token = [token retain];
|
||||
if (path)
|
||||
buf->b_odb_fname = vim_strsave(path);
|
||||
} else {
|
||||
NSLog(@"WARNING: Could not find buffer '%s' 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
|
||||
}
|
||||
|
||||
- (void)handleXcodeMod:(NSData *)data
|
||||
{
|
||||
#if 0
|
||||
const void *bytes = [data bytes];
|
||||
DescType type = *((DescType*)bytes); bytes += sizeof(DescType);
|
||||
unsigned len = *((unsigned*)bytes); bytes += sizeof(unsigned);
|
||||
if (0 == len)
|
||||
return;
|
||||
|
||||
NSAppleEventDescriptor *replyEvent = [NSAppleEventDescriptor
|
||||
descriptorWithDescriptorType:type
|
||||
bytes:bytes
|
||||
length:len];
|
||||
#endif
|
||||
}
|
||||
|
||||
- (BOOL)checkForModifiedBuffers
|
||||
{
|
||||
buf_T *buf;
|
||||
|
||||
@@ -699,7 +699,7 @@ static NSString *MMKeypadEnterString = @"KA";
|
||||
return YES;
|
||||
} else if ([[pboard types] containsObject:NSFilenamesPboardType]) {
|
||||
NSArray *files = [pboard propertyListForType:NSFilenamesPboardType];
|
||||
[[self vimController] dropFiles:files];
|
||||
[[self vimController] dropFiles:files forceOpen:NO];
|
||||
return YES;
|
||||
}
|
||||
|
||||
|
||||
@@ -49,8 +49,10 @@
|
||||
- (NSString *)serverName;
|
||||
- (MMWindowController *)windowController;
|
||||
- (void)cleanup;
|
||||
- (void)dropFiles:(NSArray *)filenames;
|
||||
- (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)sendMessage:(int)msgid data:(NSData *)data;
|
||||
- (BOOL)sendMessageNow:(int)msgid data:(NSData *)data
|
||||
timeout:(NSTimeInterval)timeout;
|
||||
|
||||
@@ -182,11 +182,12 @@ static NSTimeInterval MMResendInterval = 0.5;
|
||||
return pid;
|
||||
}
|
||||
|
||||
- (void)dropFiles:(NSArray *)filenames
|
||||
- (void)dropFiles:(NSArray *)filenames forceOpen:(BOOL)force
|
||||
{
|
||||
int i, numberOfFiles = [filenames count];
|
||||
unsigned i, numberOfFiles = [filenames count];
|
||||
NSMutableData *data = [NSMutableData data];
|
||||
|
||||
[data appendBytes:&force length:sizeof(BOOL)];
|
||||
[data appendBytes:&numberOfFiles length:sizeof(int)];
|
||||
|
||||
for (i = 0; i < numberOfFiles; ++i) {
|
||||
@@ -216,6 +217,59 @@ static NSTimeInterval MMResendInterval = 0.5;
|
||||
}
|
||||
}
|
||||
|
||||
- (void)odbEdit:(NSArray *)filenames server:(OSType)theID path:(NSString *)path
|
||||
token:(NSAppleEventDescriptor *)token
|
||||
{
|
||||
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)];
|
||||
}
|
||||
|
||||
[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];
|
||||
}
|
||||
|
||||
- (void)sendMessage:(int)msgid data:(NSData *)data
|
||||
{
|
||||
//NSLog(@"sendMessage:%s (isInitialized=%d inProcessCommandQueue=%d)",
|
||||
|
||||
@@ -157,6 +157,8 @@ enum {
|
||||
AddInputMsgID,
|
||||
SetPreEditPositionMsgID,
|
||||
TerminateNowMsgID,
|
||||
ODBEditMsgID,
|
||||
XcodeModMsgID,
|
||||
};
|
||||
|
||||
|
||||
@@ -234,3 +236,17 @@ ATSFontContainerRef loadFonts();
|
||||
@interface NSIndexSet (MMExtras)
|
||||
+ (id)indexSetWithVimList:(NSString *)list;
|
||||
@end
|
||||
|
||||
|
||||
|
||||
|
||||
// ODB Editor Suite Constants (taken from ODBEditorSuite.h)
|
||||
#define keyFileSender 'FSnd'
|
||||
#define keyFileSenderToken 'FTok'
|
||||
#define keyFileCustomPath 'Burl'
|
||||
#define kODBEditorSuite 'R*ch'
|
||||
#define kAEModifiedFile 'FMod'
|
||||
#define keyNewLocation 'New?'
|
||||
#define kAEClosedFile 'FCls'
|
||||
#define keySenderToken 'Tokn'
|
||||
|
||||
|
||||
@@ -70,6 +70,8 @@ char *MessageStrings[] =
|
||||
"AddInputMsgID",
|
||||
"SetPreEditPositionMsgID",
|
||||
"TerminateNowMsgID",
|
||||
"ODBEditMsgID",
|
||||
"XcodeModMsgID",
|
||||
};
|
||||
|
||||
|
||||
|
||||
@@ -1708,3 +1708,93 @@ serverSendReply(char_u *serverid, char_u *reply)
|
||||
}
|
||||
|
||||
#endif // MAC_CLIENTSERVER
|
||||
|
||||
|
||||
|
||||
|
||||
// -- ODB Editor Support ----------------------------------------------------
|
||||
|
||||
#ifdef FEAT_ODB_EDITOR
|
||||
/*
|
||||
* The ODB Editor protocol works like this:
|
||||
* - An external program (the server) asks MacVim to open a file and associates
|
||||
* three things with this file: (1) a server id (a four character code that
|
||||
* identifies the server), (2) a path that can be used as window title for
|
||||
* the file (optional), (3) an arbitrary token (optional)
|
||||
* - When a file is saved or closed, MacVim should tell the server about which
|
||||
* file was modified and also pass back the token
|
||||
*
|
||||
* All communication between MacVim and the server goes via Apple Events.
|
||||
*/
|
||||
|
||||
static OSErr
|
||||
odb_event(buf_T *buf, const AEEventID action)
|
||||
{
|
||||
if (!(buf->b_odb_server_id && buf->b_ffname))
|
||||
return noErr;
|
||||
|
||||
NSAppleEventDescriptor *targetDesc = [NSAppleEventDescriptor
|
||||
descriptorWithDescriptorType:typeApplSignature
|
||||
bytes:&buf->b_odb_server_id
|
||||
length:sizeof(OSType)];
|
||||
|
||||
NSString *path = [NSString stringWithUTF8String:(char*)buf->b_ffname];
|
||||
NSData *pathData = [[[NSURL fileURLWithPath:path] absoluteString]
|
||||
dataUsingEncoding:NSUTF8StringEncoding];
|
||||
NSAppleEventDescriptor *pathDesc = [NSAppleEventDescriptor
|
||||
descriptorWithDescriptorType:typeFileURL data:pathData];
|
||||
|
||||
NSAppleEventDescriptor *event = [NSAppleEventDescriptor
|
||||
appleEventWithEventClass:kODBEditorSuite
|
||||
eventID:action
|
||||
targetDescriptor:targetDesc
|
||||
returnID:kAutoGenerateReturnID
|
||||
transactionID:kAnyTransactionID];
|
||||
|
||||
[event setParamDescriptor:pathDesc forKeyword:keyDirectObject];
|
||||
|
||||
if (buf->b_odb_token)
|
||||
[event setParamDescriptor:buf->b_odb_token forKeyword:keySenderToken];
|
||||
|
||||
return AESendMessage([event aeDesc], NULL, kAENoReply | kAENeverInteract,
|
||||
kAEDefaultTimeout);
|
||||
}
|
||||
|
||||
OSErr
|
||||
odb_buffer_close(buf_T *buf)
|
||||
{
|
||||
OSErr err = noErr;
|
||||
if (buf) {
|
||||
err = odb_event(buf, kAEClosedFile);
|
||||
|
||||
buf->b_odb_server_id = 0;
|
||||
|
||||
if (buf->b_odb_token) {
|
||||
[(NSAppleEventDescriptor *)(buf->b_odb_token) release];
|
||||
buf->b_odb_token = NULL;
|
||||
}
|
||||
|
||||
if (buf->b_odb_fname) {
|
||||
vim_free(buf->b_odb_fname);
|
||||
buf->b_odb_fname = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
OSErr
|
||||
odb_post_buffer_write(buf_T *buf)
|
||||
{
|
||||
return buf ? odb_event(buf, kAEModifiedFile) : noErr;
|
||||
}
|
||||
|
||||
void
|
||||
odb_end(void)
|
||||
{
|
||||
buf_T *buf;
|
||||
for (buf = firstbuf; buf != NULL; buf = buf->b_next)
|
||||
odb_buffer_close(buf);
|
||||
}
|
||||
|
||||
#endif // FEAT_ODB_EDITOR
|
||||
|
||||
@@ -441,6 +441,10 @@ close_buffer(win, buf, action)
|
||||
if (usingNetbeans)
|
||||
netbeans_file_closed(buf);
|
||||
#endif
|
||||
#ifdef FEAT_ODB_EDITOR
|
||||
odb_buffer_close(buf);
|
||||
#endif
|
||||
|
||||
/* Change directories when the 'acd' option is set. */
|
||||
DO_AUTOCHDIR
|
||||
|
||||
|
||||
@@ -10865,6 +10865,9 @@ f_has(argvars, rettv)
|
||||
#if !defined(USE_SYSTEM) && defined(UNIX)
|
||||
"fork",
|
||||
#endif
|
||||
#ifdef FEAT_FULLSCREEN
|
||||
"fullscreen",
|
||||
#endif
|
||||
#ifdef FEAT_GETTEXT
|
||||
"gettext",
|
||||
#endif
|
||||
@@ -11052,6 +11055,9 @@ f_has(argvars, rettv)
|
||||
#ifdef FEAT_NETBEANS_INTG
|
||||
"netbeans_intg",
|
||||
#endif
|
||||
#ifdef FEAT_ODB_EDITOR
|
||||
"odbeditor",
|
||||
#endif
|
||||
#ifdef FEAT_SPELL
|
||||
"spell",
|
||||
#endif
|
||||
@@ -11093,6 +11099,9 @@ f_has(argvars, rettv)
|
||||
#ifdef FEAT_TOOLBAR
|
||||
"toolbar",
|
||||
#endif
|
||||
#ifdef FEAT_TRANSPARENCY
|
||||
"transparency",
|
||||
#endif
|
||||
#ifdef FEAT_USR_CMDS
|
||||
"user-commands", /* was accidentally included in 5.4 */
|
||||
"user_commands",
|
||||
|
||||
@@ -1282,3 +1282,10 @@
|
||||
#ifdef FEAT_GUI_MACVIM
|
||||
# define FEAT_FULLSCREEN
|
||||
#endif
|
||||
|
||||
/*
|
||||
* +odbeditor ODBEditor protocol support (aka. external editor)
|
||||
*/
|
||||
#ifdef FEAT_GUI_MACVIM
|
||||
# define FEAT_ODB_EDITOR
|
||||
#endif
|
||||
|
||||
@@ -4717,6 +4717,10 @@ nofail:
|
||||
/* Update machine specific information. */
|
||||
mch_post_buffer_write(buf);
|
||||
#endif
|
||||
#ifdef FEAT_ODB_EDITOR
|
||||
odb_post_buffer_write(buf);
|
||||
#endif
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
|
||||
@@ -1375,6 +1375,9 @@ getout(exitval)
|
||||
#ifdef FEAT_NETBEANS_INTG
|
||||
netbeans_end();
|
||||
#endif
|
||||
#ifdef FEAT_ODB_EDITOR
|
||||
odb_end();
|
||||
#endif
|
||||
#ifdef FEAT_CSCOPE
|
||||
cs_end();
|
||||
#endif
|
||||
|
||||
@@ -194,3 +194,8 @@ void gui_mch_enter_fullscreen(void);
|
||||
void gui_mch_leave_fullscreen(void);
|
||||
|
||||
void gui_macvim_update_modified_flag();
|
||||
|
||||
OSErr odb_buffer_close(buf_T *buf);
|
||||
OSErr odb_post_buffer_write(buf_T *buf);
|
||||
void odb_end(void);
|
||||
|
||||
|
||||
@@ -1583,6 +1583,11 @@ struct file_buffer
|
||||
int b_was_netbeans_file;/* TRUE if b_netbeans_file was once set */
|
||||
#endif
|
||||
|
||||
#ifdef FEAT_ODB_EDITOR
|
||||
OSType b_odb_server_id; /* FourCC of the ODB server (0 if none) */
|
||||
void *b_odb_token; /* NSAppleEventDescriptor (optional) */
|
||||
char_u *b_odb_fname; /* Custom file name (optional) */
|
||||
#endif
|
||||
};
|
||||
|
||||
|
||||
|
||||
@@ -395,6 +395,11 @@ static char *(features[]) =
|
||||
#else
|
||||
"-netbeans_intg",
|
||||
#endif
|
||||
#ifdef FEAT_ODB_EDITOR
|
||||
"+odbeditor",
|
||||
#else
|
||||
"-odbeditor",
|
||||
#endif
|
||||
#ifdef FEAT_GUI_W32
|
||||
# ifdef FEAT_OLE
|
||||
"+ole",
|
||||
|
||||
Reference in New Issue
Block a user