OK, let's say I'm creating a (Bash) Terminal emulator - I'm not actually, but it's pretty close in terms of description.
I've managed to get (almost) everything working, however I'm facing one simple issue: maintaining the current directory.
I mean... let's say the user runs pwd
and we execute this via NSTask
and /usr/bin/env bash
. This outputs the current app's directory. That's fine.
Now, let's say the user enters cd ..
. The path is changing right? (OK, even for that particular session, but it is changing, nope?)
So, I though of storing the task's currentDirectoryPath
when the Task is terminated and then re-set it when starting another Bash-related task.
However, it keeps getting the very same path (the one the app bundle is in).
What am I missing?
Any ideas on how to get this working?
The code
- (NSString*)exec:(NSArray *)args environment:(NSDictionary*)env action:(void (^)(NSString*))action completed:(void (^)(NSString*))completed
{
_task = [NSTask new];
_output = [NSPipe new];
_error = [NSPipe new];
_input = [NSPipe new];
NSFileHandle* outputF = [_output fileHandleForReading];
NSFileHandle* errorF = [_error fileHandleForReading];
__block NSString* fullOutput = @"";
NSMutableDictionary* envs = [NSMutableDictionary dictionary];
envs[@"PATH"] = [[APP environment] envPath];
[_task setLaunchPath:@"/usr/bin/env"];
if (env)
{
for (NSString* key in env)
{
envs[key] = env[key];
}
}
[_task setEnvironment:envs];
[_task setArguments:args];
[_task setStandardOutput:_output];
[_task setStandardError:_error];
[_task setStandardInput:_input];
void (^outputter)(NSFileHandle*) = ^(NSFileHandle *file){
NSData *data = [file availableData];
NSString* str = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
action(str);
fullOutput = [fullOutput stringByAppendingString:str];
};
[outputF setReadabilityHandler:outputter];
[errorF setReadabilityHandler:outputter];
[_task setTerminationHandler:^(NSTask* task){
completed(fullOutput);
dispatch_async(dispatch_get_main_queue(), ^{
[[APP environment] setPwd:[task currentDirectoryPath]];
});
[task.standardOutput fileHandleForReading].readabilityHandler = nil;
[task.standardError fileHandleForReading].readabilityHandler = nil;
[task.standardInput fileHandleForWriting].writeabilityHandler = nil;
[task terminate];
task = nil;
}];
if (![[[APP environment] pwd] isEqualToString:@""])
[_task setCurrentDirectoryPath:[[APP environment] pwd]];
[_task launch];
return @"";
}
I am fairly certain that running
cd
inNSTask
does not change the value oftask.currentDirectoryPath
. Have you tried setting a break point in your dispatch call to see if that value is actually being set correctly?Edit:
From your termination handler try doing
[[APP environment] setPwd:[[[NSProcessInfo processInfo]environment]objectForKey:@"PATH"]];