dot_over/ui/
style.rs

1use std::fmt;
2
3use clap::builder::styling;
4use console::{style, Style, StyledObject};
5use dialoguer::theme::Theme;
6use once_cell::sync::Lazy;
7
8pub static TICK_CHARS_BRAILLE_4_6_DOWN: Lazy<String> = Lazy::new(|| String::from("⠶⢲⣰⣤⣆⡖"));
9pub static TICK_CHARS_BRAILLE_4_6_UP: Lazy<String> = Lazy::new(|| String::from("⠛⠹⠼⠶⠧⠏"));
10pub static BRAILLE_6: Lazy<String> = Lazy::new(|| String::from("⠿"));
11
12pub static THIN_PROGRESS: Lazy<String> = Lazy::new(|| String::from("━>-"));
13pub static THIN_DUAL_PROGRESS: Lazy<String> = Lazy::new(|| String::from("=>-"));
14
15pub static DOTS_4: Lazy<String> = Lazy::new(|| String::from("::"));
16
17// pub static ref SPINNER: ProgressStyle = ProgressStyle::default_spinner()
18//     .template("{prefix:.bold.dim} {spinner.green} {wide_msg}")
19//     .tick_chars("⠁⠂⠄⡀⢀⠠⠐⠈ ");
20// }
21
22pub fn white<D>(value: D) -> StyledObject<D> {
23    style(value).white()
24}
25
26pub fn white_b<D>(value: D) -> StyledObject<D> {
27    white(value).bold()
28}
29
30pub fn white_bi<D>(value: D) -> StyledObject<D> {
31    white_b(value).italic()
32}
33
34pub fn cyan<D>(value: D) -> StyledObject<D> {
35    style(value).cyan()
36}
37
38pub fn yellow<D>(value: D) -> StyledObject<D> {
39    style(value).yellow()
40}
41
42pub struct DialogTheme {
43    /// The style for default values
44    pub defaults_style: Style,
45    /// The style for prompt
46    pub prompt_style: Style,
47    /// Prompt prefix value and style
48    pub prompt_prefix: StyledObject<String>,
49    /// Prompt suffix value and style
50    pub prompt_suffix: StyledObject<String>,
51    /// Prompt on success prefix value and style
52    pub success_prefix: StyledObject<String>,
53    /// Prompt on success suffix value and style
54    pub success_suffix: StyledObject<String>,
55    /// Error prefix value and style
56    pub error_prefix: StyledObject<String>,
57    /// The style for error message
58    pub error_style: Style,
59    /// The style for hints
60    pub hint_style: Style,
61    /// The style for values on prompt success
62    pub values_style: Style,
63}
64
65impl Default for DialogTheme {
66    fn default() -> DialogTheme {
67        DialogTheme {
68            defaults_style: Style::new().for_stderr().cyan(),
69            prompt_style: Style::new().for_stderr().bold(),
70            prompt_prefix: style("?".to_string()).for_stderr().yellow(),
71            prompt_suffix: style("›".to_string()).for_stderr().black().bright(),
72            success_prefix: style("✔".to_string()).for_stderr().green(),
73            success_suffix: style("·".to_string()).for_stderr().black().bright(),
74            error_prefix: style("✘".to_string()).for_stderr().red(),
75            error_style: Style::new().for_stderr().red(),
76            hint_style: Style::new().for_stderr().black().bright(),
77            values_style: Style::new().for_stderr().green(),
78        }
79    }
80}
81
82impl Theme for DialogTheme {
83    /// Formats a confirm prompt.
84    fn format_confirm_prompt(
85        &self,
86        f: &mut dyn fmt::Write,
87        prompt: &str,
88        default: Option<bool>,
89    ) -> fmt::Result {
90        if !prompt.is_empty() {
91            write!(
92                f,
93                "{} {} ",
94                &self.prompt_prefix,
95                self.prompt_style.apply_to(prompt)
96            )?;
97        }
98
99        match default {
100            None => write!(
101                f,
102                "{} {}",
103                self.hint_style.apply_to("(y/n)"),
104                &self.prompt_suffix
105            ),
106            Some(true) => write!(
107                f,
108                "{} {} {}",
109                self.hint_style.apply_to("(y/n)"),
110                &self.prompt_suffix,
111                self.defaults_style.apply_to("yes")
112            ),
113            Some(false) => write!(
114                f,
115                "{} {} {}",
116                self.hint_style.apply_to("(y/n)"),
117                &self.prompt_suffix,
118                self.defaults_style.apply_to("no")
119            ),
120        }
121    }
122
123    /// Formats a confirm prompt after selection.
124    fn format_confirm_prompt_selection(
125        &self,
126        f: &mut dyn fmt::Write,
127        prompt: &str,
128        selection: Option<bool>,
129    ) -> fmt::Result {
130        let selection = selection.map(|b| if b { "yes" } else { "no" });
131        let prefix = match selection {
132            Some("yes") => &self.success_prefix,
133            _ => &self.error_prefix,
134        };
135        let style = match selection {
136            Some("yes") => &self.values_style,
137            _ => &self.error_style,
138        };
139
140        if !prompt.is_empty() {
141            write!(f, "{} {} ", prefix, self.prompt_style.apply_to(prompt))?;
142        }
143
144        match selection {
145            Some(selection) => {
146                write!(f, "{}", style.apply_to(selection))
147            }
148            None => {
149                write!(f, "{}", &self.success_suffix)
150            }
151        }
152    }
153}
154
155pub fn clap_styles() -> styling::Styles {
156    styling::Styles::styled()
157        .header(styling::AnsiColor::Green.on_default() | styling::Effects::BOLD)
158        .usage(styling::AnsiColor::Green.on_default() | styling::Effects::BOLD)
159        .literal(styling::AnsiColor::Blue.on_default() | styling::Effects::BOLD)
160        .placeholder(styling::AnsiColor::Cyan.on_default())
161}