From 94c7206c42595fe16229d45028ef114984395ef6 Mon Sep 17 00:00:00 2001 From: Christian Heller Date: Mon, 29 Sep 2025 06:36:01 +0200 Subject: [PATCH] Explicate which indices are used negatively and which positively. --- src/ircplom/tui_base.py | 90 +++++++++++++++++++++-------------------- 1 file changed, 46 insertions(+), 44 deletions(-) diff --git a/src/ircplom/tui_base.py b/src/ircplom/tui_base.py index 2ef81c7..3414a7d 100644 --- a/src/ircplom/tui_base.py +++ b/src/ircplom/tui_base.py @@ -84,7 +84,7 @@ class _Widget(ABC): class _ScrollableWidget(_Widget): - _history_idx: int + _history_idx_neg: int def __init__(self, write: Callable[..., None], **kwargs) -> None: super().__init__(**kwargs) @@ -112,12 +112,12 @@ class _HistoryWidget(_ScrollableWidget): def __init__(self, wrap: Callable[[str], list[str]], **kwargs) -> None: super().__init__(**kwargs) self._wrap = wrap - self._wrapped_idx = self._history_idx = -1 + self._wrapped_idx_neg = self._history_idx_neg = -1 self._wrapped: list[tuple[Optional[int], str]] = [] - def _add_wrapped(self, idx_original, line) -> int: + def _add_wrapped(self, idx_pos_original, line) -> int: wrapped_lines = self._wrap(line) - self._wrapped += [(idx_original, line) for line in wrapped_lines] + self._wrapped += [(idx_pos_original, line) for line in wrapped_lines] return len(wrapped_lines) def set_geometry(self, sizes: _YX) -> None: @@ -127,45 +127,47 @@ class _HistoryWidget(_ScrollableWidget): self._wrapped.clear() self._wrapped += [(None, '')] * self._sizes.y if self._history: - for idx_history, line in enumerate(self._history): - self._add_wrapped(idx_history, line) + for idx_pos_history, line in enumerate(self._history): + self._add_wrapped(idx_pos_history, line) wrapped_lines_for_history_idx = [ t for t in self._wrapped - if t[0] == len(self._history) + self._history_idx] - idx_their_last = self._wrapped.index( + if t[0] == len(self._history) + self._history_idx_neg] + # ensure that of the full line identified by ._history_idx_neg, + # ._wrapped_idx_neg point to the lowest of its wrap parts + idx_pos_their_last = self._wrapped.index( wrapped_lines_for_history_idx[-1]) - self._wrapped_idx = idx_their_last - len(self._wrapped) + self._wrapped_idx_neg = idx_pos_their_last - len(self._wrapped) def append(self, to_append: str) -> None: super().append(to_append) self.taint() - if self._history_idx < -1: - self._history_idx -= 1 + 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) - if self._wrapped_idx < -1: - self._wrapped_idx -= n_wrapped_lines + if self._wrapped_idx_neg < -1: + self._wrapped_idx_neg -= n_wrapped_lines def _draw(self) -> None: - start_idx = self._wrapped_idx - self._sizes.y + 1 - end_idx = self._wrapped_idx - idx_bookmark = ([idx for idx, t in enumerate(self._wrapped) - if t[0] == self._bookmark]+[0])[0] - wrapped = (self._wrapped[:idx_bookmark+1] + start_idx_neg = self._wrapped_idx_neg - self._sizes.y + 1 + end_idx_neg = self._wrapped_idx_neg + idx_pos_bookmark = ([idx_pos for idx_pos, t in enumerate(self._wrapped) + if t[0] == self._bookmark]+[0])[0] + wrapped = (self._wrapped[:idx_pos_bookmark+1] + [(0, '-'*self._sizes.x)] - + self._wrapped[idx_bookmark+1:]) - to_write = [t[1] for t in wrapped[start_idx:end_idx]] - if self._wrapped_idx < -1: - scroll_info = f'vvv [{(-1) * self._wrapped_idx}] ' + + self._wrapped[idx_pos_bookmark+1:]) + to_write = [t[1] for t in wrapped[start_idx_neg:end_idx_neg]] + if self._wrapped_idx_neg < -1: + scroll_info = f'vvv [{(-1) * self._wrapped_idx_neg}] ' scroll_info += 'v' * (self._sizes.x - len(scroll_info)) to_write += [scroll_info] else: - to_write += [wrapped[self._wrapped_idx][1]] + to_write += [wrapped[self._wrapped_idx_neg][1]] for i, line in enumerate(to_write): self._write(line, i) - hist_idx = self._wrapped[end_idx][0] - self._last_read = max(self._last_read, hist_idx or 0) + hist_idx_pos = self._wrapped[end_idx_neg][0] + self._last_read = max(self._last_read, hist_idx_pos or 0) def bookmark(self) -> None: 'Store to what most recent line we have (been) scrolled.' @@ -180,21 +182,21 @@ class _HistoryWidget(_ScrollableWidget): super()._scroll(up) if self._drawable: if up: - self._wrapped_idx = max( + self._wrapped_idx_neg = max( self._sizes.y + 1 - len(self._wrapped), - self._wrapped_idx - self._y_pgscroll) + self._wrapped_idx_neg - self._y_pgscroll) else: - self._wrapped_idx = min( - -1, self._wrapped_idx + self._y_pgscroll) - history_idx_to_wrapped_idx = self._wrapped[self._wrapped_idx][0] - if history_idx_to_wrapped_idx is not None: - self._history_idx = history_idx_to_wrapped_idx\ + 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) class PromptWidget(_ScrollableWidget): 'Manages/displays keyboard input field.' - _history_idx: int = 0 + _history_idx_neg: int = 0 _input_buffer_unsafe: str _cursor_x: int @@ -245,19 +247,19 @@ class PromptWidget(_ScrollableWidget): def _scroll(self, up: bool = True) -> None: super()._scroll(up) - if up and -(self._history_idx) < len(self._history): - if self._history_idx == 0 and self._input_buffer: + if up and -(self._history_idx_neg) < len(self._history): + if self._history_idx_neg == 0 and self._input_buffer: self._archive_prompt() - self._history_idx -= 1 - self._history_idx -= 1 - self._reset_buffer(self._history[self._history_idx]) + self._history_idx_neg -= 1 + self._history_idx_neg -= 1 + self._reset_buffer(self._history[self._history_idx_neg]) elif not up: - if self._history_idx < 0: - self._history_idx += 1 - if self._history_idx == 0: + if self._history_idx_neg < 0: + self._history_idx_neg += 1 + if self._history_idx_neg == 0: self._reset_buffer('') else: - self._reset_buffer(self._history[self._history_idx]) + self._reset_buffer(self._history[self._history_idx_neg]) elif self._input_buffer: self._archive_prompt() @@ -267,7 +269,7 @@ class PromptWidget(_ScrollableWidget): self._input_buffer = (self._input_buffer[:self._cursor_x - 1] + to_insert + self._input_buffer[self._cursor_x - 1:]) - self._history_idx = 0 + self._history_idx_neg = 0 def cmd__backspace(self) -> None: 'Truncate current content by one character, if possible.' @@ -275,7 +277,7 @@ class PromptWidget(_ScrollableWidget): self._cursor_x -= 1 self._input_buffer = (self._input_buffer[:self._cursor_x] + self._input_buffer[self._cursor_x + 1:]) - self._history_idx = 0 + self._history_idx_neg = 0 def cmd__move_cursor(self, direction: str) -> None: 'Move cursor one space into direction ("left" or "right") if possible.' -- 2.30.2