winbrew_ui/
interact.rs

1use super::Ui;
2use anyhow::{Result, bail};
3use dialoguer::{Confirm, Input, Select, theme::ColorfulTheme};
4use std::io::Write;
5
6impl<W: Write> Ui<W> {
7    pub fn page_title(&mut self, title: &str) {
8        let _ = title;
9    }
10
11    pub fn confirm(&mut self, message: &str, default: bool) -> Result<bool> {
12        if self.default_yes {
13            return Ok(true);
14        }
15
16        Confirm::with_theme(&ColorfulTheme::default())
17            .with_prompt(message)
18            .default(default)
19            .interact()
20            .map_err(Into::into)
21    }
22
23    pub fn prompt_text(&mut self, message: &str, default: Option<&str>) -> Result<String> {
24        let theme = ColorfulTheme::default();
25        let input = Input::<String>::with_theme(&theme).with_prompt(message);
26        let input = if let Some(default) = default {
27            input.default(default.to_string())
28        } else {
29            input
30        };
31
32        input.interact_text().map_err(Into::into)
33    }
34
35    pub fn prompt_number(&mut self, message: &str, max: usize) -> Result<usize> {
36        if max == 0 {
37            bail!("cannot prompt for selection from an empty list");
38        }
39
40        loop {
41            let value = self.prompt_text(message, None)?;
42            match value.trim().parse::<usize>() {
43                Ok(number) if (1..=max).contains(&number) => return Ok(number - 1),
44                _ => self.warn(format!("Enter a number between 1 and {max}.")),
45            }
46        }
47    }
48
49    pub fn select_index(&mut self, message: &str, items: &[String]) -> Result<usize> {
50        if items.is_empty() {
51            bail!("cannot prompt for selection from an empty list");
52        }
53
54        Select::with_theme(&ColorfulTheme::default())
55            .with_prompt(message)
56            .items(items)
57            .default(0)
58            .interact()
59            .map_err(Into::into)
60    }
61}