1use dialoguer::theme::ColorfulTheme;
2use dialoguer::Confirm;
3use std::io::Result;
4
5#[derive(Clone, Copy)]
6pub enum Decision {
7 Yes,
8 No,
9 Quit,
10}
11
12#[derive(Clone, Copy, Default)]
13pub struct DecisionContext {
14 pub is_dry_run: bool,
15 pub yes_to_all: bool,
16}
17
18pub trait Decide {
19 fn obtain_decision(
20 &mut self,
21 ctx: &DecisionContext,
22 question: impl AsRef<str>,
23 ) -> Result<Decision>;
24}
25
26#[derive(Default)]
27pub struct NiceInteractiveDecider {
28 decision_memory: Option<Decision>,
29}
30
31impl Decide for NiceInteractiveDecider {
32 fn obtain_decision(
33 &mut self,
34 ctx: &DecisionContext,
35 question: impl AsRef<str>,
36 ) -> Result<Decision> {
37 let suffix = if ctx.is_dry_run { " [dry-run]" } else { "" };
38 Ok(self.decision_memory.as_ref().copied().unwrap_or_else(|| {
39 if ctx.yes_to_all {
40 println!(" {}{suffix} [yes by -y arg]", question.as_ref());
41 Decision::Yes
42 } else {
43 Confirm::with_theme(&ColorfulTheme::default())
44 .with_prompt(format!("{}{suffix}", question.as_ref()))
45 .default(false)
46 .show_default(true)
47 .wait_for_newline(false)
48 .interact_opt()
49 .unwrap()
50 .map(|x| if x { Decision::Yes } else { Decision::No })
51 .unwrap_or(Decision::Quit)
52 }
53 }))
54 }
55}