Map wizard errors to exit codes¶
Match on the three variants, and keep the catch-all¶
use rtb_tui::{Wizard, WizardError};
use std::process::ExitCode;
async fn run() -> ExitCode {
match wizard().run().await {
Ok(config) => {
write_config(&config);
ExitCode::SUCCESS
}
Err(WizardError::Cancelled) => {
eprintln!("cancelled — nothing was written");
ExitCode::from(1)
}
Err(WizardError::Interrupted) => ExitCode::from(130),
Err(err) => {
eprintln!("{err}");
ExitCode::from(2)
}
}
}
WizardError is #[non_exhaustive], so the final arm is required by
the compiler and not just good manners. Make it do something sensible —
a new variant in a later release will land there.
Say nothing extra on Ctrl+C¶
WizardError::Interrupted means the user pressed
Ctrl+C. They know what they did, and a shell
convention already covers it: exit 128 + SIGINT, which is 130.
Printing "interrupted" on top of the ^C the terminal already echoed
is noise.
Cancelled is different. That is Esc on the first step, or
a step returning StepOutcome::Back from there — a deliberate "no
thanks" rather than a signal. A one-line acknowledgement that says
whether anything was written is worth printing, because the user cannot
otherwise tell.
Keeping the two apart is the whole reason they are separate variants.
Report a step failure with the step name¶
WizardError::Step { step, message } carries the name the failing step
returned from WizardStep::name(), and its Display output already
includes both:
That name is the only handle you get on which step broke. If your step
names are "step1" and "step2", that is what the error will say, so
name them after what they ask for.
The original InquireError is not kept — only its message, already
stringified. There is no source() chain to walk and no way to match
on the underlying variant from outside. If a step needs to distinguish
one inquire failure from another, it has to do that inside prompt
before returning.
Do not treat cancellation as a failure to log¶
A cancelled wizard is a normal outcome. Logging it at error level, or
reporting it to telemetry as a crash, produces a dashboard full of
users who changed their minds. Both Cancelled and Interrupted
belong at info level if they belong anywhere.
Next¶
- Errors reference — every variant, its
Displayoutput and itsmiettediagnostic code. - Why escape means back — why Esc on the first step cancels rather than doing nothing.