1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
//! Output messages and prompts.

#![allow(missing_docs, clippy::module_name_repetitions)]

pub(crate) mod style {
    use console::Style;
    use once_cell::sync::Lazy;

    pub static MESSAGE: Lazy<Style> = Lazy::new(|| Style::new().green().bold());
    pub static ERROR: Lazy<Style> = Lazy::new(|| Style::new().bright().red().bold());
    pub static QUESTION: Lazy<Style> = Lazy::new(|| Style::new().yellow().bold());
}

pub mod prompt {
    use once_cell::sync::Lazy;

    use crate::print::style;

    type StyledStr<'a> = console::StyledObject<&'a str>;

    pub static CANCELED: Lazy<StyledStr> = Lazy::new(|| style::MESSAGE.apply_to("Canceled"));
    pub static PENDING: Lazy<StyledStr> = Lazy::new(|| style::MESSAGE.apply_to("Pending"));
    pub static RUNNING: Lazy<StyledStr> = Lazy::new(|| style::MESSAGE.apply_to("Running"));
    pub static INFO: Lazy<StyledStr> = Lazy::new(|| style::MESSAGE.apply_to("Info"));
    pub static ERROR: Lazy<StyledStr> = Lazy::new(|| style::ERROR.apply_to("Error"));
}

use std::fmt::{self, Display};

use console::{style, Style};
use dialoguer::theme::ColorfulTheme;

/// The right indentation to be applied on prompt prefixes.
static PROMPT_INDENT: usize = 9;

macro_rules! prompt_format {
    () => {
        "{:>indent$}"
    };
}

macro_rules! plain_format {
    () => {
        concat!(prompt_format!(), " {}")
    };
}

macro_rules! quoted_format {
    () => {
        concat!(prompt_format!(), " `{}`")
    };
}

/// Writes a message after the given prompt.
#[allow(clippy::missing_errors_doc)]
pub fn write(f: &mut fmt::Formatter, prompt: impl Display, msg: impl Display) -> fmt::Result {
    write!(f, plain_format!(), prompt, msg, indent = PROMPT_INDENT)
}

/// Prints out a message after the given prompt.
pub fn println(prompt: impl Display, msg: impl Display) {
    println!(
        plain_format!(),
        style::MESSAGE.apply_to(prompt),
        msg,
        indent = PROMPT_INDENT
    );
}

/// Prints out an error message.
pub fn println_err(msg: impl Display) {
    println!(
        plain_format!(),
        &*prompt::ERROR,
        msg,
        indent = PROMPT_INDENT
    );
}

/// Prints out a backtick-quoted message after the given prompt.
pub fn println_quoted(prompt: impl Display, msg: impl Display) {
    println!(
        quoted_format!(),
        style::MESSAGE.apply_to(prompt),
        msg,
        indent = PROMPT_INDENT
    );
}

/// Returns a [`dialoguer`] theme with the given prompt.
pub(crate) fn question_theme(prompt: impl Display) -> impl dialoguer::theme::Theme {
    let prompt_prefix = style::QUESTION.apply_to(format!(
        prompt_format!(),
        style::QUESTION.apply_to(prompt),
        indent = PROMPT_INDENT,
    ));
    ColorfulTheme {
        success_prefix: prompt_prefix.clone(),
        error_prefix: prompt_prefix.clone().red(),
        prompt_prefix,
        prompt_style: Style::new(),
        prompt_suffix: style(String::new()),
        active_item_prefix: style("  *".into()).bold().for_stderr(),
        active_item_style: Style::new().bold(),
        inactive_item_prefix: style("   ".into()).for_stderr(),
        ..ColorfulTheme::default()
    }
}