Skip to main content

semora_cli/
output.rs

1//! Printing helpers: short text by default, JSON with `--json`.
2
3use serde::Serialize;
4use time::OffsetDateTime;
5
6pub fn json<T: Serialize>(v: &T) {
7    println!("{}", serde_json::to_string_pretty(v).expect("serializable"));
8}
9
10pub fn warn(msg: impl AsRef<str>) {
11    eprintln!("warning: {}", msg.as_ref());
12}
13
14/// `2026-09-25 14:03` in UTC.
15pub fn ts(t: OffsetDateTime) -> String {
16    let fmt = time::macros::format_description!("[year]-[month]-[day] [hour]:[minute]");
17    t.format(&fmt).unwrap_or_default()
18}
19
20pub fn size(bytes: u64) -> String {
21    match bytes {
22        b if b >= 1024 * 1024 => format!("{:.1} MB", b as f64 / (1024.0 * 1024.0)),
23        b if b >= 1024 => format!("{:.1} KB", b as f64 / 1024.0),
24        b => format!("{b} B"),
25    }
26}
27
28/// A person's name for printing on one line: control characters removed, square brackets
29/// turned into round ones (so a name can't end an event header like `[comment #12 from Ada]`
30/// early), cut at 80 characters.
31pub fn clean_name(name: &str) -> String {
32    name.chars()
33        .filter(|c| !c.is_control())
34        .map(|c| match c {
35            '[' => '(',
36            ']' => ')',
37            c => c,
38        })
39        .take(80)
40        .collect::<String>()
41        .trim()
42        .to_string()
43}