feat: add reliable trigger and worker message blocks
Some checks failed
tamq-ci / test (push) Failing after 6s

Assistant: codex
Assistant-Model: gpt-5.6-sol
Assistant-Session: 01a03397-4d51-7fd1-8ff2-946eb22ea2bc
This commit is contained in:
tegwick 2026-08-25 23:22:39 +02:00
parent 72f22a13f7
commit 17b6bd7ae7
25 changed files with 588 additions and 67 deletions

View file

@ -60,6 +60,10 @@ class TerminalOutputObserver:
self.text: list[str] = []
self.state = "normal"
self.string_kind = ""
self.csi: list[str] = []
self.cursor_row: int | None = None
self.after_cr = False
self.empty_cr = False
self.operator_lines: deque[tuple[str, float]] = deque(maxlen=32)
self.last_redraw: str | None = None
@ -72,10 +76,12 @@ class TerminalOutputObserver:
self.operator_lines.popleft()
return any(candidate == line for candidate, _ in self.operator_lines)
def _emit(self, *, redraw: bool = False) -> None:
def _emit(self, *, redraw: bool = False, allow_empty: bool = False) -> None:
line = "".join(self.text)
self.text.clear()
if not line:
if allow_empty:
self.on_line("")
return
if self._is_recent_operator_echo(line):
return
@ -84,21 +90,62 @@ class TerminalOutputObserver:
self.last_redraw = line if redraw else None
self.on_line(line)
def _move_cursor(self, final: str) -> None:
parameters = "".join(self.csi)
previous = self.cursor_row
new_row: int | None = None
try:
first = int((parameters.split(";", 1)[0] or "1"))
except ValueError:
first = 1
if final in "Hf":
new_row = first
elif final == "d":
new_row = first
elif final in "BE" and previous is not None:
new_row = previous + first
elif final in "AF" and previous is not None:
new_row = max(1, previous - first)
if (
previous is not None
and new_row is not None
and new_row > previous + 1
):
self.on_line("")
if new_row is not None:
self.cursor_row = new_row
def feed(self, data: bytes) -> None:
for character in self.decoder.decode(data):
if self.state == "normal":
if character == "\x1b":
self.after_cr = False
self.state = "esc"
elif character in "\r\n":
self._emit(redraw=character == "\r")
elif character == "\r":
self.empty_cr = not self.text
self._emit(redraw=True)
self.after_cr = True
elif character == "\n":
if self.after_cr:
if self.empty_cr:
self._emit(allow_empty=True)
else:
self._emit(allow_empty=True)
self.after_cr = False
self.empty_cr = False
if self.cursor_row is not None:
self.cursor_row += 1
elif character in ("\b", "\x7f"):
self.after_cr = False
if self.text:
self.text.pop()
elif character == "\t" or character >= " ":
self.after_cr = False
self.text.append(character)
elif self.state == "esc":
if character == "[":
self.state = "csi"
self.csi.clear()
elif character in "]P_^":
self.state = "string"
self.string_kind = character
@ -108,7 +155,10 @@ class TerminalOutputObserver:
if "@" <= character <= "~":
if character in self._CURSOR_BOUNDARIES:
self._emit(redraw=True)
self._move_cursor(character)
self.state = "normal"
else:
self.csi.append(character)
elif self.state == "string":
if character == "\x07" and self.string_kind == "]":
self.state = "normal"
@ -248,6 +298,9 @@ class PtyTap:
if self.ready_file is not None:
self.ready_file.unlink(missing_ok=True)
self.output_observer.flush()
flush_worker = getattr(self.broker, "flush_worker_message", None)
if flush_worker is not None:
flush_worker()
for signum, handler in saved_handlers.items():
signal.signal(signum, handler)
if saved_terminal is not None: