Prompts¶
rich::prompt asks
the user a question on the terminal, validates the answer, and asks again
until it gets a valid one.
| Type | Returns | Accepts |
|---|---|---|
Prompt |
String |
any text, or one of a list of choices |
Confirm |
bool |
y or n, any case |
IntPrompt |
i64 |
a whole number |
FloatPrompt |
f64 |
a number |
The prompts are not re-exported at the crate root:
use rich::prompt::{Confirm, FloatPrompt, IntPrompt, Prompt, ScriptedInput};
use rich::{Console, Text};
Asking¶
fn interactive() -> std::io::Result<()> {
let console = Console::new();
let name = Prompt::new("What is your [bold]name[/]").ask(&console, Some("World"))?;
let colour = Prompt::new("Favourite colour")
.choices(["red", "green", "blue"])
.case_sensitive(false)
.ask(&console, None)?;
let age = IntPrompt::new("Age").ask(&console, None)?;
let ok = Confirm::new("Continue?").ask(&console, Some(true))?;
console.print_str(&format!("{name} likes {colour}, is {age}, continue={ok}"));
Ok(())
}
ask(&console, default)writes the question, reads a line from standard input, and returnsstd::io::Result<T>. An empty answer returns the default, when there is one.- End of input (stdin closed,
Ctrl-D) returns the default — or the type's zero value ("",false,0) when there is none — instead of looping. - An invalid answer prints a message and asks again.
This page has no screenshot of ask itself — it waits for a keyboard.
The pictures below show the same questions rendered through the API that
ask uses.
What the user sees¶
The question is console markup, followed by the choices in
prompt.choices style, the default in prompt.default style, and :.
make_prompt returns that line as a Text without asking anything:
fn questions(console: &Console) {
// make_prompt renders a question exactly as ask() prints it.
console.print(&Prompt::new("What is your [bold]name[/]").make_prompt(console, Some("World")));
console.print(
&Prompt::new("Favourite colour")
.choices(["red", "green", "blue"])
.make_prompt(console, None),
);
console.print(&IntPrompt::new("Age").make_prompt(console, Some(30)));
console.print(&Confirm::new("Continue?").make_prompt(console, Some(true)));
console.print(
&Prompt::new("Password")
.choices(["hunter2"])
.show_choices(false)
.show_default(false)
.make_prompt(console, Some("hunter2")),
);
}
| Option | On | Effect |
|---|---|---|
choices([...]) |
Prompt |
only these answers are accepted; shown as [a/b/c] |
case_sensitive(false) |
Prompt |
match choices in any case; returns the choice as spelled in the list |
show_choices(false) |
Prompt, Confirm |
hide [a/b/c] but still enforce it |
show_default(false) |
all | hide (default) but still use it |
A rejected answer is reported in the prompt.invalid or
prompt.invalid.choice style, and the question is asked again:
Without a keyboard¶
Every ask has an ask_from twin that reads from an
InputSource
instead of stdin. ScriptedInput replays a list of lines, so the whole loop —
defaults, rejections, re-asking — runs in a test:
fn scripted() {
let console = Console::new();
// ScriptedInput feeds canned lines instead of reading the keyboard.
let mut input = ScriptedInput::new(["", "purple", "GREEN"]);
let name = Prompt::new("Name")
.ask_from(&console, &mut input, Some("World"))
.unwrap();
assert_eq!(name, "World"); // empty answer → the default
// "purple" is rejected, the question is asked again, "GREEN" matches.
let colour = Prompt::new("Colour")
.choices(["red", "green", "blue"])
.case_sensitive(false)
.ask_from(&console, &mut input, None)
.unwrap();
assert_eq!(colour, "green"); // the choice as spelled in the list
let mut input = ScriptedInput::new(["forty", "42", "y", "3.5"]);
assert_eq!(
IntPrompt::new("Age")
.ask_from(&console, &mut input, None)
.unwrap(),
42
);
assert!(Confirm::new("Sure?")
.ask_from(&console, &mut input, None)
.unwrap());
assert_eq!(
FloatPrompt::new("Ratio")
.ask_from(&console, &mut input, None)
.unwrap(),
3.5
);
}
Implement InputSource (one method, read_line) to read from anything else:
a socket, a GUI field, a file of answers.
To test only the validation, call process_response, which does no I/O at all:
fn validation() {
// The validation step on its own: no I/O at all.
assert_eq!(IntPrompt::new("n").process_response(" 7 "), Ok(7));
let error = IntPrompt::new("n").process_response("seven").unwrap_err();
assert_eq!(
error.0,
"[prompt.invalid]Please enter a valid integer number"
);
assert_eq!(Confirm::new("ok?").process_response("Y"), Ok(true));
}
Gotchas¶
- No hidden input. Upstream's
password=True(no echo) is not ported; read secrets with a crate such asrpassword. IntPromptisi64,FloatPromptisf64. Convert and range-check after asking; there is no custom validator hook.
See also¶
- Console and printing — the console a prompt writes to
- Text and style — restyle
prompt.*names in a theme - API:
prompt·Prompt·Confirm·IntPrompt·ScriptedInput