Skip to main content

Module live

Module live 

Source
Expand description

One check, one block — and while it runs, one line: per-check output capture plus a live progress region for the concurrent stage.

Twenty checks used to print straight to inherited stdio from their own threads, so two failing linters shuffled their lines together and the reader un-shuffled them by hand — the dispatcher’s roll-up existed partly to apologise for it. Now every check writes into its own slot, and a completed check’s output reaches stdout as ONE locked write: contiguous, whatever the other nineteen were doing.

Three writers feed a slot:

  1. The check’s own thread, through say — which is what common::ok/fail/warn call. A thread with no slot installed (commit-msg, amont install, the dispatcher itself) prints directly, exactly as before; nothing outside a stage changes.
  2. A captured child’s reader threads, through Stage::append_raw — they are not the check’s thread, so the thread-local cannot carry the routing; the Arc is captured before the spawn instead.
  3. Nobody else. The dispatcher’s own lines (skips, pins, the roll-up) happen strictly before or after the fan-out and stay direct.

Order across checks is COMPLETION order — deterministic per block, not per stage, which is the same nondeterminism the interleaved version had without the shuffling. amont.progress false switches the whole mechanism off and restores raw streaming for anyone who wants to watch a tool write in real time.

§The region

When stderr is a real terminal (watching) the stage also paints a live region UNDER the finished blocks: one line per running check — braille spinner, name, elapsed — repainted every 80ms by a ticker thread, shrinking as checks finish, gone without a trace when the stage ends. Blocks go to stdout, the region to stderr; both feed one tty, and every write to either happens under the same Stage::out lock, so a block never tears a repaint in half. Piped, redirected, TERM=dumb, or CI: watching is false, no ticker starts, and the region costs nothing — which is also why the test suite (piped stdio throughout) exercises capture but never the paint.

Structs§

FinishOnDrop
Emits slot idx’s block when dropped — however the check’s closure exits, a panic included: the partial output of a check that died still reaches the reader, above the dead-check verdict the runner fills in.
SinkGuard
Uninstalls the thread’s sink on drop, whatever path the check took out.
Stage
A running stage: the slots, and the one lock every terminal write inside the stage goes through.

Functions§

current_sink
The sink installed on THIS thread, if any — how a child-capture helper on the check’s own thread learns where the reader threads should append.
enabled
Whether the capture mechanism is on at all. amont.progress false is the escape hatch back to raw streaming — one knob, read once.
say
One line of check output, wherever it should go.
watching
Is anyone watching? True only when stderr is a real terminal that speaks VT: not piped, not redirected, not TERM=dumb — and on Windows only with TERM actually set, because bare conhost may not interpret the cursor codes the region depends on. This is the paint gate; capture (enabled) does not consult it.