app
Adom Step2GLB - STEP to GLB converter
Public Made by Adomby adom
Color-preserving STEP (.step/.stp) to GLB converter. Thin Rust CLI shelling to a shared OCCT XCAF service. Formerly 'step2glb'.
1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465
//! Shared CLI output helpers — OK: / ERROR: / Hint: + note! macro.
//! Mirrors the pattern from adom-cli-design SKILL + video-post's implementation:
//! ANSI colors only when stdout/stderr is a TTY; piped output is plain ASCII
//! so `cmd > log` never embeds raw escape sequences.
use std::io::IsTerminal;
use std::sync::OnceLock;
pub const GREEN: &str = "\x1b[32m";
pub const RED: &str = "\x1b[31m";
pub const YELLOW: &str = "\x1b[33m";
pub const CYAN: &str = "\x1b[36m";
pub const BOLD: &str = "\x1b[1m";
pub const DIM: &str = "\x1b[2m";
pub const RESET: &str = "\x1b[0m";
static STDOUT_IS_TTY: OnceLock<bool> = OnceLock::new();
static STDERR_IS_TTY: OnceLock<bool> = OnceLock::new();
pub fn stdout_is_tty() -> bool { *STDOUT_IS_TTY.get_or_init(|| std::io::stdout().is_terminal()) }
pub fn stderr_is_tty() -> bool { *STDERR_IS_TTY.get_or_init(|| std::io::stderr().is_terminal()) }
pub fn strip_ansi(s: &str) -> String {
let mut out = String::with_capacity(s.len());
let mut chars = s.chars().peekable();
while let Some(c) = chars.next() {
if c == '\x1b' && chars.peek() == Some(&'[') {
chars.next();
for c2 in chars.by_ref() { if c2.is_ascii_alphabetic() { break; } }
continue;
}
out.push(c);
}
out
}
pub fn ok(msg: impl std::fmt::Display) {
let s = msg.to_string();
if stdout_is_tty() { println!("{GREEN}{BOLD}OK:{RESET} {s}"); }
else { println!("OK: {}", strip_ansi(&s)); }
}
pub fn err(msg: impl std::fmt::Display) {
let s = msg.to_string();
if stderr_is_tty() { eprintln!("{RED}{BOLD}ERROR:{RESET} {s}"); }
else { eprintln!("ERROR: {}", strip_ansi(&s)); }
}
pub fn hint(msg: impl std::fmt::Display) {
let s = msg.to_string();
if stderr_is_tty() { eprintln!("{DIM}Hint:{RESET} {s}"); }
else { eprintln!("Hint: {}", strip_ansi(&s)); }
}
pub fn warn(msg: impl std::fmt::Display) {
let s = msg.to_string();
if stderr_is_tty() { eprintln!("{YELLOW}{BOLD}WARN:{RESET} {s}"); }
else { eprintln!("WARN: {}", strip_ansi(&s)); }
}
/// Internal progress macro — prints to stdout with ANSI gating.
#[macro_export]
macro_rules! note {
($($arg:tt)*) => {{
let __s = format!($($arg)*);
if $crate::ui::stdout_is_tty() { println!("{}", __s); }
else { println!("{}", $crate::ui::strip_ansi(&__s)); }
}};
}