fn pty_reader_loop(
reader: Box<dyn Read + Send>,
tx: Sender<LineEvent>,
idle_tx: Sender<()>,
idle_timeout: Duration,
)Expand description
PTY reader loop: drains bytes from the master, strips DSR / ANSI control sequences, and forwards line-split chunks to the publisher.
Uses a thread-bridge + recv_timeout to add a quiet-window flush
identical to stream_reader’s tokio::time::timeout approach, but
for the blocking sync I/O that the PTY master reader requires.
P1a — collapse_cr: called on the pending accumulator after
each PTY read (after strip_ansi), collapsing mid-buffer lone-\r
overwrites (trailing-\r convention, e.g. "frame\r") and embedded
multi-frame chunks (e.g. printf 'f1\rf2\rfinal\n'). Previously the
PTY path passed \r bytes intact and relied on spawn_publisher_loop’s
pending_cr_line slot; that slot only fires per-LineEvent so embedded
\rs in a single write survived uncollapsed.
P1b — leading-\r spinner collapse: throttled spinners (npm,
cargo, ora, tqdm at ~80-100 ms/frame, above the 50 ms quiet window)
arrive as separate reads. When the quiet window expires and pending
starts with \r, the frame is stashed in a pending_cr_override slot
rather than flushed. The next read prepends it so collapse_cr
overwrites it with the new frame. The slot is flushed when a
\n-terminated line arrives or at EOF.
P2a — FLUSH_BYTES guard: flushed unconditionally when accumulated
size exceeds FLUSH_BYTES, preventing unbounded accumulation from a
trailing-\r spinner that never emits \n.