Implement writing to child process

This commit is contained in:
Kovid Goyal 2016-10-16 19:38:35 +05:30
parent 29ba13835a
commit f7eaf3fee5
4 changed files with 38 additions and 15 deletions

View File

@ -2,18 +2,27 @@
# vim:fileencoding=utf-8 # vim:fileencoding=utf-8
# License: GPL v3 Copyright: 2016, Kovid Goyal <kovid at kovidgoyal.net> # License: GPL v3 Copyright: 2016, Kovid Goyal <kovid at kovidgoyal.net>
from PyQt5.QtCore import QObject import os
import io
from PyQt5.QtCore import QObject, QSocketNotifier
from .screen import Screen from .screen import Screen
from .term import TerminalWidget from .term import TerminalWidget
from .utils import resize_pty, hangup from .utils import resize_pty, hangup, create_pty
class Boss(QObject): class Boss(QObject):
def __init__(self, opts, parent=None): def __init__(self, opts, parent):
QObject.__init__(self, parent) QObject.__init__(self, parent)
self.screen = Screen(opts, parent=self) self.write_buf = memoryview(b'')
self.read_notifier = QSocketNotifier(create_pty()[0], QSocketNotifier.Read, self)
self.read_notifier.activated.connect(self.read_ready)
self.write_notifier = QSocketNotifier(create_pty()[0], QSocketNotifier.Write, self)
self.write_notifier.setEnabled(False)
self.write_notifier.activated.connect(self.write_ready)
self.screen = Screen(opts, self.write_to_child, parent=self)
self.term = TerminalWidget(opts, self.screen.linebuf, parent) self.term = TerminalWidget(opts, self.screen.linebuf, parent)
self.term.relayout_lines.connect(self.relayout_lines) self.term.relayout_lines.connect(self.relayout_lines)
resize_pty(self.screen.columns, self.screen.lines) resize_pty(self.screen.columns, self.screen.lines)
@ -22,6 +31,25 @@ class Boss(QObject):
self.screen.apply_opts(opts) self.screen.apply_opts(opts)
self.term.apply_opts(opts) self.term.apply_opts(opts)
def read_ready(self, read_fd):
data = os.read(read_fd, io.DEFAULT_BUFFER_SIZE)
if not data:
# EOF
self.parent().child_process_died()
return
def write_ready(self, write_fd):
while self.write_buf:
n = os.write(write_fd, io.DEFAULT_BUFFER_SIZE)
if not n:
return
self.write_buf = self.write_buf[n:]
self.write_notifier.setEnabled(False)
def write_to_child(self, data):
self.write_buf = memoryview(self.write_buf.tobytes() + data)
self.write_notifier.setEnabled(True)
def relayout_lines(self, previous, cells_per_line, previousl, lines_per_screen): def relayout_lines(self, previous, cells_per_line, previousl, lines_per_screen):
self.screen.resize(lines_per_screen, cells_per_line) self.screen.resize(lines_per_screen, cells_per_line)
resize_pty(cells_per_line, lines_per_screen) resize_pty(cells_per_line, lines_per_screen)

View File

@ -59,6 +59,9 @@ class MainWindow(QMainWindow):
if signal.SIGINT in signals or signal.SIGTERM in signals: if signal.SIGINT in signals or signal.SIGTERM in signals:
self.shutdown() self.shutdown()
def child_process_died(self):
self.shutdown()
def shutdown(self): def shutdown(self):
self.close() self.close()
self.boss.shutdown() self.boss.shutdown()

View File

@ -45,8 +45,9 @@ class Screen(QObject):
line_added_to_history = pyqtSignal() line_added_to_history = pyqtSignal()
_notify_cursor_position = True _notify_cursor_position = True
def __init__(self, opts, columns: int=80, lines: int=24, parent=None): def __init__(self, opts, write_to_child, columns: int=80, lines: int=24, parent=None):
QObject.__init__(self, parent) QObject.__init__(self, parent)
self.write_process_input = write_to_child
self.savepoints = deque() self.savepoints = deque()
self.columns = columns self.columns = columns
self.lines = lines self.lines = lines
@ -855,16 +856,6 @@ class Screen(QObject):
self.write_process_input( self.write_process_input(
ctrl.CSI + "{0};{1}R".format(y, x).encode()) ctrl.CSI + "{0};{1}R".format(y, x).encode())
def write_process_input(self, data):
"""Writes data to the process running inside the terminal.
By default is a noop.
:param bytes data: data to write to the process ``stdin``.
.. versionadded:: 0.5.0
"""
def debug(self, *args, **kwargs): def debug(self, *args, **kwargs):
"""Endpoint for unrecognized escape sequences. """Endpoint for unrecognized escape sequences.

View File

@ -36,6 +36,7 @@ def create_pty():
if not hasattr(create_pty, 'master'): if not hasattr(create_pty, 'master'):
create_pty.master, create_pty.slave = os.openpty() create_pty.master, create_pty.slave = os.openpty()
fcntl.fcntl(create_pty.slave, fcntl.F_SETFD, fcntl.fcntl(create_pty.slave, fcntl.F_GETFD) & ~fcntl.FD_CLOEXEC) fcntl.fcntl(create_pty.slave, fcntl.F_SETFD, fcntl.fcntl(create_pty.slave, fcntl.F_GETFD) & ~fcntl.FD_CLOEXEC)
# Note that master and slave are in blocking mode
return create_pty.master, create_pty.slave return create_pty.master, create_pty.slave