123 lines
3.9 KiB
Python
123 lines
3.9 KiB
Python
import fcntl, os, select, pty, threading
|
|
|
|
from buffer import Buffer, ACT_NORM, ACT_NONE
|
|
import term
|
|
|
|
class PipeBuffer(Buffer):
|
|
btype = 'pipe'
|
|
terms = {
|
|
'dumb': term.Dumb,
|
|
'xterm': term.XTerm,
|
|
}
|
|
modename = 'pipe'
|
|
def __init__(self, cmd, args, name=None, term='dumb'):
|
|
Buffer.__init__(self)
|
|
self.cmd = cmd
|
|
if name:
|
|
self._name = name
|
|
else:
|
|
self._name = '*Pipe*'
|
|
|
|
self.term = self.terms[term]()
|
|
self._pid, self._pty = pty.fork()
|
|
if self._pid == 0:
|
|
os.execve(cmd, [cmd] + args, {'TERM': self.term.name})
|
|
|
|
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 _set_nonblock(self, fd):
|
|
flags = fcntl.fcntl(fd, fcntl.F_GETFL)
|
|
fcntl.fcntl(fd, fcntl.F_SETFL, flags | os.O_NDELAY)
|
|
|
|
def _filter_output(self, output):
|
|
output2 = []
|
|
i = 0
|
|
escaped = []
|
|
for c in output:
|
|
if escaped:
|
|
escaped.append(c)
|
|
if c == 'm':
|
|
escaped = []
|
|
elif c == '\x1b':
|
|
escaped.append(c)
|
|
elif c == '\n':
|
|
output2.append(c)
|
|
i = 0
|
|
elif c == '\t':
|
|
j = i % 8
|
|
output2.append(' ' * (8 - j))
|
|
i += 8 - j
|
|
elif c == '\a':
|
|
pass
|
|
elif c == '\b':
|
|
if i > 0:
|
|
output2.pop(-1)
|
|
i -= 1
|
|
else:
|
|
output2.append(c)
|
|
i += 1
|
|
return ''.join(output2)
|
|
|
|
def pipe_read(self):
|
|
fd = self._pty
|
|
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)
|
|
end = self.get_buffer_end()
|
|
data = self.term.term_filter(data)
|
|
self.insert_string(end, data, force=True, act=ACT_NONE)
|
|
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):
|
|
pass
|
|
os.close(fd)
|
|
|
|
def pipe_write(self, s):
|
|
self._lock.acquire()
|
|
self._towrite += s
|
|
self._lock.release()
|
|
|
|
def insert_string(self, p, s, act=ACT_NORM, force=False):
|
|
lines = s.split("\n")
|
|
self.insert_lines(p, lines, act, force)
|
|
|
|
def insert_lines(self, p, lines, act=ACT_NORM, force=False):
|
|
llen = len(lines)
|
|
assert llen > 0
|
|
if not force and self.readonly():
|
|
raise ReadOnlyError("buffer is read-only")
|
|
p2 = p.vadd(len(lines[-1]), llen - 1)
|
|
if llen > 1:
|
|
self.lines.insert(p.y + 1, [])
|
|
self.lines[p.y + 1] = lines[-1] + self.lines[p.y][p.x:]
|
|
self.lines[p.y] = self.lines[p.y][:p.x] + lines[0]
|
|
for i in range(1, llen - 1):
|
|
self.lines.insert(p.y + i, lines[i])
|
|
else:
|
|
self.lines[p.y] = self.lines[p.y][:p.x] + lines[-1] + self.lines[p.y][p.x:]
|
|
self._region_add(p, p2, lines, act)
|
|
self.modified = True
|
|
|
|
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")
|