diff --git a/kitty/boss.py b/kitty/boss.py index 1c4d95454..a94d8ba30 100644 --- a/kitty/boss.py +++ b/kitty/boss.py @@ -6,20 +6,29 @@ from collections import deque from PyQt5.QtCore import QObject +from .data_types import Line, rewrap_lines from .term import TerminalWidget + class Boss(QObject): def __init__(self, opts, parent=None): + QObject.__init__(self, parent) self.linebuf = deque(maxlen=max(1000, opts.scrollback_lines)) self.term = TerminalWidget(opts, self.linebuf, parent) self.term.relayout_lines.connect(self.relayout_lines) def apply_opts(self, opts): if opts.scrollback_lines != self.linebuf.maxlen: - self.linebuf, old = deque(maxlen=max(1000, opts.scrollback_lines)), self.linebuf - self.linebuf.extend(old) + self.linebuf = deque(self.linebuf, maxlen=max(1000, opts.scrollback_lines)) + self.term.linebuf = self.linebuf self.term.apply_opts(opts) - def relayout_lines(self): - pass + def relayout_lines(self, previous, cells_per_line): + if previous == cells_per_line: + return + old = self.linebuf.copy() + print(list(old)) + self.linebuf.clear() + self.linebuf.extend(rewrap_lines(old, cells_per_line)) + print(list(self.linebuf)) diff --git a/kitty/data_types.py b/kitty/data_types.py index 66bb8642d..6a0847cda 100644 --- a/kitty/data_types.py +++ b/kitty/data_types.py @@ -2,7 +2,7 @@ # vim:fileencoding=utf-8 # License: GPL v3 Copyright: 2016, Kovid Goyal -from typing import Tuple, Dict, Union +from typing import Tuple, Dict, Union, Iterator, Sequence from numpy import zeros, dtype from PyQt5.QtGui import QColor @@ -12,7 +12,7 @@ color_type = dtype([('type', 'u1'), ('r', 'u1'), ('g', 'u1'), ('b', 'u1')]) class Line: - __slots__ = 'char fg bg bold italic reverse strikethrough decoration decoration_fg'.split() + __slots__ = 'char fg bg bold italic reverse strikethrough decoration decoration_fg width'.split() continued = False def __init__(self, sz: int): @@ -25,6 +25,25 @@ class Line: self.strikethrough = zeros(sz, bool) self.decoration = zeros(sz, 'u1') self.decoration_fg = zeros(sz, color_type) + self.width = zeros(sz, 'u1') + + def __len__(self): + return len(self.char) + + def copy_char(self, src: int, to, dest: int) -> None: + to.char[dest] = self.char[src] + to.fg[dest] = self.fg[src] + to.bg[dest] = self.bg[src] + to.bold[dest] = self.bold[src] + to.italic[dest] = self.italic[src] + to.reverse[dest] = self.reverse[src] + to.strikethrough[dest] = self.strikethrough[src] + to.decoration[dest] = self.decoration[src] + to.decoration_fg[dest] = self.decoration_fg[src] + to.width[dest] = self.width[src] + + def __repr__(self) -> str: + return repr(''.join(self.char)) def as_color(entry: Tuple[int, int, int, int], color_table: Dict[int, QColor]) -> Union[QColor, None]: @@ -33,3 +52,38 @@ def as_color(entry: Tuple[int, int, int, int], color_table: Dict[int, QColor]) - return color_table.get(r) if t == 2: return QColor(r, g, b) + + +def copy_char(src: Line, dest: Line, src_pos: int, dest_pos: int) -> None: + for i in range(src.width[src_pos]): + src.copy_char(src_pos + i, dest, dest_pos + i) + + +def rewrap_lines(lines: Sequence[Line], width: int) -> Iterator[Line]: + if lines: + current_line, current_dest_pos = Line(width), 0 + src_limit = len(lines[0]) - 1 + for i, src in enumerate(lines): + current_src_pos = 0 + while current_src_pos <= src_limit: + cw = src.width[current_src_pos] + if cw == 0: + # Hard line break, start a new line + yield current_line + current_line, current_dest_pos = Line(width), 0 + break + if cw + current_dest_pos > width: + # dest line does not have enough space to hold the current source char + yield current_line + current_line, current_dest_pos = Line(width), 0 + current_line.continued = True + copy_char(src, current_line, current_src_pos, current_dest_pos) + current_dest_pos += cw + current_src_pos += cw + else: + hard_break = src is not lines[-1] and not lines[i + 1].continued + if hard_break: + yield current_line + current_line, current_dest_pos = Line(width), 0 + if current_dest_pos: + yield current_line