putzen_cli/
decider.rs

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