_display_size: YX
_y_pgscroll: int
- def __init__(self, wrap_func: Callable) -> None:
- self._wrap = wrap_func
+ def __init__(self, term: Terminal) -> None:
+ self._term = term
self._history: list[str] = []
self._wrapped: list[tuple[int, str]] = []
self._upscroll_history: int = 0
self._upscroll_wrapped: int = 0
- def apply_geometry(self, display_size: YX) -> None:
- 'Calcs .wrapped conditions based on new display_size, stored scroll.'
- self._display_size = display_size
+ def apply_geometry(self, limit_y: int) -> None:
+ 'Calcs display conditions based on new display_size, stored scroll.'
+ self._display_size = YX(limit_y, self._term.size.x)
self._y_pgscroll = self._display_size.y // 2
self._wrapped.clear()
self._wrapped += [(-1, '')] * self._display_size.y
self._upscroll_wrapped = len(self._wrapped) - (idx_last + 1)
def _add_wrapped(self, idx_original, line) -> int:
- wrapped_lines = self._wrap(line)
+ wrapped_lines = self._term.wrap(line)
self._wrapped += [(idx_original, line) for line in wrapped_lines]
return len(wrapped_lines)
self._upscroll_history += 1
self._upscroll_wrapped += n_wrapped
+ def draw(self) -> None:
+ 'Print display_size/scroll-appropriate wrapped selection of lines.'
+ start_idx = len(self._wrapped) - (self._display_size.y
+ + self._upscroll_wrapped)
+ to_write = [t[1] for t in
+ self._wrapped[start_idx:-(self._upscroll_wrapped + 1)]]
+ if self._upscroll_wrapped:
+ scroll_info = f'vvv [{self._upscroll_wrapped}] '
+ scroll_info += 'v' * (self._display_size.x - len(scroll_info))
+ to_write += [scroll_info]
+ else:
+ to_write += [self._wrapped[-1][1]]
+ for i, line in enumerate(to_write):
+ self._term.write_yx(YX(i, 0), line)
+
def scroll(self, up=True) -> None:
'Scrolls view down by half of display size.'
self._upscroll_wrapped = (
idx_lowest = self._wrapped[-(self._upscroll_wrapped + 1)][0]
self._upscroll_history = len(self._history) - (idx_lowest + 1)
- @property
- def wrapped(self) -> list[str]:
- 'Returns display_size/scroll-appropriately wrapped selection of lines.'
- start_idx = len(self._wrapped) - (self._display_size.y
- + self._upscroll_wrapped)
- to_return = [t[1] for t in
- self._wrapped[start_idx:-(self._upscroll_wrapped + 1)]]
- if self._upscroll_wrapped:
- scroll_info = f'vvv [{self._upscroll_wrapped}] '
- scroll_info += 'v' * (self._display_size.x - len(scroll_info))
- return to_return + [scroll_info]
- return to_return + [self._wrapped[-1][1]]
-
class TuiPrompt:
'Keyboard-controlled command input field.'
def __init__(self, term: Terminal, *args, **kwargs) -> None:
self._term = term
self._prompt = TuiPrompt(self._term)
- self._logs = [LogBuffer(self._term.wrap) for i in range(2)]
+ self._logs = [LogBuffer(self._term) for i in range(2)]
self._log_selected = 0
self._upscroll = 0
self._calc_and_draw_all()
self._logs[1].append(f'<- {event.payload.raw}')
elif event.type_ == 'SEND':
self._logs[1].append(f'-> {event.payload.raw}')
- self._draw_log()
+ self._log.draw()
elif event.type_ == 'KEYBINDING':
getattr(self, f'_cmd__{event.payload[0]}')(*event.payload[1:])
elif event.type_ == 'INPUT_CHAR':
# self._log+= [
# f'DEBUG {line}' for line
# in '\n'.join(format_exception(event.payload)).split('\n')]
- # self._draw_log()
+ # self._log.draw()
else:
return True
self._term.flush()
def _log(self) -> LogBuffer:
return self._logs[self._log_selected]
+ def _calc_and_draw_all(self) -> None:
+ self._term.clear()
+ self._term.calc_geometry()
+ self._prompt.start_y = self._term.size.y - 1
+ self._y_separator = self._term.size.y - 2
+ for log in self._logs:
+ log.apply_geometry(limit_y=self._y_separator)
+ self._term.write_yx(YX(self._y_separator, 0), '=' * self._term.size.x)
+ self._term.write_yx(YX(self._prompt.start_y, 0), INPUT_PROMPT)
+ self._log.draw()
+ self._prompt.draw()
+
def _cmd__prompt_backspace(self) -> None:
self._prompt.backspace()
def _cmd__scroll(self, direction: str) -> None:
self._log.scroll(up=direction == 'up')
- self._draw_log()
+ self._log.draw()
def _cmd__disconnect(self, quit_msg: str = 'ircplom says bye') -> None:
self.broadcast('SEND', IrcMessage('QUIT', [quit_msg]))
if buffer_idx < 0 or buffer_idx > len(self._logs):
return f'unavailable buffer idx: {buffer_idx}'
self._log_selected = buffer_idx
- self._draw_log()
+ self._log.draw()
return None
- def _calc_and_draw_all(self) -> None:
- self._term.clear()
- self._term.calc_geometry()
- self._prompt.start_y = self._term.size.y - 1
- self._y_separator = self._term.size.y - 2
- for log in self._logs:
- log.apply_geometry(YX(self._y_separator, self._term.size.x))
- self._draw_frame()
- self._draw_log()
- self._prompt.draw()
-
- def _draw_frame(self) -> None:
- self._term.write_yx(YX(self._y_separator, 0), '=' * self._term.size.x)
- self._term.write_yx(YX(self._prompt.start_y, 0), INPUT_PROMPT)
-
- def _draw_log(self) -> None:
- for i, line in enumerate(self._log.wrapped):
- self._term.write_yx(YX(i, 0), line)
-
class SocketRecvLoop(Loop):
'Loop receiving and translating socket messages towards main loop.'