1use bitwarden_cli::Color;
2use clap::ValueEnum;
3
4use crate::command::Cli;
5
6#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, ValueEnum, Debug)]
7#[allow(clippy::upper_case_acronyms)]
8pub(crate) enum Output {
9 JSON,
10 YAML,
11 Table,
12 TSV,
13 None,
14}
15
16pub enum CommandOutput {
17 Plain(String),
18 Object(Box<dyn erased_serde::Serialize>),
19}
20pub type CommandResult = color_eyre::eyre::Result<CommandOutput>;
21
22impl From<&str> for CommandOutput {
23 fn from(text: &str) -> Self {
24 CommandOutput::Plain(text.to_owned())
25 }
26}
27impl From<String> for CommandOutput {
28 fn from(text: String) -> Self {
29 CommandOutput::Plain(text)
30 }
31}
32impl From<()> for CommandOutput {
33 fn from(_: ()) -> Self {
34 CommandOutput::Plain(String::new())
35 }
36}
37
38pub struct RenderConfig {
39 pub output: Output,
40 pub color: Color,
41 pub cleanexit: bool,
42 pub quiet: bool,
43}
44
45impl RenderConfig {
46 pub fn new(cli: &Cli) -> Self {
47 Self {
48 output: cli.output,
49 color: cli.color,
50 cleanexit: cli.cleanexit,
51 quiet: cli.quiet,
52 }
53 }
54
55 pub fn render_result(&self, result: CommandResult) -> color_eyre::eyre::Result<()> {
56 if self.quiet || self.output == Output::None {
57 return Ok(());
58 }
59
60 fn pretty_print(language: &str, data: &str, color: Color) {
61 if color.is_enabled() {
62 bat::PrettyPrinter::new()
63 .input_from_bytes(data.as_bytes())
64 .language(language)
65 .print()
66 .expect("Input is valid");
67 } else {
68 print!("{}", data);
69 }
70 }
71
72 match result {
73 Err(e) => Err(e),
75
76 Ok(_) if self.cleanexit => Ok(()),
78
79 Ok(CommandOutput::Plain(text)) => {
81 println!("{}", text);
82 Ok(())
83 }
84
85 Ok(CommandOutput::Object(obj)) => {
87 match self.output {
88 Output::JSON => {
89 let mut json = serde_json::to_string_pretty(&*obj)?;
90 json.push('\n');
93 pretty_print("json", &json, self.color);
94 }
95 Output::YAML => {
96 let yaml = serde_yaml::to_string(&*obj)?;
97 pretty_print("yaml", &yaml, self.color);
98 }
99 Output::Table => {
100 todo!()
101 }
102 Output::TSV => {
103 todo!()
104 }
105 Output::None => unreachable!(),
106 }
107 Ok(())
108 }
109 }
110 }
111}