use console::{Style, Term};
pub struct Ui {
term: Term,
pub heading: Style,
pub success: Style,
pub warning: Style,
pub muted: Style,
pub bold: Style,
}
impl Default for Ui {
fn default() -> Self {
Self::new()
}
}
impl Ui {
pub fn new() -> Self {
Self {
term: Term::stderr(),
heading: Style::new().cyan().bold(),
success: Style::new().green(),
warning: Style::new().yellow(),
muted: Style::new().dim(),
bold: Style::new().bold(),
}
}
pub fn heading(&self, text: &str) {
let _ = self
.term
.write_line(&format!("\n{}", self.heading.apply_to(text)));
}
pub fn success(&self, text: &str) {
let _ = self
.term
.write_line(&self.success.apply_to(text).to_string());
}
pub fn warning(&self, text: &str) {
let _ = self
.term
.write_line(&self.warning.apply_to(text).to_string());
}
pub fn muted(&self, text: &str) {
let _ = self.term.write_line(&self.muted.apply_to(text).to_string());
}
pub fn line(&self, text: &str) {
let _ = self.term.write_line(text);
}
pub fn blank(&self) {
let _ = self.term.write_line("");
}
pub fn bullet_list(&self, items: &[String]) {
for item in items {
let _ = self
.term
.write_line(&format!(" {} {}", self.muted.apply_to("-"), item));
}
}
pub fn confirm(&self, prompt: &str, default: bool) -> anyhow::Result<bool> {
Ok(cliclack::confirm(prompt)
.initial_value(default)
.interact()?)
}
pub fn multi_select(
&self,
prompt: &str,
values: &[String],
labels: &[String],
defaults: &[bool],
) -> anyhow::Result<Vec<String>> {
let initial_values: Vec<String> = values
.iter()
.zip(defaults.iter())
.filter_map(|(val, &selected)| if selected { Some(val.clone()) } else { None })
.collect();
let mut ms = cliclack::multiselect(prompt);
for (val, label) in values.iter().zip(labels.iter()) {
ms = ms.item(val.clone(), label, "");
}
ms = ms.initial_values(initial_values);
ms = ms.required(false);
Ok(ms.interact()?)
}
pub fn input(&self, prompt: &str, default: &str) -> anyhow::Result<String> {
Ok(cliclack::input(prompt)
.default_input(default)
.required(false)
.interact::<String>()?)
}
pub fn summary(&self, count: usize, noun: &str, verb: &str) {
let plural = if count == 1 { "" } else { "es" };
self.success(&format!("{count} {noun}{plural} {verb}."));
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_ui_default() {
let ui = Ui::default();
let styled = ui.heading.apply_to("test");
assert!(styled.to_string().contains("test"));
}
}