@contextmanager
def context(self, q_to_main: EventQueue) -> Generator:
'Combine multiple contexts into one.'
- signal(SIGWINCH, lambda *_: q_to_main.eput('SIGWINCH'))
+ signal(SIGWINCH, lambda *_: q_to_main.eput('SET_SCREEN'))
self._blessed = BlessedTerminal()
with (self._blessed.raw(),
self._blessed.fullscreen(),
'Defines most basic TUI object API.'
@abstractmethod
- def set_geometry(self, measurements: tuple[int | YX, ...]) -> None:
+ def set_geometry(self, measurements: YX) -> None:
'Update widget\'s measurements, re-generate content where necessary.'
@abstractmethod
self._input_buffer = ''
self._history_idx = 0
- def set_geometry(self, measurements: tuple[int | YX, ...]) -> None:
- assert len(measurements) == 1
- assert isinstance(measurements[0], int)
+ def set_geometry(self, measurements: YX) -> None:
self._start_y = measurements[0]
def append(self, to_append: str) -> None:
self.draw()
def draw(self) -> None:
- self._write_yx(YX(self._start_y, len(INPUT_PROMPT)),
- f'{self._input_buffer}_')
+ self._write_yx(YX(self._start_y, 0),
+ f'{INPUT_PROMPT} {self._input_buffer}_')
def _scroll(self, up: bool = True) -> None:
if up and -(self._history_idx) < len(self._history):
self._wrapped += [(idx_original, line) for line in wrapped_lines]
return len(wrapped_lines)
- def set_geometry(self, measurements: tuple[int | YX, ...]) -> None:
- assert len(measurements) == 1
- assert isinstance(measurements[0], YX)
- self._view_size = measurements[0]
+ def set_geometry(self, measurements: YX) -> None:
+ self._view_size = measurements
self._y_pgscroll = self._view_size.y // 2
self._wrapped.clear()
self._wrapped += [(None, '')] * self._view_size.y
class Window(Widget):
'Collects a log and a prompt meant for the same content stream.'
+ _y_separator: int
def __init__(self, term: Terminal) -> None:
self._term = term
self.log = LogWidget(self._term.wrap, self._term.write_yx)
self.prompt = PromptWidget(self._term.write_yx)
+ if hasattr(self._term, 'size'):
+ self.set_geometry()
- def set_geometry(self, measurements: tuple[int | YX, ...]) -> None:
- assert len(measurements) == 2
- assert isinstance(measurements[0], int)
- assert isinstance(measurements[1], int)
- log_height = measurements[0]
- start_y_prompt = measurements[1]
- self.log.set_geometry((YX(log_height, self._term.size.x),))
- self.prompt.set_geometry((start_y_prompt,))
+ def set_geometry(self, _=None) -> None:
+ assert _ is None
+ self._y_separator = self._term.size.y - 2
+ self.log.set_geometry(YX(self._y_separator, self._term.size.x))
+ self.prompt.set_geometry(YX(self._term.size.y - 1, self._term.size.x))
def draw(self) -> None:
+ self._term.clear()
self.log.draw()
+ self._term.write_yx(YX(self._y_separator, 0), '=' * self._term.size.x)
self.prompt.draw()
self._windows = [Window(self._term)]
self._conn_windows: list[Window] = []
self._window_idx = 0
- self._calc_and_draw_all()
- self._term.flush()
super().__init__(*args, **kwargs)
+ self.put(Event('SET_SCREEN'))
def _cmd_name_to_cmd(self, cmd_name: str) -> Optional[Callable]:
cmd_parent = self
def process_main(self, event: Event) -> bool:
if not super().process_main(event):
return False
- if event.type_ == 'CONNECTION_WINDOW':
+ if event.type_ == 'SET_SCREEN':
+ self._term.calc_geometry()
+ for window in self._windows:
+ window.set_geometry()
+ self.window.draw()
+ elif event.type_ == 'CONNECTION_WINDOW':
conn_win = Window(self._term)
- conn_win.set_geometry((self._y_separator, self._y_prompt))
self._windows += [conn_win]
self._conn_windows += [conn_win]
elif event.type_ == 'ALERT':
cmd(*event.payload[1:])
elif event.type_ == 'INPUT_CHAR':
self.window.prompt.append(event.payload)
- elif event.type_ == 'SIGWINCH':
- self._calc_and_draw_all()
# elif event.type_ == 'DEBUG':
# from traceback import format_exception
# for line in '\n'.join(format_exception(event.payload)
'Currently selected Window.'
return self._windows[self._window_idx]
- def _calc_and_draw_all(self) -> None:
- self._term.clear()
- self._term.calc_geometry()
- self._y_prompt = self._term.size.y - 1
- self._y_separator = self._term.size.y - 2
- self._term.write_yx(YX(self._y_separator, 0), '=' * self._term.size.x)
- self._term.write_yx(YX(self._y_prompt, 0), INPUT_PROMPT)
- for window in self._windows:
- window.set_geometry((self._y_separator, self._y_prompt))
- self.window.draw()
-
def cmd__connect(self,
hostname: str,
username: str,