use crate::builtin_docs::{BUILTIN_CHAPTERS, BUILTIN_DOCS, EX_COMMANDS, OPTION_DOCS, V_VARS};
pub const LOGO: [&str; 6] = [
"██╗ ██╗██╗███╗ ███╗██╗ ██████╗ ███████╗",
"██║ ██║██║████╗ ████║██║ ██╔══██╗██╔════╝",
"██║ ██║██║██╔████╔██║██║ ██████╔╝███████╗",
"╚██╗ ██╔╝██║██║╚██╔╝██║██║ ██╔══██╗╚════██║",
" ╚████╔╝ ██║██║ ╚═╝ ██║███████╗██║ ██║███████║",
" ╚═══╝ ╚═╝╚═╝ ╚═╝╚══════╝╚═╝ ╚═╝╚══════╝",
];
pub fn visible_width(s: &str) -> usize {
let bytes = s.as_bytes();
let mut i = 0;
let mut w = 0usize;
while i < bytes.len() {
if bytes[i] == 0x1B && i + 1 < bytes.len() && bytes[i + 1] == b'[' {
i += 2;
while i < bytes.len() && !(0x40..=0x7E).contains(&bytes[i]) {
i += 1;
}
i += 1;
} else {
let step = std::str::from_utf8(&bytes[i..])
.ok()
.and_then(|s| s.chars().next())
.map(|c| c.len_utf8())
.unwrap_or(1);
w += 1;
i += step;
}
}
w
}
pub fn render_banner(colored: bool) -> String {
let version = env!("CARGO_PKG_VERSION");
let cores = std::thread::available_parallelism()
.map(|n| n.get())
.unwrap_or(1);
let n_builtins = BUILTIN_DOCS.len();
let n_ex = EX_COMMANDS.len();
let n_vvars = V_VARS.len();
let n_options = OPTION_DOCS.len();
let n_chapters = BUILTIN_CHAPTERS.len();
let (mem_total_gib, mem_avail_gib) = {
use sysinfo::System;
let mut sys = System::new();
sys.refresh_memory();
let total = sys.total_memory() as f64 / 1024.0 / 1024.0 / 1024.0;
let avail = sys.available_memory() as f64 / 1024.0 / 1024.0 / 1024.0;
(total, avail)
};
let os = std::env::consts::OS;
let arch = std::env::consts::ARCH;
let pid = std::process::id();
let (c, m, r, y, g, n) = if colored {
(
"\x1b[36m", "\x1b[35m", "\x1b[31m", "\x1b[33m", "\x1b[32m", "\x1b[0m",
)
} else {
("", "", "", "", "", "")
};
const INNER: usize = 64;
let bar = "─".repeat(INNER);
let mut out = String::with_capacity(2048);
let row = |out: &mut String, body: &str| {
let pad = INNER.saturating_sub(visible_width(body));
out.push_str(&format!("{c} │{n}{body}{:pad$}{c}│{n}\n", "", pad = pad));
};
out.push_str(&format!("{c} {}{n}\n", LOGO[0]));
out.push_str(&format!("{c} {}{n}\n", LOGO[1]));
out.push_str(&format!("{m} {}{n}\n", LOGO[2]));
out.push_str(&format!("{m} {}{n}\n", LOGO[3]));
out.push_str(&format!("{r} {}{n}\n", LOGO[4]));
out.push_str(&format!("{r} {}{n}\n", LOGO[5]));
out.push_str(&format!("{c} ┌{bar}┐{n}\n"));
row(
&mut out,
&format!(
" {y}SYSTEM{n} status:{g} ONLINE {c}//{n} {y}os:{n} {os} {y}arch:{n} {arch} {y}pid:{n} {pid}"
),
);
row(
&mut out,
&format!(
" {y}CORES{n} {cores} {y}MEM{n} {mem_avail_gib:.1} {c}/{n} {mem_total_gib:.1} GiB available"
),
);
out.push_str(&format!("{c} ├{bar}┤{n}\n"));
row(
&mut out,
&format!(
" {y}builtins{n} {n_builtins:<5} {y}ex-cmds{n} {n_ex:<5} {y}v:vars{n} {n_vvars:<5}"
),
);
row(
&mut out,
&format!(" {y}options{n} {n_options:<5} {y}chapters{n} {n_chapters:<5}"),
);
out.push_str(&format!("{c} └{bar}┘{n}\n"));
out.push_str(&format!(
"{m} >> VIML INTERPRETER ON FUSEVM // FULL SPECTRUM v{version} <<{n}\n"
));
out
}
pub fn print_banner(colored: bool) {
print!("{}", render_banner(colored));
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn visible_width_ignores_csi_sequences() {
assert_eq!(visible_width("\x1b[31mabc\x1b[0m"), 3);
assert_eq!(visible_width("\x1b[1;38;5;202mok"), 2);
}
#[test]
fn visible_width_counts_each_char_once_for_multibyte() {
assert_eq!(visible_width("─├┤"), 3);
assert_eq!(visible_width("aé你"), 3);
}
#[test]
fn visible_width_handles_empty_and_lone_escape() {
assert_eq!(visible_width(""), 0);
assert_eq!(visible_width("\x1bz"), 2);
}
#[test]
fn render_banner_plain_has_no_ansi_escapes() {
let s = render_banner(false);
assert!(!s.contains('\x1b'), "plain banner must not contain ESC");
assert!(s.contains("VIML INTERPRETER"));
assert!(s.contains(env!("CARGO_PKG_VERSION")));
}
#[test]
fn render_banner_colored_contains_ansi_escapes() {
let s = render_banner(true);
assert!(s.contains("\x1b["));
assert!(s.contains("\x1b[0m"));
}
#[test]
fn render_banner_rows_all_match_inner_width_after_strip() {
let s = render_banner(false);
let top = s
.lines()
.find(|l| l.starts_with(" ┌"))
.expect("top border present");
let want = visible_width(top);
let mut box_rows = 0;
for line in s.lines() {
if line.starts_with(" │") && line.ends_with('│') {
box_rows += 1;
assert_eq!(
visible_width(line),
want,
"box row width drift on line: {line}"
);
}
}
assert!(box_rows >= 4, "expected several rendered box rows");
}
#[test]
fn logo_has_six_rows_and_matches_help_glyphs() {
assert_eq!(LOGO.len(), 6);
assert!(LOGO[0].starts_with("██╗"));
}
}