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)
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
80pub fn print_raw<T: serde::Serialize>(value: &T) {
82 println!("{}", serde_json::to_string_pretty(value).unwrap());
83}