use clap::CommandFactory;
use std::io::IsTerminal;
const WORDMARK: [&str; 6] = [
" ██████╗ ███████╗████████╗██████╗ █████╗ ██╗ ██╗ █████╗ ",
"██╔═══██╗██╔════╝╚══██╔══╝██╔══██╗██╔══██╗██║ ██╔╝██╔══██╗",
"██║ ██║███████╗ ██║ ██████╔╝███████║█████╔╝ ███████║",
"██║ ██║╚════██║ ██║ ██╔══██╗██╔══██║██╔═██╗ ██╔══██║",
"╚██████╔╝███████║ ██║ ██║ ██║██║ ██║██║ ██╗██║ ██║",
" ╚═════╝ ╚══════╝ ╚═╝ ╚═╝ ╚═╝╚═╝ ╚═╝╚═╝ ╚═╝╚═╝ ╚═╝",
];
const NARROW: &str = "OSTRAKA";
const NEEDS: u16 = 60;
const ACCENT: &str = "\x1b[36m";
const MUTED: &str = "\x1b[90m";
const BOLD: &str = "\x1b[1m";
const OFF: &str = "\x1b[0m";
fn colour(out_is_terminal: bool) -> bool {
out_is_terminal
&& std::env::var_os("NO_COLOR").is_none()
&& std::env::var("TERM").map(|t| t != "dumb").unwrap_or(true)
}
pub fn render(width: u16, colour: bool) -> String {
let (accent, muted, bold, off) = if colour {
(ACCENT, MUTED, BOLD, OFF)
} else {
("", "", "", "")
};
let mut out = String::new();
if width >= NEEDS {
for row in WORDMARK {
out.push_str(accent);
out.push_str(row);
out.push_str(off);
out.push('\n');
}
} else {
out.push_str(bold);
out.push_str(NARROW);
out.push_str(off);
out.push('\n');
}
let cli = crate::Cli::command();
let about = cli.get_about().map(|a| a.to_string()).unwrap_or_default();
out.push('\n');
out.push_str(&format!(
" {bold}Ostraka v{}{off} — {about}\n\n",
env!("CARGO_PKG_VERSION")
));
out.push_str(&format!("{bold}Commands:{off}\n"));
let names: Vec<(String, String)> = cli
.get_subcommands()
.filter(|c| !c.is_hide_set())
.map(|c| {
(
c.get_name().to_string(),
c.get_about().map(|a| a.to_string()).unwrap_or_default(),
)
})
.collect();
let pad = names.iter().map(|(n, _)| n.len()).max().unwrap_or(0);
for (name, about) in &names {
out.push_str(&format!(
" {accent}{name:<pad$}{off} {muted}{about}{off}\n"
));
}
out.push_str(&format!(
"\n {muted}`ostraka <command> --help` for one of them.{off}\n"
));
out
}
pub fn print() {
let terminal = std::io::stdout().is_terminal();
let width = crossterm::terminal::size().map(|(w, _)| w).unwrap_or(80);
print!("{}", render(width, colour(terminal)));
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn the_wordmark_is_one_rectangle() {
let widths: Vec<usize> = WORDMARK.iter().map(|r| r.chars().count()).collect();
assert!(
widths.iter().all(|w| *w == widths[0]),
"ragged wordmark: {widths:?}"
);
assert_eq!(widths[0], NEEDS as usize - 2, "{widths:?}");
}
#[test]
fn a_narrow_terminal_gets_the_name_instead_of_half_a_wordmark() {
let wide = render(80, false);
let narrow = render(40, false);
assert!(wide.contains(WORDMARK[0]), "{wide}");
assert!(!narrow.contains(WORDMARK[0]), "{narrow}");
assert!(narrow.contains(NARROW), "{narrow}");
for out in [&wide, &narrow] {
assert!(out.contains("run"), "{out}");
assert!(out.contains("Commands:"), "{out}");
}
}
#[test]
fn every_command_the_parser_has_is_listed() {
let out = render(80, false);
for command in crate::Cli::command().get_subcommands() {
assert!(
out.contains(command.get_name()),
"{} is missing from:\n{out}",
command.get_name()
);
}
}
#[test]
fn nothing_escapes_when_colour_is_off() {
assert!(!render(80, false).contains('\x1b'));
assert!(render(80, true).contains('\x1b'));
}
#[test]
fn no_colour_is_honoured_however_it_is_set() {
assert!(!colour(false), "a pipe still got colour");
}
}