use std::fmt::Display;
use std::io::IsTerminal;
use bonds_core::BondError;
use bonds_core::error::ErrorKind;
const RESET: &str = "\x1b[0m";
const GREEN_BOLD: &str = "\x1b[1;32m";
const YELLOW_BOLD: &str = "\x1b[1;33m";
const RED_BOLD: &str = "\x1b[1;31m";
const MAGENTA: &str = "\x1b[35m";
const CYAN: &str = "\x1b[36m";
const DIM: &str = "\x1b[2m";
const DIM_UNDERLINE: &str = "\x1b[2;4m";
const BOLD: &str = "\x1b[1m";
const UNDERLINE: &str = "\x1b[4m";
const BOLD_UNDERLINE: &str = "\x1b[1;4m";
const GREEN: &str = "\x1b[32m";
const YELLOW: &str = "\x1b[33m";
const RED: &str = "\x1b[31m";
const GOLD: &str = "\x1b[38;5;220m";
const LIGHT_BLUE: &str = "\x1b[38;5;117m";
const DIM_BOLD: &str = "\x1b[1;2m";
const NEWLINE: &str = " ";
const BONDS_BANNER: &str = r#"
__ __
/\ \ /\ \
\ \ \____ ___ ___ \_\ \ ____
\ \ '__`\ / __`\/' _ `\ /'_` \ /',__\
\ \ \L\ /\ \L\ /\ \/\ \/\ \L\ \/\__, `\
\ \_,__\ \____\ \_\ \_\ \___,_\/\____/
\/___/ \/___/ \/_/\/_/\/__,_ /\/___/
"#;
pub fn landing(version: &str) {
paint(BONDS_BANNER, BOLD);
paint(" ", DIM_UNDERLINE);
newline();
paint(" https://bonds.fyi ", LIGHT_BLUE);
paint(" ", DIM_UNDERLINE);
newline();
info(format!("Version {version}"));
dim("Organize and manage source-target directory bonds.");
newline();
heading("Quick start:");
normal(" bond add <source> [target] [--name <name>] [--dry-run] [--verbose]");
normal(" bond list");
normal(" bond info <id|name>");
normal(" bond remove <id|name> [--with-target] [--dry-run] [--verbose]");
normal(
" bond update <id|name> [--source <path>] [--target <path>] [--name <name>] [--dry-run] [--verbose]",
);
normal(" bond migrate <id|name> [dest] [--dry-run] [--verbose]");
newline();
dim("Use `bond --help` for the full command reference.");
}
fn colors_enabled() -> bool {
if std::env::var_os("NO_COLOR").is_some() {
return false;
}
if std::env::var_os("CLICOLOR_FORCE").is_some() {
return true;
}
std::io::stderr().is_terminal() && std::env::var("TERM").map_or(true, |term| term != "dumb")
}
fn paint(text: impl Display, style: &str) -> String {
let text = text.to_string();
#[allow(unused_assignments)]
let mut result = String::with_capacity(style.len() + text.len() + RESET.len());
if colors_enabled() {
result = format!("{style}{text}{RESET}");
} else {
result = text;
}
println!("{}", result);
result
}
fn style_for(kind: ErrorKind) -> &'static str {
match kind {
ErrorKind::NotFound | ErrorKind::Conflict => YELLOW_BOLD,
ErrorKind::Input | ErrorKind::Runtime | ErrorKind::Config => RED_BOLD,
}
}
pub fn error_prefix(kind: ErrorKind) -> String {
paint("Error:", style_for(kind))
}
pub fn format_error(err: &BondError) -> String {
format!("{} {}", error_prefix(err.kind()), err)
}
pub fn format_context_error(context: &str, err: &BondError) -> String {
format!("{} {}: {}", error_prefix(err.kind()), context, err)
}
#[allow(dead_code)]
pub fn success(text: impl Display) -> String {
paint(text, GREEN)
}
#[allow(dead_code)]
pub fn info(text: impl Display) -> String {
paint(text, CYAN)
}
#[allow(dead_code)]
pub fn warning(text: impl Display) -> String {
paint(text, YELLOW)
}
#[allow(dead_code)]
pub fn error(text: impl Display) -> String {
paint(text, RED)
}
#[allow(dead_code)]
pub fn title(text: impl Display) -> String {
paint(format!("\n{}\n", text), BOLD_UNDERLINE)
}
#[allow(dead_code)]
pub fn heading(text: impl Display) -> String {
paint(format!("{}", text), BOLD)
}
#[allow(dead_code)]
pub fn underline(text: impl Display) -> String {
paint(format!("{}", text), UNDERLINE)
}
#[allow(dead_code)]
pub fn subheading(text: impl Display) -> String {
paint(format!("{}", text), DIM_BOLD)
}
#[allow(dead_code)]
pub fn normal(text: impl Display) -> String {
paint(text, RESET)
}
#[allow(dead_code)]
pub fn key(text: impl Display) -> String {
paint(text, GOLD)
}
#[allow(dead_code)]
pub fn id(text: impl Display) -> String {
paint(text, LIGHT_BLUE)
}
#[allow(dead_code)]
pub fn path(text: impl Display) -> String {
paint(text, MAGENTA)
}
#[allow(dead_code)]
pub fn dim(text: impl Display) -> String {
paint(text, DIM)
}
#[allow(dead_code)]
pub fn status_ok(text: impl Display) -> String {
paint(text, GREEN_BOLD)
}
#[allow(dead_code)]
pub fn status_warn(text: impl Display) -> String {
paint(text, YELLOW_BOLD)
}
#[allow(dead_code)]
pub fn status_bad(text: impl Display) -> String {
paint(text, RED_BOLD)
}
#[allow(dead_code)]
pub fn newline() {
paint("", NEWLINE);
}
#[allow(dead_code)]
pub fn debug(text: impl Display) -> String {
paint(text, DIM)
}