redraw_affected: Optional[Callable] = None
_lines_t: list[tuple[str, str]]
_colwidths: dict[str, int]
+ _idx_: int = 0
def __init__(self, path: Path, get_client: Callable, verbose: bool
) -> None:
def lines_t_from_file(path: Path, prefix='') -> list[tuple[str, str]]:
with path.open('r', encoding='utf8') as f:
- return [(f'{prefix}{idx + 1}', line.rstrip('\n'))
- for idx, line in enumerate(f.readlines())
- if line.rstrip()
- and not line.startswith(_MARK_COMMENT)]
+ return [(f'{prefix}{idx + 1}',
+ line.rstrip('\n') if line.rstrip() else _MARK_COMMENT)
+ for idx, line in enumerate(f.readlines())]
def insert(idx_str: str,
insert_args: tuple[str, ...],
else:
to_join += [_SEP_1.join(str(n + bumped_offset)
for n in cmd_arg)
- or ',']
+ or _SEP_1]
candidate[1] = _SEP_0.join(to_join)
try:
fragment: list[tuple[str, str]] = []
fragments_cutoff = -1
for idx, line_t in enumerate(self._lines_t[:] + [('', '')]):
+ if line_t[1].startswith(_MARK_COMMENT):
+ continue
if line_t[1].startswith(_MARK_FRAGMENT):
assert _SEP_0 in line_t[1], (idx, line_t)
if anchor:
if replacement_happened or idx == fragments_cutoff:
new_lines_t += [line_t]
continue
- cmd_name, remains = line_t[1].split(_SEP_0, maxsplit=1)
+ cmd_name, args = self._cmdname_and_args_from(line_t[1])
if cmd_name == _MARK_INSERT:
- new_lines_t += insert(
- line_t[0],
- self._args_for_cmd(cmd_name, remains),
- fragments)
+ new_lines_t += [('', f'# <{line_t[1]}>')]
+ new_lines_t += insert(line_t[0], args, fragments)
+ new_lines_t += [('', f'# </${_MARK_INSERT}>')]
replacement_happened = True
else:
new_lines_t += [line_t]
# NB: To start playback past fragments section, could move ._idx there;
# but .ensure_has_started can easier test unchangedness if by .idx==0.
self._lines_t = self._lines_t[fragments_cutoff + 1:]
- self._idx = 0
+
+ @property
+ def _idx(self) -> int:
+ return self._idx_
+
+ @_idx.setter
+ def _idx(self, val: int) -> None:
+ self._line_log_and_parse(*self._current_line)
+ self._idx_ = val
@staticmethod
def _args_for_cmd(cmd_name: str, remains: str) -> tuple[str, ...]:
@classmethod
def _cmdname_and_args_from(cls, line: str) -> tuple[str, tuple[str, ...]]:
+ if line.startswith(_MARK_COMMENT):
+ return '', tuple()
cmd_name, remains = line.split(_SEP_0, maxsplit=1)
return cmd_name, cls._args_for_cmd(cmd_name, remains)
def _current_line(self) -> tuple[str, str]:
return self._lines_t[self._idx]
- def _line_log_and_parse(self, idx_info: str, line: str
- ) -> tuple[str, tuple[str, ...]]:
+ def _line_log_and_parse(self, idx_info: str, line: str) -> None:
col_titles = ('line number(s)', 'command', 'arguments')
def args_verbose(args: tuple[str, ...]) -> str:
return ' '.join(f'[{arg}]' for arg in args)
+ def log_by_mode(to_print: str) -> None:
+ (print if self._verbose else self._print_on_fail.append)(to_print)
+
def print_padded(to_pad: tuple[str, ...], unpadded_end: str) -> None:
to_log = []
for idx, colname in enumerate(col_titles[:len(to_pad)]):
text = to_pad[idx]
to_log += [text + ' ' * (self._colwidths[colname] - len(text))]
to_log += [unpadded_end]
- if self._verbose:
- print(*to_log)
- else:
- self._print_on_fail += [' '.join(to_log)]
+ log_by_mode(' '.join(to_log))
if not hasattr(self, '_colwidths'):
self._colwidths: dict[str, int] = {}
for idx_str, line_ in self._lines_t:
cmd_name, args = self._cmdname_and_args_from(line_)
- for idx, value in enumerate((idx_str,
- cmd_name,
- args_verbose(args[:-1]))):
- title = col_titles[idx]
- to_cmp = [len(value), self._colwidths.get(title, 0)]
- if idx < len(col_titles) - 1:
- to_cmp += [len(title)]
- self._colwidths[title] = max(to_cmp)
+ if cmd_name:
+ for idx, value in enumerate((idx_str,
+ cmd_name,
+ args_verbose(args[:-1]))):
+ title = col_titles[idx]
+ to_cmp = [len(value), self._colwidths.get(title, 0)]
+ if idx < len(col_titles) - 1:
+ to_cmp += [len(title)]
+ self._colwidths[title] = max(to_cmp)
print_padded(to_pad=col_titles[:-1],
unpadded_end=col_titles[-1])
cmd_name, args = self._cmdname_and_args_from(line)
- items = (idx_info, cmd_name) + args
- print_padded(to_pad=items[:2] + (args_verbose(items[2:-1]),),
- unpadded_end=items[-1])
- return cmd_name, args
+ if cmd_name:
+ items = (idx_info, cmd_name) + args
+ print_padded(to_pad=items[:2] + (args_verbose(items[2:-1]),),
+ unpadded_end=items[-1])
+ else:
+ log_by_mode(' ' + line)
def ensure_has_started(self) -> None:
'Check if still at beginning, and if so, play till at next log line.'
if self._idx >= len(self._lines_t):
self._lines_t += [('', '> /quit'),
('', 'log 0 <..')]
- cmd_name, args = self._line_log_and_parse(*self._current_line)
+ cmd_name, args = self._cmdname_and_args_from(self._current_line[1])
if cmd_name == _MARK_PROMPT:
assert self.put_keypress is not None
if args[0] == 'raise_sigwinch':