size: YX
tui: 'TuiLoop'
_blessed: BlessedTerminal
+ _cursor_yx_: YX
@contextmanager
def context(self, q_to_main: EventQueue) -> Generator:
self._blessed.fullscreen(),
self._blessed.hidden_cursor(),
KeyboardLoop(q_to_main, self.get_keypresses())):
+ self._cursor_yx = YX(0, 0)
with TuiLoop(self, q_to_main) as self.tui:
yield self
+ @property
+ def _cursor_yx(self) -> YX:
+ return self._cursor_yx_
+
+ @_cursor_yx.setter
+ def _cursor_yx(self, yx: YX) -> None:
+ print(self._blessed.move_yx(yx.y, yx.x), end='')
+ self._cursor_yx_ = yx
+
def calc_geometry(self) -> None:
'(Re-)calculate .size..'
self.size = YX(self._blessed.height, self._blessed.width)
return self._blessed.wrap(line, width=self.size.x,
subsequent_indent=' '*4)
- def write_yx(self, offset: YX, msg: str) -> None:
- 'Starting at offset, write line with msg, padded at end with spaces.'
- print(self._blessed.move_yx(offset.y, offset.x), end='')
- # ._blessed.length can slow down things notably, only use where needed
- len_with_offset = offset.x + (len(msg) if msg.isascii()
- else self._blessed.length(msg))
- if len_with_offset > self.size.x:
- print(self._blessed.truncate(msg, self.size.x - offset.x), end='')
- else:
- len_padding = self.size.x - len_with_offset
- print(msg + (' ' * len_padding), end='')
+ def write(self,
+ msg: str = '',
+ start_y: Optional[int] = None,
+ attribute: Optional[str] = None,
+ padding: bool = True
+ ) -> None:
+ 'Print to terminal, with position, padding to line end, attributes.'
+ if start_y:
+ self._cursor_yx = YX(start_y, 0)
+ # ._blessed.length can slow down things notably: only use where needed!
+ end_x = self._cursor_yx.x + (len(msg) if msg.isascii()
+ else self._blessed.length(msg))
+ len_padding = self.size.x - end_x
+ if len_padding < 0:
+ msg = self._blessed.truncate(msg, self.size.x - self._cursor_yx.x)
+ elif padding:
+ msg += ' ' * len_padding
+ end_x = self.size.x
+ if attribute:
+ msg = getattr(self._blessed, attribute)(msg)
+ print(msg, end='')
+ self._cursor_yx = YX(self._cursor_yx.y, end_x)
def get_keypresses(self) -> Iterator[str]:
'''Loop through keypresses from terminal, collect what blessed ignores.
'Defines some API shared between PromptWidget and LogWidget.'
_history_idx: int
- def __init__(self, write_yx: Callable[[YX, str], None]) -> None:
- self._write_yx = write_yx
+ def __init__(self, write: Callable[..., None], *args, **kwargs) -> None:
+ super().__init__(*args, **kwargs)
+ self._write = write
self._history: list[str] = []
@abstractmethod
break
offset += len_too_much
prompt = f'<{offset}|{prompt_template}…'
- self._write_yx(YX(self._y, 0), to_write)
+ self._write(to_write, self._y)
def _scroll(self, up: bool = True) -> None:
if up and -(self._history_idx) < len(self._history):
else:
to_write += [self._wrapped[self._wrapped_idx][1]]
for i, line in enumerate(to_write):
- self._write_yx(YX(i, 0), line)
+ self._write(line, i)
def _scroll(self, up: bool = True) -> None:
if up:
def __init__(self, idx: int, term: Terminal) -> None:
self.idx = idx
self._term = term
- self.log = LogWidget(self._term.wrap, self._term.write_yx)
- self.prompt = PromptWidget(self._term.write_yx)
+ self.log = LogWidget(self._term.wrap, self._term.write)
+ self.prompt = PromptWidget(self._term.write)
if hasattr(self._term, 'size'):
self.set_geometry()
status_line = idx_box + '=' * (self._term.size.x - len(idx_box))
self._term.clear()
self.log.draw()
- self._term.write_yx(YX(self._y_status, 0), status_line)
+ self._term.write(status_line, self._y_status)
self.prompt.draw()
def cmd__paste(self) -> None:
'Write OSC 52 ? sequence to get encoded clipboard paste into stdin.'
- self._term.write_yx(YX(self._y_status, 0), f'\033{OSC_52_PREFIX}?\007')
+ self._term.write(f'\033{OSC_52_PREFIX}?\007', self._y_status)
self.draw()