pub mod diagnostics;
use serde::{Deserialize, Serialize};
use std::io::IsTerminal;
use std::str::FromStr;
#[derive(
Debug, Clone, Copy, Default, PartialEq, Eq, Deserialize, Serialize, schemars::JsonSchema,
)]
#[serde(rename_all = "lowercase")]
pub enum ColorMode {
#[default]
Auto,
Always,
Never,
}
impl FromStr for ColorMode {
type Err = String;
fn from_str(s: &str) -> Result<Self, Self::Err> {
match s {
"auto" => Ok(Self::Auto),
"always" => Ok(Self::Always),
"never" => Ok(Self::Never),
_ => Err(format!(
"unknown color mode `{s}`; expected auto, always, or never"
)),
}
}
}
#[derive(Debug, Clone, Deserialize, Serialize, Default, schemars::JsonSchema)]
#[serde(default)]
pub struct PrettyConfig {
pub enabled: Option<bool>,
pub colors: Option<ColorMode>,
pub highlight: Option<bool>,
}
impl PrettyConfig {
pub fn enabled(&self) -> bool {
self.enabled
.unwrap_or_else(|| std::io::stdout().is_terminal())
}
pub fn use_colors(&self) -> bool {
if std::env::var("NO_COLOR").is_ok() {
return false;
}
match self.colors.unwrap_or_default() {
ColorMode::Always => true,
ColorMode::Never => false,
ColorMode::Auto => std::io::stdout().is_terminal(),
}
}
pub fn highlight(&self) -> bool {
self.highlight.unwrap_or(true)
}
}
pub trait OutputFormatter: Serialize + schemars::JsonSchema {
fn format_text(&self) -> String;
fn format_pretty(&self) -> String {
self.format_text()
}
}
pub fn progress_bar(ratio: f64, width: usize) -> String {
let ratio = ratio.clamp(0.0, 1.0);
let filled = ((ratio * width as f64).round() as usize).min(width);
format!("{}{}", "█".repeat(filled), "░".repeat(width - filled))
}
pub fn progress_bar_good(ratio: f64, width: usize) -> String {
use nu_ansi_term::Color;
let color = if ratio >= 0.67 {
Color::Green
} else if ratio >= 0.34 {
Color::Yellow
} else {
Color::Red
};
color.paint(progress_bar(ratio, width)).to_string()
}
pub fn progress_bar_bad(ratio: f64, width: usize) -> String {
progress_bar_good(1.0 - ratio, width)
}
#[cfg(test)]
mod tests {
use super::*;
#[derive(Serialize, schemars::JsonSchema)]
#[allow(dead_code)]
struct TestOutput {
name: String,
count: usize,
}
impl OutputFormatter for TestOutput {
fn format_text(&self) -> String {
format!("{}: {}", self.name, self.count)
}
}
#[test]
fn test_pretty_config_use_colors() {
let config = PrettyConfig {
colors: Some(ColorMode::Always),
..Default::default()
};
assert!(config.use_colors());
let config = PrettyConfig {
colors: Some(ColorMode::Never),
..Default::default()
};
assert!(!config.use_colors());
}
#[test]
fn test_pretty_config_highlight() {
let config = PrettyConfig::default();
assert!(config.highlight());
let config = PrettyConfig {
highlight: Some(false),
..Default::default()
};
assert!(!config.highlight());
}
}