2025-06-18 18:14:09 +00:00
|
|
|
use std::{fmt, process, sync::LazyLock};
|
|
|
|
|
|
|
|
|
|
use console::{StyledObject, style};
|
|
|
|
|
use dialoguer::{Select, theme::ColorfulTheme};
|
2025-06-24 21:58:18 +00:00
|
|
|
use indicatif::{ProgressBar, ProgressStyle};
|
2025-06-18 18:14:09 +00:00
|
|
|
use log::{error, info};
|
|
|
|
|
|
|
|
|
|
use crate::sharry;
|
|
|
|
|
|
|
|
|
|
type StaticStyled<'t> = LazyLock<StyledObject<&'t str>>;
|
|
|
|
|
|
|
|
|
|
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<String>
|
|
|
|
|
where
|
2025-06-24 01:28:09 +00:00
|
|
|
F: Fn(StyledObject<&'t str>) -> StyledObject<&'t str>,
|
2025-06-18 18:14:09 +00:00
|
|
|
{
|
2025-06-24 01:28:09 +00:00
|
|
|
strs.iter().map(|&s| f(style(s)).to_string()).collect()
|
2025-06-18 18:14:09 +00:00
|
|
|
}
|
|
|
|
|
|
2025-06-24 21:58:18 +00:00
|
|
|
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"),
|
|
|
|
|
)
|
|
|
|
|
}
|
|
|
|
|
|
2025-06-18 18:14:09 +00:00
|
|
|
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:?}");
|
|
|
|
|
}
|
|
|
|
|
}
|