1use std::{
8 fmt,
9 io::{IsTerminal, Stdout, Write, stdout},
10};
11
12use anyhow::{Context, Result};
13use serde::Serialize;
14
15use crate::clap::args::JsonFlag;
16
17pub trait PrintTable {
19 fn print(&self, writer: &mut dyn Write, table_max_width: Option<u16>) -> Result<()>;
22}
23
24pub trait Printer {
26 fn out<T: fmt::Display + Serialize>(&mut self, data: T) -> Result<()>;
28
29 fn is_json(&self) -> bool {
31 false
32 }
33}
34
35pub struct StdoutPrinter {
37 stdout: Stdout,
38 json: bool,
39}
40
41impl StdoutPrinter {
42 pub fn new(json: &JsonFlag) -> Self {
44 Self {
45 stdout: stdout(),
46 json: json.enabled,
47 }
48 }
49}
50
51impl Printer for StdoutPrinter {
52 fn out<T: fmt::Display + serde::Serialize>(&mut self, data: T) -> Result<()> {
53 if self.json {
54 if self.stdout.is_terminal() {
55 serde_json::to_writer_pretty(&mut self.stdout, &data)
56 .context("Print pretty JSON to stdout error")?;
57 writeln!(self.stdout)?;
58 } else {
59 serde_json::to_writer(&mut self.stdout, &data)
60 .context("Print JSON to stdout error")?;
61 }
62 } else {
63 write!(self.stdout, "{data}")?;
64 }
65
66 Ok(())
67 }
68
69 fn is_json(&self) -> bool {
70 self.json
71 }
72}
73
74#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
76pub struct Message {
77 message: String,
78}
79
80impl Message {
81 pub fn new(message: impl ToString) -> Self {
83 Self {
84 message: message.to_string(),
85 }
86 }
87}
88
89impl fmt::Display for Message {
90 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
91 writeln!(f, "{}", &self.message)
92 }
93}