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
36pub fn print_success<T, F>(ctx: Ctx, data: &T, human: F)
37where
38 T: serde::Serialize,
39 F: FnOnce(&T),
40{
41 match ctx.format {
42 Format::Json => {
43 let envelope = serde_json::json!({
44 "version": "1",
45 "status": "success",
46 "data": data,
47 });
48 println!("{}", serde_json::to_string_pretty(&envelope).unwrap());
49 }
50 Format::Human if !ctx.quiet => human(data),
51 Format::Human => {}
52 }
53}
54
55pub fn print_error(format: Format, err: &AppError) {
56 match format {
57 Format::Json => {
58 let envelope = serde_json::json!({
59 "version": "1",
60 "status": "error",
61 "error": {
62 "code": err.error_code(),
63 "message": err.to_string(),
64 "suggestion": err.suggestion(),
65 },
66 });
67 eprintln!("{}", serde_json::to_string_pretty(&envelope).unwrap());
68 }
69 Format::Human => {
70 eprintln!("error: {}", err);
71 let hint = err.suggestion();
72 if !hint.is_empty() {
73 eprintln!(" hint: {}", hint);
74 }
75 }
76 }
77}
78
79pub fn print_raw<T: serde::Serialize>(value: &T) {
80 println!("{}", serde_json::to_string_pretty(value).unwrap());
81}