use terminal_size::{terminal_size, Width};
use crate::cli::color;
use crate::cli::output::{OutputConfig, OutputFormat};
const LABEL: &str = " SaferSkills ";
const LEAD: usize = 3;
const FALLBACK_WIDTH: usize = 80;
const PALETTE: &[u8] = &[
36, 37, 66, 72, 73, 79, 67, 108, 109, 110, 103, 115, ];
fn pick_color() -> u8 {
let nanos = std::time::SystemTime::now()
.duration_since(std::time::UNIX_EPOCH)
.map(|d| d.as_nanos() as u64)
.unwrap_or(0);
let mut x = nanos ^ ((std::process::id() as u64) << 32);
x = x.wrapping_add(0x9E37_79B9_7F4A_7C15);
x = (x ^ (x >> 30)).wrapping_mul(0xBF58_476D_1CE4_E5B9);
x = (x ^ (x >> 27)).wrapping_mul(0x94D0_49BB_1331_11EB);
x ^= x >> 31;
PALETTE[(x as usize) % PALETTE.len()]
}
fn detect_width() -> usize {
if let Some((Width(w), _)) = terminal_size() {
if w > 0 {
return usize::from(w);
}
}
std::env::var("COLUMNS")
.ok()
.and_then(|v| v.trim().parse::<usize>().ok())
.filter(|w| *w > 0)
.unwrap_or(FALLBACK_WIDTH)
}
fn build_rule(width: usize, color: bool, color_code: u8) -> String {
let min_width = LEAD + LABEL.chars().count() + 1;
let width = width.max(min_width);
let fill = if color { '\u{2584}' } else { '=' };
let lead: String = std::iter::repeat_n(fill, LEAD).collect();
let tail_len = width - LEAD - LABEL.chars().count();
let tail: String = std::iter::repeat_n(fill, tail_len).collect();
if color {
format!("\x1b[38;5;{color_code}m{lead}{LABEL}{tail}\x1b[0m")
} else {
format!("{lead}{LABEL}{tail}")
}
}
pub fn print(output: &OutputConfig) {
if output.format == OutputFormat::Json || output.quiet {
return;
}
eprintln!("{}", build_rule(detect_width(), output.color, pick_color()));
let version = env!("CARGO_PKG_VERSION");
let meta = format!(" v{version} · An OpenLatch project");
eprintln!("{}", color::dim(&meta, output.color));
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn rule_contains_camelcase_wordmark() {
assert!(build_rule(80, false, 36).contains("SaferSkills"));
assert!(build_rule(80, true, 36).contains("SaferSkills"));
}
#[test]
fn plain_rule_spans_exact_width() {
assert_eq!(build_rule(80, false, 36).chars().count(), 80);
assert_eq!(build_rule(200, false, 36).chars().count(), 200);
}
#[test]
fn narrow_width_clamps_up_to_fit_label() {
let min_width = LEAD + LABEL.chars().count() + 1;
assert_eq!(build_rule(1, false, 36).chars().count(), min_width);
}
#[test]
fn plain_rule_has_no_ansi() {
assert!(!build_rule(80, false, 36).contains("\x1b["));
}
#[test]
fn colored_rule_uses_256color_escape() {
for &code in PALETTE {
let rule = build_rule(80, true, code);
assert!(rule.starts_with(&format!("\x1b[38;5;{code}m")));
assert!(rule.ends_with("\x1b[0m"));
}
}
#[test]
fn picked_color_is_always_in_palette() {
for _ in 0..256 {
assert!(PALETTE.contains(&pick_color()));
}
}
#[test]
fn palette_excludes_aggressive_codes() {
const AGGRESSIVE: &[u8] = &[9, 196, 160, 124, 202, 208, 214, 13, 201, 165, 199];
for code in AGGRESSIVE {
assert!(!PALETTE.contains(code), "palette must stay non-aggressive");
}
}
}