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)
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)
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:
@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):