fish-shell/osx/osx_fish_launcher.m
ridiculousfish 4912967eab Large set of changes related to making fish relocatable, and improving the build and install story.
- etc/config.fish and share/config.fish are now "universal" and no longer reference install paths or need to be touched by autotools. They've been removed from config.fish.in to config.fish.
- fish now attempts to determine __fish_datadir and __fish_sysconfdir relative to the path of the fish executable itself (typically by walking up one directory). This means that you can copy the directory hierarchy around and things will still work. The compiled-in paths are used as a backup.
- The fish Xcode project now can build fish natively, without needing autotools.
- Version bumped to 2.0
2012-07-08 15:20:39 -07:00

98 lines
3.5 KiB
Objective-C

#import <Foundation/Foundation.h>
#import <CoreServices/CoreServices.h>
#import <Carbon/Carbon.h>
#import <stdlib.h>
#import <stdio.h>
#import <unistd.h>
#import <errno.h>
#import <sys/types.h>
#import <sys/stat.h>
// The path to the command file, which we'll delete on death (if it exists)
static char s_command_path[PATH_MAX];
static void die(const char *format, ...) {
va_list ap;
va_start(ap, format);
vfprintf(stderr, format, ap);
va_end(ap);
fputc('\n', stderr);
if (s_command_path[0] != '\0') {
unlink(s_command_path);
}
exit(EXIT_FAILURE);
}
static void launch_fish_with_applescript(NSString *fish_binary_path)
{
// load the script from a resource by fetching its URL from within our bundle
NSString *path = [[NSBundle mainBundle] pathForResource:@"launch_fish" ofType:@"scpt"];
if (! path) die("Couldn't get path to launch_fish.scpt");
NSURL *url = [NSURL fileURLWithPath:path isDirectory:NO];
if (! url) die("Couldn't get URL to launch_fish.scpt");
NSDictionary *errors = nil;
NSAppleScript *appleScript = [[NSAppleScript alloc] initWithContentsOfURL:url error:&errors];
if (! appleScript) die("Couldn't load AppleScript");
// create the first parameter
NSAppleEventDescriptor *firstParameter =
[NSAppleEventDescriptor descriptorWithString:fish_binary_path];
// create and populate the list of parameters (in our case just one)
NSAppleEventDescriptor *parameters = [NSAppleEventDescriptor listDescriptor];
[parameters insertDescriptor:firstParameter atIndex:1];
// create the AppleEvent target
ProcessSerialNumber psn = {0, kCurrentProcess};
NSAppleEventDescriptor *target =
[NSAppleEventDescriptor
descriptorWithDescriptorType:typeProcessSerialNumber
bytes:&psn
length:sizeof(ProcessSerialNumber)];
// create an NSAppleEventDescriptor with the script's method name to call,
// this is used for the script statement: "on show_message(user_message)"
// Note that the routine name must be in lower case.
NSAppleEventDescriptor *handler = [NSAppleEventDescriptor descriptorWithString:
[@"launch_fish" lowercaseString]];
// create the event for an AppleScript subroutine,
// set the method name and the list of parameters
NSAppleEventDescriptor *event =
[NSAppleEventDescriptor appleEventWithEventClass:kASAppleScriptSuite
eventID:kASSubroutineEvent
targetDescriptor:target
returnID:kAutoGenerateReturnID
transactionID:kAnyTransactionID];
[event setParamDescriptor:handler forKeyword:keyASSubroutineName];
[event setParamDescriptor:parameters forKeyword:keyDirectObject];
// call the event in AppleScript
if (![appleScript executeAppleEvent:event error:&errors])
{
// report any errors from 'errors'
NSLog(@"Oops: %@", errors);
}
[appleScript release];
}
/* This approach asks Terminal to open a script that we control */
int main(void) {
[[NSAutoreleasePool alloc] init];
/* Get the fish executable. Make sure it's absolute. */
NSURL *fish_executable = [[NSBundle mainBundle] URLForResource:@"fish" withExtension:@"" subdirectory:@"base/bin"];
if (! fish_executable)
die("Could not find fish executable in bundle");
launch_fish_with_applescript([fish_executable path]);
/* If we succeeded, it will clean itself up */
return 0;
}