Refactor to make TerminalWidget self contained
This commit is contained in:
parent
5088f9b8e5
commit
226e333e9e
@ -7,16 +7,13 @@ import io
|
||||
|
||||
from PyQt5.QtCore import QObject, QSocketNotifier
|
||||
|
||||
from .screen import Screen
|
||||
from .term import TerminalWidget
|
||||
from .utils import resize_pty, hangup, create_pty
|
||||
from .tracker import ChangeTracker
|
||||
from pyte.streams import Stream
|
||||
|
||||
|
||||
class Boss(QObject):
|
||||
|
||||
def __init__(self, opts, parent):
|
||||
def __init__(self, opts, parent, dump_commands):
|
||||
QObject.__init__(self, parent)
|
||||
self.shutting_down = False
|
||||
self.write_buf = memoryview(b'')
|
||||
@ -25,17 +22,13 @@ class Boss(QObject):
|
||||
self.write_notifier = QSocketNotifier(create_pty()[0], QSocketNotifier.Write, self)
|
||||
self.write_notifier.setEnabled(False)
|
||||
self.write_notifier.activated.connect(self.write_ready)
|
||||
self.tracker = ChangeTracker(self)
|
||||
self.screen = s = Screen(opts, self.tracker, parent=self)
|
||||
self.stream = Stream(s)
|
||||
s.write_to_child.connect(self.write_to_child)
|
||||
self.term = TerminalWidget(opts, self.tracker, self.screen.linebuf, parent)
|
||||
self.term = TerminalWidget(opts, parent, dump_commands)
|
||||
self.term.relayout_lines.connect(self.relayout_lines)
|
||||
self.term.send_data_to_child.connect(self.write_to_child)
|
||||
resize_pty(self.screen.columns, self.screen.lines)
|
||||
self.term.write_to_child.connect(self.write_to_child)
|
||||
resize_pty(80, 24)
|
||||
|
||||
def apply_opts(self, opts):
|
||||
self.screen.apply_opts(opts)
|
||||
self.term.apply_opts(opts)
|
||||
|
||||
def read_ready(self, read_fd):
|
||||
@ -50,7 +43,7 @@ class Boss(QObject):
|
||||
self.read_notifier.setEnabled(False)
|
||||
self.parent().child_process_died()
|
||||
return
|
||||
self.stream.feed(data)
|
||||
self.term.feed(data)
|
||||
|
||||
def write_ready(self, write_fd):
|
||||
if not self.shutting_down:
|
||||
@ -65,8 +58,7 @@ class Boss(QObject):
|
||||
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)
|
||||
def relayout_lines(self, cells_per_line, lines_per_screen):
|
||||
resize_pty(cells_per_line, lines_per_screen)
|
||||
|
||||
def shutdown(self):
|
||||
|
||||
@ -24,13 +24,13 @@ class MainWindow(QMainWindow):
|
||||
|
||||
report_error = pyqtSignal(object)
|
||||
|
||||
def __init__(self, opts):
|
||||
def __init__(self, opts, dump_commands):
|
||||
QMainWindow.__init__(self)
|
||||
self.setWindowTitle(appname)
|
||||
sys.excepthook = self.on_unhandled_error
|
||||
self.report_error.connect(self.show_error, type=Qt.QueuedConnection)
|
||||
self.handle_unix_signals()
|
||||
self.boss = Boss(opts, self)
|
||||
self.boss = Boss(opts, self, dump_commands)
|
||||
self.setCentralWidget(self.boss.term)
|
||||
|
||||
def on_unhandled_error(self, etype, value, tb):
|
||||
@ -85,6 +85,7 @@ def option_parser():
|
||||
a('-d', '--directory', default='.', help=_('Change to the specified directory when launching'))
|
||||
a('--version', action='version', version='{} {} by Kovid Goyal'.format(appname, '.'.join(str_version)))
|
||||
a('--profile', action='store_true', default=False, help=_('Show profiling data after exit'))
|
||||
a('--dump-commands', action='store_true', default=False, help=_('Output commands received from child process to stdout'))
|
||||
return parser
|
||||
|
||||
|
||||
@ -114,7 +115,7 @@ def main():
|
||||
validate_font(opts)
|
||||
except ValueError as err:
|
||||
raise SystemExit(str(err)) from None
|
||||
w = MainWindow(opts)
|
||||
w = MainWindow(opts, args.dump_commands)
|
||||
w.show()
|
||||
if args.profile:
|
||||
import cProfile
|
||||
|
||||
@ -69,6 +69,9 @@ class Screen(QObject):
|
||||
if sz != self.tophistorybuf.maxlen:
|
||||
self.tophistorybuf = deque(self.tophistorybuf, maxlen=sz)
|
||||
|
||||
def line(self, i):
|
||||
return self.linebuf[i]
|
||||
|
||||
def __repr__(self):
|
||||
return ("{0}({1}, {2})".format(self.__class__.__name__,
|
||||
self.columns, self.lines))
|
||||
|
||||
@ -4,18 +4,20 @@
|
||||
|
||||
from functools import lru_cache
|
||||
from itertools import product
|
||||
from typing import Tuple, Iterator, Sequence
|
||||
from typing import Tuple, Iterator
|
||||
|
||||
from PyQt5.QtCore import pyqtSignal, QTimer, QRect, Qt
|
||||
from PyQt5.QtGui import QColor, QPainter, QFont, QFontMetrics, QRegion, QPen, QPixmap
|
||||
from PyQt5.QtWidgets import QWidget
|
||||
|
||||
from .config import build_ansi_color_tables, Options, fg_color_table, bg_color_table
|
||||
from .data_types import Line, Cursor, HAS_BG_MASK, COL_SHIFT, COL_MASK, as_color
|
||||
from .data_types import Cursor, HAS_BG_MASK, COL_SHIFT, COL_MASK, as_color
|
||||
from .utils import set_current_font_metrics
|
||||
from .tracker import ChangeTracker
|
||||
from .screen import wrap_cursor_position
|
||||
from .keys import key_event_to_data
|
||||
from .screen import Screen
|
||||
from pyte.streams import Stream, DebugStream
|
||||
|
||||
|
||||
def ascii_width(fm: QFontMetrics) -> int:
|
||||
@ -41,18 +43,24 @@ def pixmap_for_text(text, color, default_fg, font, w, h, baseline):
|
||||
|
||||
class TerminalWidget(QWidget):
|
||||
|
||||
relayout_lines = pyqtSignal(object, object, object, object)
|
||||
relayout_lines = pyqtSignal(object, object)
|
||||
write_to_child = pyqtSignal(object)
|
||||
send_data_to_child = pyqtSignal(object)
|
||||
cells_per_line = 80
|
||||
lines_per_screen = 24
|
||||
|
||||
def __init__(self, opts: Options, tracker: ChangeTracker, linebuf: Sequence[Line], parent: QWidget=None):
|
||||
def __init__(self, opts: Options, parent: QWidget=None, dump_commands: bool=False):
|
||||
QWidget.__init__(self, parent)
|
||||
self.cursor = Cursor()
|
||||
self.tracker = ChangeTracker(self)
|
||||
self.tracker.dirtied.connect(self.update_screen)
|
||||
sclass = DebugStream if dump_commands else Stream
|
||||
self.screen = Screen(opts, self.tracker, parent=self)
|
||||
self.screen.write_to_child.connect(self.write_to_child)
|
||||
self.stream = sclass(self.screen)
|
||||
self.feed = self.stream.feed
|
||||
self.last_drew_cursor_at = (0, 0)
|
||||
self.setFocusPolicy(Qt.WheelFocus)
|
||||
tracker.dirtied.connect(self.update_screen)
|
||||
self.linebuf = linebuf
|
||||
self.cursor = Cursor()
|
||||
self.setAutoFillBackground(True)
|
||||
self.apply_opts(opts)
|
||||
self.debounce_resize_timer = t = QTimer(self)
|
||||
@ -66,6 +74,7 @@ class TerminalWidget(QWidget):
|
||||
self.pending_update = QRegion()
|
||||
|
||||
def apply_opts(self, opts):
|
||||
self.screen.apply_opts(opts)
|
||||
self.opts = opts
|
||||
pixmap_for_text.cache_clear()
|
||||
pal = self.palette()
|
||||
@ -97,7 +106,8 @@ class TerminalWidget(QWidget):
|
||||
self.line_width = self.cells_per_line * self.cell_width
|
||||
self.layout_size = self.size()
|
||||
if (previous, previousl) != (self.cells_per_line, self.lines_per_screen):
|
||||
self.relayout_lines.emit(previous, self.cells_per_line, previousl, self.lines_per_screen)
|
||||
self.screen.resize(self.lines_per_screen, self.cells_per_line)
|
||||
self.relayout_lines.emit(self.cells_per_line, self.lines_per_screen)
|
||||
self.update()
|
||||
|
||||
def resizeEvent(self, ev):
|
||||
@ -180,7 +190,7 @@ class TerminalWidget(QWidget):
|
||||
x, y = wrap_cursor_position(self.cursor.x, self.cursor.y, len(self.line_positions), len(self.cell_positions))
|
||||
r = QRect(self.cell_positions[x], self.line_positions[y], self.cell_width, self.cell_height)
|
||||
self.last_drew_cursor_at = x, y
|
||||
line = self.linebuf[x]
|
||||
line = self.screen.line(x)
|
||||
colors = line.basic_cell_data(y)[2]
|
||||
if colors & HAS_BG_MASK:
|
||||
bg = as_color(colors >> COL_SHIFT, bg_color_table())
|
||||
@ -193,7 +203,7 @@ class TerminalWidget(QWidget):
|
||||
painter.drawRect(r)
|
||||
|
||||
def paint_cell(self, painter: QPainter, col: int, row: int) -> None:
|
||||
line = self.linebuf[row]
|
||||
line = self.screen.line(row)
|
||||
ch, attrs, colors = line.basic_cell_data(col)
|
||||
x, y = self.cell_positions[col], self.line_positions[row]
|
||||
if colors & HAS_BG_MASK and (col != self.last_drew_cursor_at[0] or row != self.last_drew_cursor_at[1]):
|
||||
|
||||
@ -362,7 +362,10 @@ class DebugStream(Stream):
|
||||
default, which means -- debug all events).
|
||||
"""
|
||||
|
||||
def __init__(self, to=sys.stdout, only=(), *args, **kwargs):
|
||||
def __init__(self, *args, **kwargs):
|
||||
to = kwargs.pop('to', sys.stdout)
|
||||
only = kwargs.pop('only', ())
|
||||
|
||||
def safe_str(chunk):
|
||||
if isinstance(chunk, bytes):
|
||||
chunk = chunk.decode("utf-8")
|
||||
@ -375,6 +378,7 @@ class DebugStream(Stream):
|
||||
pass
|
||||
|
||||
class Bugger(object):
|
||||
|
||||
def __getattr__(self, event):
|
||||
if only and event not in only:
|
||||
return noop
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user