From: Christian Heller Date: Tue, 7 Oct 2025 06:23:25 +0000 (+0200) Subject: Reorganize history log drawing to avoid storing empty lines in history. X-Git-Url: https://plomlompom.com/repos/%7Broute%7D?a=commitdiff_plain;p=ircplom Reorganize history log drawing to avoid storing empty lines in history. --- diff --git a/src/ircplom/testing.py b/src/ircplom/testing.py index ad63e37..fd63e6d 100644 --- a/src/ircplom/testing.py +++ b/src/ircplom/testing.py @@ -242,6 +242,9 @@ class TestingClientTui(ClientTui): self._playbook.put_keypress = self._term._q_keypresses.put self._playbook.ensure_has_started() # if .__init__ didn't yet by log() + def _switch_window(self, idx: int) -> None: + self._window_idx = idx + @classmethod def on_file(cls, path_test: Path): 'Return cls with ._path_test set.' diff --git a/src/ircplom/tui_base.py b/src/ircplom/tui_base.py index fe74f99..8b5028e 100644 --- a/src/ircplom/tui_base.py +++ b/src/ircplom/tui_base.py @@ -115,17 +115,21 @@ class _ScrollableWidget(_Widget): class _HistoryWidget(_ScrollableWidget): _history_idx_neg = -1 - _newest_read_history_idx: int = 0 - _bookmark_history_idx_pos: int = 0 + _UNSET_HISTORY_IDX_POS: int = -1 + _COMPARAND_HISTORY_IDX_POS: int = -2 + _BOOKMARK_HISTORY_IDX_POS: int = -3 + _PADDING_HISTORY_IDX_POS: int = -4 + _newest_read_history_idx_pos: int _wrapped_idx_neg: int _y_pgscroll: int def __init__(self, wrap: Callable[[str], list[str]], **kwargs) -> None: super().__init__(**kwargs) self._wrap = wrap - self._wrapped: list[tuple[Optional[int], str]] = [] + self._wrapped: list[tuple[int, str]] = [] + self._newest_read_history_idx_pos = self._UNSET_HISTORY_IDX_POS - def _add_wrapped(self, history_idx_pos, line) -> int: + def _add_wrapped(self, history_idx_pos: int, line: str) -> int: wrapped_lines = self._wrap(line) self._wrapped += [(history_idx_pos, line) for line in wrapped_lines] return len(wrapped_lines) @@ -135,19 +139,16 @@ class _HistoryWidget(_ScrollableWidget): if self._drawable: self._y_pgscroll = self._sizes.y // 2 self._wrapped.clear() - self._wrapped_idx_neg = -1 - self._wrapped += [(None, '')] * self._sizes.y for history_idx_pos, line in enumerate(self._history): self._add_wrapped(history_idx_pos, line) # ensure that of the full line identified by ._history_idx_neg, # ._wrapped_idx_neg point to the lowest of its wrap parts - wrapped_lines_for_history_idx = [ - t for t in self._wrapped - if t[0] == len(self._history) + self._history_idx_neg] - if wrapped_lines_for_history_idx: - idx_pos_their_last = self._wrapped.index( - wrapped_lines_for_history_idx[-1]) - self._wrapped_idx_neg = idx_pos_their_last - len(self._wrapped) + self._wrapped_idx_neg = ( + -1 if (not self._wrapped) + else (-len(self._wrapped) + + self._last_wrapped_idx_pos_for_hist_idx_pos( + self._history_idx_neg + len(self._history)))) + self.bookmark() def append(self, to_append: str) -> None: super().append(to_append) @@ -155,48 +156,63 @@ class _HistoryWidget(_ScrollableWidget): if self._history_idx_neg < -1: self._history_idx_neg -= 1 if self._drawable: - n_wrapped_lines = self._add_wrapped(len(self._history) - - 1, to_append) + n_wrapped = self._add_wrapped(len(self._history) - 1, to_append) if self._wrapped_idx_neg < -1: - self._wrapped_idx_neg -= n_wrapped_lines + self._wrapped_idx_neg -= n_wrapped def _draw(self) -> None: - start_idx_neg = self._wrapped_idx_neg - self._sizes.y + 1 add_scroll_info = self._wrapped_idx_neg < -1 - end_idx_neg = self._wrapped_idx_neg if add_scroll_info else None - bookmark_wrapped_idx_pos\ - = ([idx_pos for idx_pos, t in enumerate(self._wrapped) - if t[0] == self._bookmark_history_idx_pos] + [0])[0] - wrapped = (self._wrapped[:bookmark_wrapped_idx_pos] - + [(0, '-' * self._sizes.x)] # bookmark line - + self._wrapped[bookmark_wrapped_idx_pos:]) + start_idx_neg = (self._wrapped_idx_neg + - self._sizes.y + 1 + bool(add_scroll_info)) + end_idx_neg = (self._wrapped_idx_neg + 1) if add_scroll_info else None + + wrapped = self._wrapped[start_idx_neg:end_idx_neg] + while len(wrapped) < self._sizes.y - bool(add_scroll_info): + wrapped.insert(0, (self._PADDING_HISTORY_IDX_POS, '')) to_write_w_attrs: list[tuple[Optional[str], str]] = [] - prev_idx_unwrapped: Optional[int] = -1 + prev_history_idx_pos = self._COMPARAND_HISTORY_IDX_POS attrs: list[str] - for idx_unwrapped, line in wrapped[start_idx_neg:end_idx_neg]: - if idx_unwrapped != prev_idx_unwrapped: + for history_idx_pos, line in wrapped: + if history_idx_pos != prev_history_idx_pos: attrs = ['on_black'] for c in line.split(LOG_FMT_SEP, maxsplit=1)[0]: attrs += list(LOG_FMT_ATTRS.get(c, tuple())) - prev_idx_unwrapped = idx_unwrapped + prev_history_idx_pos = history_idx_pos to_write_w_attrs += [(','.join(attrs), line)] if add_scroll_info: - scroll_info = f'vvv [{(-1) * self._wrapped_idx_neg}] ' + scroll_info = f'vvv [{(-1) * self._history_idx_neg}] ' scroll_info += 'v' * (self._sizes.x - len(scroll_info)) to_write_w_attrs += [('reverse', scroll_info)] for idx, line_t in enumerate(to_write_w_attrs): self._write(start_y=idx, attributes=line_t[0], msg=line_t[1]) - hist_idx_pos = self._wrapped[(end_idx_neg or 0) - 1][0] or 0 - self._newest_read_history_idx = max(self._newest_read_history_idx, - hist_idx_pos) + self._newest_read_history_idx_pos\ + = max(self._newest_read_history_idx_pos, wrapped[-1][0]) def bookmark(self) -> None: - 'Store to what most recent line we have (been) scrolled.' - self._bookmark_history_idx_pos = self._newest_read_history_idx + 1 + 'Store next idx to what most recent line we have (been) scrolled.' + bookmark = (self._BOOKMARK_HISTORY_IDX_POS, '-' * self._sizes.x) + if bookmark in self._wrapped: + bookmark_idx_neg\ + = self._wrapped.index(bookmark) - len(self._wrapped) + del self._wrapped[bookmark_idx_neg] + if bookmark_idx_neg > self._wrapped_idx_neg: + self._wrapped_idx_neg += 1 + bookmark_wrapped_idx_pos = ( + 0 if (not self._wrapped) + else (1 + self._last_wrapped_idx_pos_for_hist_idx_pos( + self._newest_read_history_idx_pos))) + self._wrapped.insert(bookmark_wrapped_idx_pos, bookmark) + if bookmark_wrapped_idx_pos - len(self._wrapped)\ + > self._wrapped_idx_neg: + self._wrapped_idx_neg -= 1 + + def _last_wrapped_idx_pos_for_hist_idx_pos(self, hist_idx_pos: int) -> int: + return [idx for idx, t in enumerate(self._wrapped) + if t[0] == hist_idx_pos][-1] @property def has_unread_highlight(self) -> bool: @@ -207,22 +223,21 @@ class _HistoryWidget(_ScrollableWidget): @property def n_lines_unread(self) -> int: 'How many new lines have been logged since last focus.' - return len(self._history) - self._newest_read_history_idx - 1 + return len(self._history) - (self._newest_read_history_idx_pos + 1) def _scroll(self, up: bool = True) -> None: super()._scroll(up) - if self._drawable: + if self._drawable and self._wrapped: if up: self._wrapped_idx_neg = max( - self._sizes.y + 1 - len(self._wrapped), + -len(self._wrapped), self._wrapped_idx_neg - self._y_pgscroll) else: self._wrapped_idx_neg = min( -1, self._wrapped_idx_neg + self._y_pgscroll) - hist_idx_to_wrapped_idx = self._wrapped[self._wrapped_idx_neg][0] - if hist_idx_to_wrapped_idx is not None: - self._history_idx_neg = hist_idx_to_wrapped_idx\ - - len(self._history) + self._history_idx_neg\ + = (-len(self._history) + + max(0, self._wrapped[self._wrapped_idx_neg][0])) class PromptWidget(_ScrollableWidget):