putzen_cli/
decider.rs

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}