1use core::fmt;
7
8use inquire::{Confirm, InquireError, Select, Text};
9use thiserror::Error;
10
11#[derive(Debug, Error)]
13pub enum PromptError {
14 #[error("cannot prompt text")]
16 Text(#[source] InquireError),
17 #[error("cannot prompt boolean")]
19 Bool(#[source] InquireError),
20 #[error("cannot prompt item from list")]
22 Item(#[source] InquireError),
23}
24
25pub type PromptResult<T> = Result<T, PromptError>;
27
28pub fn text<T: AsRef<str>>(prompt: T, default: Option<T>) -> PromptResult<String> {
30 let mut prompt = Text::new(prompt.as_ref());
31
32 if let Some(default) = default.as_ref() {
33 prompt = prompt.with_default(default.as_ref())
34 }
35
36 prompt.prompt().map_err(PromptError::Text)
37}
38
39pub fn some_text<T: AsRef<str>>(prompt: T, default: Option<T>) -> PromptResult<Option<String>> {
41 let mut prompt = Text::new(prompt.as_ref());
42
43 if let Some(default) = default.as_ref() {
44 prompt = prompt.with_default(default.as_ref())
45 }
46
47 prompt.prompt_skippable().map_err(PromptError::Text)
48}
49
50pub fn bool(prompt: impl AsRef<str>, default: bool) -> PromptResult<bool> {
52 Confirm::new(prompt.as_ref())
53 .with_default(default)
54 .prompt()
55 .map_err(PromptError::Bool)
56}
57
58pub fn item<T: fmt::Display + Eq>(
61 prompt: impl AsRef<str>,
62 items: impl IntoIterator<Item = T>,
63 default: Option<T>,
64) -> PromptResult<T> {
65 let items: Vec<_> = items.into_iter().collect();
66
67 let default = if let Some(default) = default.as_ref() {
68 items
69 .iter()
70 .enumerate()
71 .find_map(|(i, item)| if item == default { Some(i) } else { None })
72 } else {
73 None
74 };
75
76 let mut prompt = Select::new(prompt.as_ref(), items).without_filtering();
77
78 if let Some(default) = default.as_ref() {
79 prompt = prompt.with_starting_cursor(*default);
80 }
81
82 prompt.prompt().map_err(PromptError::Item)
83}