1use crate::styles::{paint, ACCENT, DIM, WHITE};
4use std::io::Write;
5
6use super::core::{Frame, Key, Prompt, RenderCtx, Step};
7use super::error::{PromptError, Result};
8use super::theme;
9
10pub struct ConfirmPrompt {
12 label: String,
13 default: Option<bool>,
14 value: bool,
15}
16
17pub fn confirm(label: impl Into<String>) -> ConfirmPrompt {
26 ConfirmPrompt {
27 label: label.into(),
28 default: None,
29 value: true,
30 }
31}
32
33impl ConfirmPrompt {
34 pub fn default(mut self, v: bool) -> Self {
37 self.default = Some(v);
38 self.value = v;
39 self
40 }
41
42 pub fn run(self) -> Result<bool> {
44 super::core::run(self)
45 }
46}
47
48impl Prompt for ConfirmPrompt {
49 type Output = bool;
50
51 fn handle(&mut self, key: Key) -> Step<bool> {
52 match key {
53 Key::Left | Key::Right => {
54 self.value = !self.value;
55 Step::Continue
56 }
57 Key::Char('y') | Key::Char('Y') => Step::Submit(true),
58 Key::Char('n') | Key::Char('N') => Step::Submit(false),
59 Key::Enter => Step::Submit(self.value),
60 Key::Escape | Key::Interrupt => Step::Cancel,
61 _ => Step::Continue,
62 }
63 }
64
65 fn render(&self, _ctx: RenderCtx) -> Frame {
66 vec![
67 theme::label(&self.label),
68 theme::confirm_line(self.value),
69 theme::frame_bot(None),
70 ]
71 }
72
73 fn render_answered(&self, value: &bool) -> Frame {
74 theme::answered(&self.label, if *value { "Yes" } else { "No" })
75 .split("\r\n")
76 .map(String::from)
77 .collect()
78 }
79
80 fn run_fallback(self) -> Result<bool> {
81 let hint = match self.default {
82 Some(true) => "Y/n",
83 Some(false) => "y/N",
84 None => "y/n",
85 };
86 eprint!(
87 "{} {} [{}]: ",
88 paint(ACCENT, "◆"),
89 paint(WHITE, &self.label),
90 paint(DIM, hint)
91 );
92 std::io::stderr().flush().map_err(PromptError::Io)?;
93 loop {
94 let line = super::engine::fallback::read_line_raw()?;
95 match line.to_lowercase().as_str() {
96 "y" | "yes" => return Ok(true),
97 "n" | "no" => return Ok(false),
98 "" if self.default.is_some() => return Ok(self.default.unwrap()),
99 _ => {
100 eprint!(" Please enter y or n: ");
101 std::io::stderr().flush().map_err(PromptError::Io)?;
102 }
103 }
104 }
105 }
106}