import fcntl, os, select, pty, threading, time from buffer import Buffer, ACT_NORM, ACT_NONE from term import XTerm from point import Point # evil evil evil evil evil class XTermBuffer(Buffer, XTerm): btype = 'term' modename = 'pipe' termtype = 'xterm' #termtype = 'vt100' def __init__(self, app, cmd, args, name=None): XTerm.__init__(self) Buffer.__init__(self) self.application = app self._name = name or '*XTerm*' self._pid, self._pty = pty.fork() if self._pid == 0: # child process os.execvpe(cmd, [cmd] + args, {'TERM': self.termtype}) self._lock = threading.Lock() self._towrite = '' self._done = False self._set_nonblock(self._pty) self._thread = threading.Thread(target=self.pipe_read) self._thread.setDaemon(True) self._thread.start() def _w(self): return self.windows[0] def _get_height(self): return self._w().height def _get_width(self): return self._w().width # TERM STUFF def _term_insert(self, s): w = self._w() p = w.logical_cursor() if p.x == len(self.lines[p.y]): w.buffer.insert_string(p, s, act=ACT_NONE, force=True) else: w.buffer.overwrite_char(p, s, act=ACT_NONE, force=True) def term_do_clear(self): self.set_lines([''], force=True) self._meta = [] def term_do_clear_bol(self): w = self._w() p1, p2 = w.get_line_left() self.delete(p1, p2, force=True) self._meta = [] def term_do_clear_eol(self): w = self._w() p1, p2 = w.get_line_right() self.delete(p1, p2, force=True) self._meta = [] def term_do_clear_eos(self): self._meta = [] def term_do_backspace(self): self._w().backward() def term_do_tab(self): self._term_insert(' ') def term_do_newline(self): w = self._w() p = w.logical_cursor() if p.y < len(self.lines) - 1: w.start_of_line() w.next_line() else: w.end_of_line() w.buffer.insert_string(w.logical_cursor(), "\n", act=ACT_NONE, force=True) def term_do_creturn(self): self._w().start_of_line() def term_do_delete(self): self._w().delete_right() def term_handle_print(self, c): self._term_insert(c) def term_handle_ctl(self, c): n = ord(c) if n == 7: #bell pass elif n == 8: self.term_do_backspace() elif n == 9: self.term_do_tab() elif n == 10: self.term_do_newline() elif n == 13: self.term_do_creturn() elif n == 27: self.term_do_esc(c) elif n == 127: self.term_do_delete() else: self._term_insert('%03o' % n) def term_receive(self, s): for c in s: self.term_handle(c) # BUFFER STUFF def _set_nonblock(self, fd): flags = fcntl.fcntl(fd, fcntl.F_GETFL) fcntl.fcntl(fd, fcntl.F_SETFL, flags | os.O_NDELAY) def pipe_read(self): fd = self._pty # wait until we are hooked up and ready to go while not self.windows: time.sleep(0.1) # ok, so start reading stuff! try: while not self._done: if self._towrite: ifd, ofd, efd = select.select([fd], [fd], [fd], 0.1) else: ifd, ofd, efd = select.select([fd], [], [fd], 0.1) if ifd: data = os.read(ifd[0], 1024) self.term_receive(data) self.application.need_draw = True if ofd: self._lock.acquire() n = os.write(ofd[0], self._towrite) self._towrite = self._towrite[n:] self._lock.release() if efd: raise Exception, "exception is ready: %s" % repr(efd) except (OSError, TypeError, AttributeError): pass os.close(fd) def pipe_write(self, s): self._lock.acquire() self._towrite += s self._lock.release() def name(self): return self._name def changed(self): return False def readonly(self): return True def undo(self, move, act): raise Exception, "invalid" def redo(self, move, act): raise Exception, "invalid" def reload(self): raise Exception, "invalid"