use crate::color::Palette;
pub enum Line {
Raw(String),
Kv(String, String),
}
pub fn visible_width(s: &str) -> usize {
let mut w = 0usize;
let mut it = s.chars();
while let Some(c) = it.next() {
if c == '\x1b' {
for n in it.by_ref() {
if n.is_ascii_alphabetic() {
break;
}
}
} else {
w += 1;
}
}
w
}
pub fn strip_ansi(s: &str) -> String {
let mut out = String::with_capacity(s.len());
let mut it = s.chars();
while let Some(c) = it.next() {
if c == '\x1b' {
for n in it.by_ref() {
if n.is_ascii_alphabetic() {
break;
}
}
} else {
out.push(c);
}
}
out
}
pub fn render(logo: &[String], info: &[Line], pal: &Palette, term_width: usize) {
let logo_w = logo.iter().map(|l| visible_width(l)).max().unwrap_or(0);
let key_w = info
.iter()
.filter_map(|l| match l {
Line::Kv(k, _) => Some(k.chars().count()),
_ => None,
})
.max()
.unwrap_or(0);
let gap = if logo_w > 0 { 3 } else { 0 };
const SEP: &str = " ";
let rows = logo.len().max(info.len());
let mut out = String::new();
for i in 0..rows {
let logo_line = logo.get(i).map(String::as_str).unwrap_or("");
let logo_pad = logo_w.saturating_sub(visible_width(logo_line));
let info_str = match info.get(i) {
Some(Line::Raw(s)) => s.clone(),
Some(Line::Kv(k, v)) => {
let mut value = v.clone();
if term_width > 0 {
let used = logo_w + gap + key_w + SEP.len();
if term_width > used {
let avail = term_width - used;
if value.chars().count() > avail && avail > 1 {
let cut: String = value.chars().take(avail - 1).collect();
value = format!("{cut}…");
}
}
}
let key = pal.paint(pal.key, &format!("{:<width$}", k, width = key_w));
format!("{key}{SEP}{value}")
}
None => String::new(),
};
out.push_str(logo_line);
out.push_str(&" ".repeat(logo_pad + gap));
out.push_str(&info_str);
out.push('\n');
}
print!("{out}");
}