Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What is the best way to redirect stdout to NSTextView in Cocoa?

Hi: I want to redirect stdout to a NSTextView. Could this also work with outputs of subprocesses? What might be the best way to achieve this?

EDIT: According to Peter Hosey answer I implemented the following. But I do not get a notification. What am I doing wrong?

NSPipe *pipe = [NSPipe pipe];
NSFileHandle *pipeHandle = [pipe fileHandleForWriting];
dup2(STDOUT_FILENO, [pipeHandle fileDescriptor]);
NSFileHandle *fileHandle = [[NSFileHandle alloc] initWithFileDescriptor:pipeHandle];
[fileHandle acceptConnectionInBackgroundAndNotify];

NSNotificationCenter *dnc = [NSNotificationCenter defaultCenter];
[dnc addObserver:self selector:@selector(handleNotification:) name:NSFileHandleConnectionAcceptedNotification object:fileHandle];
like image 710
Sney Avatar asked Mar 09 '10 02:03

Sney


2 Answers

I was looking to do the same thing and came across this post. I was able to figure it out after reading this and Apple's documentation. I'm including my solution here. "pipe" and "pipeReadHandle" are declared in the interface. In the init method I included the following code:

pipe = [NSPipe pipe] ;
pipeReadHandle = [pipe fileHandleForReading] ;
dup2([[pipe fileHandleForWriting] fileDescriptor], fileno(stdout)) ;

[[NSNotificationCenter defaultCenter] addObserver: self selector: @selector(handleNotification:) name: NSFileHandleReadCompletionNotification object: pipeReadHandle] ;
[pipeReadHandle readInBackgroundAndNotify] ;

The handleNotification: method is

[pipeReadHandle readInBackgroundAndNotify] ;
NSString *str = [[NSString alloc] initWithData: [[notification userInfo] objectForKey: NSFileHandleNotificationDataItem] encoding: NSASCIIStringEncoding] ;
// Do whatever you want with str 
like image 137
elessar Avatar answered Oct 06 '22 00:10

elessar


I want to redirect stdout to a NSTextView.

Your own stdout?

Could this also work with outputs of subprocesses?

Sure.

What might be the best way to achieve this?

File descriptors are your friend here.

Create a pipe (using either NSPipe or pipe(2)) and dup2 its write end onto STDOUT_FILENO. When invoking subprocesses, don't set their stdout; they'll inherit your stdout, which is your pipe. (You may want to close the read end in the subprocess, though. I'm not sure whether this will be necessary; try it and find out. If it does turn out to be, you'll need to use fork and exec, and close the read end in between.)

Read from the read end of the pipe in the background asynchronously, using either kevent or NSFileHandle. When new data comes in, interpret it using some encoding and append it to the contents of the text view.

If the text view is in a scroll view, you should check the scroll position before appending to it. If it was at the end, you'll probably want to jump it back to the end after appending.

like image 45
Peter Hosey Avatar answered Oct 06 '22 02:10

Peter Hosey