use std::{fmt, process, sync::LazyLock}; use console::{StyledObject, style}; use dialoguer::{Select, theme::ColorfulTheme}; use indicatif::{ProgressBar, ProgressStyle}; use log::{error, info}; use crate::sharry; type StaticStyled<'t> = LazyLock>; pub static SHRUPL: StaticStyled = LazyLock::new(|| style("ShrUpl").yellow().bold()); pub fn prompt_continue() -> bool { let prompt = format!( "This operation has previously been stopped. {}", style("How to proceed?").cyan() ); let choices = [ format!("Load and {}", style("continue operation").green().bold()), format!("Start a {}", style("new operation").cyan().bold()), format!("Quit {}", *SHRUPL), ]; let selection = Select::with_theme(&ColorfulTheme::default()) .with_prompt(prompt) .default(0) .items(&choices) .interact() .unwrap_or(2); if selection == 2 { process::exit(0); } selection == 0 } pub fn style_all<'t, F>(strs: &[&'t str], f: F) -> Vec where F: Fn(StyledObject<&'t str>) -> StyledObject<&'t str>, { strs.iter().map(|&s| f(style(s)).to_string()).collect() } pub fn new_progressbar() -> ProgressBar { ProgressBar::hidden().with_style( ProgressStyle::with_template(&format!( concat!( "{{bar:50.cyan/blue}} {{msg:.magenta}}: ", "{{binary_bytes:.yellow}}{}{{binary_total_bytes:.yellow}} ", "({{eta}})", ), style("/").magenta(), )) .expect("invalid style template"), ) } pub enum Log {} impl Log { fn eprintln(kind: impl fmt::Display, msg: impl fmt::Display) { eprintln!("{} {}: {}", *SHRUPL, kind, style(msg).cyan().italic(),); } pub fn warning(msg: impl fmt::Display) { Self::eprintln(style("Warning").magenta().bold(), msg); } pub fn error(msg: impl fmt::Display) -> ! { Self::eprintln(style("Error").red().bold(), msg); process::exit(1); } pub fn handle(e: &sharry::ClientError) { if e.is_fatal() { // react to fatal error error!("fatal error: {e:?}"); Self::error(e); } // handle recoverable error info!("recoverable error: {e:?}"); } }