Implement writing to child process
This commit is contained in:
parent
29ba13835a
commit
f7eaf3fee5
@ -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)
|
||||||
|
|||||||
@ -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()
|
||||||
|
|||||||
@ -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.
|
||||||
|
|
||||||
|
|||||||
@ -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
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user