#![allow(dead_code)]
use serde::Serialize;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
pub enum Format {
#[default]
Human,
Json,
Quiet,
}
impl std::fmt::Display for Format {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Format::Human => write!(f, "human"),
Format::Json => write!(f, "json"),
Format::Quiet => write!(f, "quiet"),
}
}
}
impl std::str::FromStr for Format {
type Err = String;
fn from_str(s: &str) -> Result<Self, Self::Err> {
match s.to_lowercase().as_str() {
"human" | "pretty" | "text" | "table" => Ok(Format::Human),
"json" => Ok(Format::Json),
"quiet" => Ok(Format::Quiet),
_ => Err(format!(
"Unknown format '{}'. Valid options: human, json, quiet",
s
)),
}
}
}
pub fn print_and_exit<T: Outputable>(result: T, format_str: &str) -> i32 {
let format = format_str.parse::<Format>().unwrap_or(Format::Human);
let rendered = result.render(format);
if !rendered.is_empty() {
println!("{}", rendered);
}
result.exit_code().code()
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum ExitCode {
Ok = 0,
Warning = 1,
Error = 2,
}
impl ExitCode {
pub fn code(self) -> i32 {
self as i32
}
}
pub trait Outputable: Serialize {
fn to_human(&self) -> String;
fn to_json(&self) -> String {
serde_json::to_string_pretty(self).unwrap_or_else(|e| format!("{{\"error\":\"{}\"}}", e))
}
fn to_quiet(&self) -> String {
String::new()
}
fn render(&self, format: Format) -> String {
match format {
Format::Human => self.to_human(),
Format::Json => self.to_json(),
Format::Quiet => self.to_quiet(),
}
}
fn exit_code(&self) -> ExitCode {
ExitCode::Ok
}
}
pub mod colors {
pub const RESET: &str = "\x1b[0m";
pub const BOLD: &str = "\x1b[1m";
pub const RED: &str = "\x1b[31m";
pub const GREEN: &str = "\x1b[32m";
pub const YELLOW: &str = "\x1b[33m";
pub const BLUE: &str = "\x1b[34m";
pub const CYAN: &str = "\x1b[36m";
pub const DIM: &str = "\x1b[2m";
}
pub mod icons {
pub const OK: &str = "[OK]";
pub const WARN: &str = "[WARN]";
pub const ERROR: &str = "[ERROR]";
pub const INFO: &str = "[INFO]";
pub const INSTALL: &str = "+";
pub const UPDATE: &str = "~";
pub const SATISFIED: &str = "=";
pub const HOOK: &str = "->";
}
pub fn status_line(icon: &str, color: &str, message: &str) -> String {
format!("{}{}{} {}", color, icon, colors::RESET, message)
}
pub fn header(title: &str) -> String {
format!(
"{}{}{}\n{}",
colors::BOLD,
title,
colors::RESET,
"=".repeat(title.len())
)
}
pub fn subheader(title: &str) -> String {
format!("\n{}{}{}:", colors::BOLD, title, colors::RESET)
}