Skip to main content

invoice_cli/
output.rs

1use std::io::IsTerminal;
2
3use crate::error::AppError;
4
5#[derive(Clone, Copy, Debug)]
6pub enum Format {
7    Json,
8    Human,
9}
10
11impl Format {
12    pub fn detect(json_flag: bool) -> Self {
13        if json_flag || !std::io::stdout().is_terminal() {
14            Format::Json
15        } else {
16            Format::Human
17        }
18    }
19}
20
21#[derive(Clone, Copy)]
22pub struct Ctx {
23    pub format: Format,
24    pub quiet: bool,
25}
26
27impl Ctx {
28    pub fn new(json_flag: bool, quiet: bool) -> Self {
29        Self {
30            format: Format::detect(json_flag),
31            quiet,
32        }
33    }
34}
35
36/// Print a success envelope (JSON) or call the human formatter (TTY).
37pub fn print_success<T, F>(ctx: Ctx, data: &T, human: F)
38where
39    T: serde::Serialize,
40    F: FnOnce(&T),
41{
42    match ctx.format {
43        Format::Json => {
44            let envelope = serde_json::json!({
45                "version": "1",
46                "status": "success",
47                "data": data,
48            });
49            println!("{}", serde_json::to_string_pretty(&envelope).unwrap());
50        }
51        Format::Human if !ctx.quiet => human(data),
52        Format::Human => {}
53    }
54}
55
56pub fn print_error(format: Format, err: &AppError) {
57    match format {
58        Format::Json => {
59            let envelope = serde_json::json!({
60                "version": "1",
61                "status": "error",
62                "error": {
63                    "code": err.error_code(),
64                    "message": err.to_string(),
65                    "suggestion": err.suggestion(),
66                },
67            });
68            eprintln!("{}", serde_json::to_string_pretty(&envelope).unwrap());
69        }
70        Format::Human => {
71            eprintln!("error: {}", err);
72            let hint = err.suggestion();
73            if !hint.is_empty() {
74                eprintln!("  hint: {}", hint);
75            }
76        }
77    }
78}
79
80/// Emit a raw JSON value on stdout (used by agent-info — unwrapped manifest).
81pub fn print_raw<T: serde::Serialize>(value: &T) {
82    println!("{}", serde_json::to_string_pretty(value).unwrap());
83}