use std::io; use std::sync::Mutex; use is_terminal::IsTerminal; use owo_colors::OwoColorize; use crate::cli::ColorMode; #[derive(Clone, Copy, Debug)] pub enum StatusKind { Renamed, Skipped, Failed, } pub struct Output { use_color: bool, verbose: bool, lock: Mutex<()>, } impl Output { pub fn new(color_mode: &ColorMode, verbose: bool) -> Self { let use_color = match color_mode { ColorMode::Always => true, ColorMode::Never => false, ColorMode::Auto => io::stdout().is_terminal(), }; Self { use_color, verbose, lock: Mutex::new(()), } } pub fn status_line( &self, index: usize, total: usize, status: StatusKind, filename: &str, provider: Option<&str>, result: &str, output_name: Option<&str>, ) { let _guard = self.lock.lock().unwrap(); let prefix = format!("[{}/{}]", index, total); let status_label = match status { StatusKind::Renamed => "renamed", StatusKind::Skipped => "skipped", StatusKind::Failed => "failed", }; let status_label = self.colorize_status(status_label, status); let provider_label = provider.map(|p| format!("{p}")); let mut line = format!("{prefix} {status_label} {filename}"); if let Some(provider) = provider_label { line.push_str(&format!(" | {provider}")); } line.push_str(&format!(" | {result}")); if let Some(output_name) = output_name { line.push_str(&format!(" -> {output_name}")); } println!("{line}"); } pub fn warn(&self, message: &str) { let _guard = self.lock.lock().unwrap(); let msg = if self.use_color { message.yellow().to_string() } else { message.to_string() }; eprintln!("{msg}"); } pub fn info(&self, message: &str) { if self.verbose { let _guard = self.lock.lock().unwrap(); println!("{message}"); } } fn colorize_status(&self, text: &str, status: StatusKind) -> String { if !self.use_color { return text.to_string(); } match status { StatusKind::Renamed => text.green().to_string(), StatusKind::Skipped => text.yellow().to_string(), StatusKind::Failed => text.red().to_string(), } } }