From a633f4e228f20e2a8d377d6d90ae915fc4894fa3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=B6rn-Michael=20Miehe?= <40151420+ldericher@users.noreply.github.com> Date: Wed, 18 Jun 2025 18:14:09 +0000 Subject: [PATCH] move most printing/styling into own file --- src/main.rs | 99 ++++++++------------------------------------------- src/output.rs | 72 +++++++++++++++++++++++++++++++++++++ 2 files changed, 86 insertions(+), 85 deletions(-) create mode 100644 src/output.rs diff --git a/src/main.rs b/src/main.rs index 08fa7b0..8db3d12 100644 --- a/src/main.rs +++ b/src/main.rs @@ -3,6 +3,7 @@ mod cachefile; mod cli; mod file; mod impl_ureq; +mod output; mod sharry; use std::{ @@ -15,54 +16,11 @@ use std::{ use clap::Parser; use console::style; -use dialoguer::{Select, theme::ColorfulTheme}; -use log::{error, info, trace}; +use log::{info, trace}; use appstate::AppState; use cli::Cli; -use sharry::ClientError; - -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 {}", style("ShrUpl").yellow().bold()), - ]; - - let selection = Select::with_theme(&ColorfulTheme::default()) - .with_prompt(prompt) - .default(0) - .items(&choices) - .interact() - .unwrap_or(2); - - if selection == 2 { - process::exit(255); - } - - selection == 0 -} - -fn handle_error(e: &ClientError) { - if e.is_fatal() { - // react to fatal error - error!("fatal error: {e:?}"); - eprintln!( - "{} {}", - style("Error!").red().bold(), - style(e.to_string()).cyan().italic(), - ); - process::exit(1); - } - - // handle recoverable error - info!("recoverable error: {e:?}"); -} +use output::{Log, SHRUPL, prompt_continue}; fn main() { env_logger::init(); @@ -87,11 +45,7 @@ fn main() { let args = Cli::parse(); info!("args: {args:#?}"); - println!( - "{} to {}!", - style("Welcome").magenta().bold(), - style("ShrUpl").yellow().bold(), - ); + println!("{} to {}!", style("Welcome").magenta().bold(), *SHRUPL); let mut state = AppState::try_resume(&args) .and_then(|state| prompt_continue().then_some(state)) @@ -101,34 +55,22 @@ fn main() { match AppState::from_args(&args) { Ok(state) => { state.save().unwrap_or_else(|e| { - eprintln!( - "{} Failed to save {} state: {e}", - style("Warning:").red().bold(), - style("ShrUpl").yellow().bold(), - ); + Log::warning(format_args!("Failed to save state: {e}")); }); state } Err(e) => { - handle_error(&e); - process::exit(1); + Log::handle(&e); + Log::error(format_args!("Failed to create state: {e}")); } } }); info!("continuing with state: {state:#?}"); - let fns_magenta = state - .file_names() - .iter() - .map(|&n| style(n).magenta().to_string()) - .collect::>() - .join(", "); + let fns_magenta = output::style_all(&state.file_names(), |s| style(s).magenta()).join(", "); - println!( - "{} is uploading: {fns_magenta}", - style("ShrUpl").yellow().bold(), - ); + println!("{} is uploading: {fns_magenta}", *SHRUPL); let mut buffer = vec![0; args.chunk_size * 1024 * 1024]; @@ -137,14 +79,13 @@ fn main() { Err(e) => { // TODO better error handling (this will just retry endlessly) // Error 404: Share might have been deleted - handle_error(&e); + Log::handle(&e); if let Some(s) = state.rewind() { trace!("State rewound, retrying last chunk"); state = s; } else { - eprintln!("{} Failed to retry chunk!", style("Error:").red().bold()); - process::exit(1); + Log::error("Failed to retry chunk!"); } } Ok(false) => { @@ -157,26 +98,14 @@ fn main() { } state.save().unwrap_or_else(|e| { - eprintln!( - "{} Failed to save {} state: {e}", - style("Warning:").red().bold(), - style("ShrUpl").yellow().bold(), - ); + Log::warning(format_args!("Failed to save state: {e}")); }); check_ctrlc(); } state.clear().unwrap_or_else(|e| { - eprintln!( - "{} Failed to remove {} state: {e}", - style("Warning:").red().bold(), - style("ShrUpl").yellow().bold(), - ); + Log::warning(format_args!("Failed to remove state: {e}")); }); - println!( - "{} finished {}", - style("ShrUpl").yellow().bold(), - style("successfully!").green() - ); + println!("{} finished {}", *SHRUPL, style("successfully!").green()); } diff --git a/src/output.rs b/src/output.rs new file mode 100644 index 0000000..1c28fd0 --- /dev/null +++ b/src/output.rs @@ -0,0 +1,72 @@ +use std::{fmt, process, sync::LazyLock}; + +use console::{StyledObject, style}; +use dialoguer::{Select, theme::ColorfulTheme}; +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(&'t str) -> StyledObject<&'t str>, +{ + strs.iter().map(|&s| f(s).to_string()).collect() +} + +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:?}"); + } +}