mchost / src/ui.rs

raw file 2118 bytes
//! Tiny terminal helpers: colored, prefixed output that degrades to plain text
//! when piped or when NO_COLOR is set.

use std::io::IsTerminal;
use std::sync::OnceLock;

fn color() -> bool {
    static ON: OnceLock<bool> = OnceLock::new();
    *ON.get_or_init(|| std::io::stdout().is_terminal() && std::env::var_os("NO_COLOR").is_none())
}

fn paint(code: &str, text: &str) -> String {
    if color() {
        format!("\x1b[{code}m{text}\x1b[0m")
    } else {
        text.to_string()
    }
}

pub fn banner(name: &str, version: &str) {
    println!("{}", paint("36", &format!("{name} {version}")));
}

pub fn info(msg: &str) {
    println!("{} {}", paint("36", "[info]"), msg);
}

pub fn ok(msg: &str) {
    println!("{} {}", paint("32", "[ ok ]"), msg);
}

pub fn warn(msg: &str) {
    println!("{} {}", paint("33", "[warn]"), msg);
}

pub fn error(msg: &str) {
    eprintln!("{} {}", paint("31", "[fail]"), msg);
}

pub fn server(line: &str) {
    println!("{} {}", paint("37", "        [server]"), line);
}

pub fn tunnel(line: &str) {
    println!("{} {}", paint("35", "[tunnel]"), line);
}

pub fn tunnel_ok(line: &str) {
    println!("{} {}", paint("32", "[tunnel]"), line);
}

pub fn bridge(line: &str) {
    println!("{} {}", paint("33", "[bridge]"), line);
}

pub fn bridge_ok(line: &str) {
    println!("{} {}", paint("32", "[bridge]"), line);
}

pub fn client(line: &str) {
    println!("{} {}", paint("34", "[connect]"), line);
}

pub fn client_ok(line: &str) {
    println!("{} {}", paint("32", "[connect]"), line);
}

/// A highlighted, hard-to-miss block for the address players would use.
pub fn highlight(lines: &[String]) {
    let width = lines
        .iter()
        .map(|l| l.chars().count())
        .max()
        .unwrap_or(0)
        .max(40);
    let bar = paint("36", &"─".repeat(width + 4));
    println!("{bar}");
    for line in lines {
        let pad = width - line.chars().count();
        println!(
            "{} {}{}{}",
            paint("36", "│"),
            line,
            " ".repeat(pad),
            paint("36", "│")
        );
    }
    println!("{bar}");
}