1from Foundation import *
2from PyObjCTools import AppHelper
3
4class FileObserver(NSObject):
5    def initWithFileDescriptor_readCallback_errorCallback_(self,
6            fileDescriptor, readCallback, errorCallback):
7        self = self.init()
8        self.readCallback = readCallback
9        self.errorCallback = errorCallback
10        self.fileHandle = NSFileHandle.alloc().initWithFileDescriptor_(
11            fileDescriptor)
12        self.nc = NSNotificationCenter.defaultCenter()
13        self.nc.addObserver_selector_name_object_(
14            self,
15            'fileHandleReadCompleted:',
16            NSFileHandleReadCompletionNotification,
17            self.fileHandle)
18        self.fileHandle.readInBackgroundAndNotify()
19        return self
20
21    def fileHandleReadCompleted_(self, aNotification):
22        ui = aNotification.userInfo()
23        newData = ui.objectForKey_(NSFileHandleNotificationDataItem)
24        if newData is None:
25            if self.errorCallback is not None:
26                self.errorCallback(self, ui.objectForKey_(NSFileHandleError))
27            self.close()
28        else:
29            self.fileHandle.readInBackgroundAndNotify()
30            if self.readCallback is not None:
31                self.readCallback(self, str(newData))
32
33    def close(self):
34        self.nc.removeObserver_(self)
35        if self.fileHandle is not None:
36            self.fileHandle.closeFile()
37            self.fileHandle = None
38        # break cycles in case these functions are closed over
39        # an instance of us
40        self.readCallback = None
41        self.errorCallback = None
42
43    def __del__(self):
44        # Without this, if a notification fires after we are GC'ed
45        # then the app will crash because NSNotificationCenter
46        # doesn't retain observers.  In this example, it doesn't
47        # matter, but it's worth pointing out.
48        self.close()
49
50def prompt():
51    sys.stdout.write("write something: ")
52    sys.stdout.flush()
53
54def gotLine(observer, aLine):
55    if aLine:
56        print "you wrote:", aLine.rstrip()
57        prompt()
58    else:
59        print ""
60        AppHelper.stopEventLoop()
61
62def gotError(observer, err):
63    print "error:", err
64    AppHelper.stopEventLoop()
65
66if __name__ == '__main__':
67    import sys
68    observer = FileObserver.alloc().initWithFileDescriptor_readCallback_errorCallback_(
69        sys.stdin.fileno(), gotLine, gotError)
70    prompt()
71    AppHelper.runConsoleEventLoop(installInterrupt=True)
72