Skip to main content

max / quasi

Let the host say something no handler knows about A route that failed, an address that will not open, a device that is not there. quasi-tui has had `say` since its runtime existed and this crate shipped without it, which leaves a windowed host writing to stderr: nowhere at all for a GUI. Found wiring audiofiles' described settings panel into the app, which is the first consumer that had to report a RouteError to a user.
Co-Authored-By
Claude Opus 5 (1M context) <noreply@anthropic.com>
Author: Max Johnson <me@maxj.phd> · 2026-08-13 21:30 UTC
Signed with PGP, not checked
Commit: 7a98331a5d03c5fd6bf3d3b8f250196ef981678d
Parent: 34f5145
2 files changed, +27 insertions, -0 deletions
@@ -167,6 +167,19 @@
167 167 }
168 168 }
169 169
170 + /// Put a message on the screen, from the host rather than from a route.
171 + ///
172 + /// The host has things to say that no handler knows about: a route that
173 + /// failed, an address it will not open, a device that is not there. Without
174 + /// this they go to stderr, which for a windowed app is nowhere at all.
175 + pub fn say(&mut self, text: impl Into<String>) {
176 + self.screen.notices.push(Node::Notice {
177 + kind: quasi_router::layout::Notice::Banner,
178 + tone: quasi_router::layout::Tone::Danger,
179 + text: text.into(),
180 + });
181 + }
182 +
170 183 /// Answer the question a control asked.
171 184 ///
172 185 /// Anything that is not yes is no, which is the safe way round for a prompt
@@ -372,3 +372,17 @@
372 372 let sent: Vec<&str> = params.get_all(Node::TICKED).collect();
373 373 assert_eq!(sent, ["1", "2"]);
374 374 }
375 +
376 + #[test]
377 + fn the_host_can_say_something_no_handler_knows_about() {
378 + // A route that failed has to land somewhere the user is looking. For a
379 + // windowed app stderr is nowhere.
380 + let mut runtime = Runtime::new(screen_of([Node::text("first")]));
381 + runtime.say("The library is not reachable.");
382 + assert!(
383 + runtime.screen().notices.iter().any(
384 + |node| matches!(node, Node::Notice { text, .. } if text.contains("not reachable"))
385 + ),
386 + "the host had nowhere to put it"
387 + );
388 + }