// The switchboard: a live, newest-first feed of generated signals, one line // each — sender ──SIG──▶ target — coloured by severity, with a right-hand // note for the source (kill/tgkill/kernel/…), the ×N coalesce count, and a // badge when the signal was lethal or ignored. Lethal deliveries get a faint // row tint so a kill jumps off the screen. Pure UI: it reads the `feed` // snapshot and nothing else. import { Box, Text } from "yeet:tui"; import { SEV_COLOR, isFatalBlow, sigName, syscallName, wasIgnored } from "@/lib/signals.js"; import { ago, clip, dur, ljust, rjust } from "@/lib/format.js"; import { fieldHits } from "@/lib/fuzzy.js"; import { filter } from "@/probes/sigwire.js"; const BRIGHT = "#e6f0ea"; const DIM = "#5f6f68"; const FAINT = "#3a4640"; const IGN = "#9a8a4a"; const CAUGHT = "#5fe08a"; const EINTR_C = "#ff8c1a"; // the "your syscall just got cancelled" orange const SEL = "#123f3a"; // selected-row background — a clearly-lit teal band const SEL_BAR = "#3ddc84"; // the bright cursor bar down the selected row's edge const GUTTER = "▌"; // left-edge marker cell (U+258C), lit only on the selection const MATCH_BG = "#5c4a1a"; // amber marker under chars matched by the fuzzy filter const TIME_W = 7; const EP_W = 22; // endpoint column (comm·pid) const WIRE_W = 15; // the wire + signal label + arrowhead // Render `text` in the given face, but with the characters at `hits` (a Set of // indices, or null) lit on the match-highlight background — so a fuzzy filter // shows exactly which characters it matched. No hits → one plain span. const hl = (text, hits, fg, bold) => { if (!hits || !hits.size) return {text}; const spans = []; let i = 0; while (i < text.length) { const on = hits.has(i); let j = i + 1; while (j < text.length && hits.has(j) === on) j++; const seg = text.slice(i, j); spans.push( on ? ( {seg} ) : ( {seg} ), ); i = j; } return spans; }; // comm·pid spans. Sender is right-justified so it hugs the wire; target is // left-justified so it trails the arrowhead. Target comm is bold — it's the // one you're usually hunting for. commHits/pidHits light matched chars. const endpoint = (comm, pid, { right, bold, commHits, pidHits }) => { const c = clip(comm || "?", 14); const pidDigits = `${pid}`; const pidStr = `·${pidDigits}`; const spans = [ {hl(c, commHits, BRIGHT, bold)}, {"·"}{hl(pidDigits, pidHits, DIM, false)}, ]; if (!right) return spans; const pad = Math.max(0, EP_W - c.length - pidStr.length); return [pad ? {" ".repeat(pad)} : null, ...spans]; }; // ──SIGNAME───▶ — dashes fill to a fixed width so the arrowhead (and the // target column after it) always land on the same column. const wire = (sig, sev, sigHits) => { const col = SEV_COLOR[sev]; const avail = WIRE_W - 3; // "──" + "▶" const name = clip(sigName(sig), avail); const dash = "─".repeat(Math.max(0, avail - name.length)); return ( {"──"} {hl(name, sigHits, col, true)} {dash} {"▶"} ); }; // The right-hand disposition tag: did the target catch it, let it hit the // default action, or ignore it — and, for a caught signal that has returned, // how long its handler ran. dispHits lights the matched chars of the word. const dispSpan = (r, dispHits) => { if (r.disp === "caught") return ( {" "}{hl("caught", dispHits, CAUGHT, false)} {r.durNs != null ? {` ${dur(r.durNs)}`} : null} ); if (r.disp === "ignored" || (!r.disp && wasIgnored(r.result))) return {" ⊘ "}{hl("ignored", r.disp ? dispHits : null, IGN, false)}; if (r.disp === "default") return {" "}{hl("default", dispHits, DIM, false)}; return null; }; // Did this signal interrupt a blocked syscall? EINTR is the headline — the // classic "my read() randomly failed" gremlin, made visible. const intrSpan = (r) => { if (r.eintr === 1) return {` ↯ EINTR ${syscallName(r.intrSyscall)}`}; if (r.eintr === 2) return {` ↺ restarted ${syscallName(r.intrSyscall)}`}; return null; }; function Row({ r, now, selected, hits }) { const col = SEV_COLOR[r.sev]; const fatalHit = isFatalBlow(r.sig, r.code, r.result); const tint = selected ? SEL : fatalHit ? "#ff2d5520" : undefined; // real deaths glow red const note = []; if (r.count > 1) note.push({` ×${r.count}`}); note.push({" "}{hl(r.src, hits?.src, DIM, false)}); note.push(intrSpan(r)); note.push(dispSpan(r, hits?.disp)); if (fatalHit) note.push({" ☠"}); return ( {selected ? GUTTER : " "} {`${rjust(ago((now - r.ts) / 1e9), TIME_W - 1)} `} {endpoint(r.sComm, r.sPid, { right: true, commHits: hits?.sComm, pidHits: hits?.sPid })} {wire(r.sig, r.sev, hits?.sig)} {endpoint(r.tComm, r.tPid, { bold: true, commHits: hits?.tComm, pidHits: hits?.tPid })} {note} ); } const Header = () => ( {" " + rjust("WHEN", TIME_W) + rjust("SENDER", EP_W) + ljust(" SIGNAL", WIRE_W) + ljust("TARGET", EP_W) + "NOTE"} ); export default function Feed({ view, rows, sel, filtered }) { return (
{() => { const v = view.get(); const si = sel ? sel.get() : -1; const list = v.rows.slice(0, Math.max(1, rows)); if (!list.length) { const q = filter.get(); const msg = q ? ` nothing matches “${q}” — Esc to clear the search` : filtered && filtered.get() ? " no interrupted syscalls yet — nothing has hit EINTR" : " waiting for signals…"; return {msg}; } const q = filter.get(); return list.map((r, i) => ); }} ); }