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
# 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 .term import TerminalWidget
from .utils import resize_pty, hangup
from .utils import resize_pty, hangup, create_pty
class Boss(QObject):
def __init__(self, opts, parent=None):
def __init__(self, opts, 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.relayout_lines.connect(self.relayout_lines)
resize_pty(self.screen.columns, self.screen.lines)
@ -22,6 +31,25 @@ class Boss(QObject):
self.screen.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):
self.screen.resize(lines_per_screen, cells_per_line)
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:
self.shutdown()
def child_process_died(self):
self.shutdown()
def shutdown(self):
self.close()
self.boss.shutdown()

View File

@ -45,8 +45,9 @@ class Screen(QObject):
line_added_to_history = pyqtSignal()
_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)
self.write_process_input = write_to_child
self.savepoints = deque()
self.columns = columns
self.lines = lines
@ -855,16 +856,6 @@ class Screen(QObject):
self.write_process_input(
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):
"""Endpoint for unrecognized escape sequences.

View File

@ -36,6 +36,7 @@ def create_pty():
if not hasattr(create_pty, 'master'):
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)
# Note that master and slave are in blocking mode
return create_pty.master, create_pty.slave