libcli_rs/output/
console.rs1use std::any::Any;
2use std::io::Write;
3
4use anyhow::Result;
5use inflector::Inflector;
6use prettytable::{format, Cell, Row, Table};
7use serde::{Deserialize, Serialize};
8use serde_json::Value;
9
10use crate::output::OutputTrait;
11
12pub struct ConsoleOutput;
13
14impl ConsoleOutput {
15 pub fn new() -> Self {
16 Self {}
17 }
18
19 fn display_obj(
20 &self,
21 table: &mut Table,
22 obj: &Value,
23 include_keys: &Option<Vec<&str>>,
24 exclude_keys: &Option<Vec<&str>>,
25 ) -> Result<()> {
26 let obj = obj.as_object().unwrap();
27
28 let predict_include_keys = |it: &(&String, &Value)| {
29 if let Some(keys) = include_keys {
30 keys.contains(&it.0.to_lowercase().as_str())
31 } else {
32 true
33 }
34 };
35
36 let predict_exclude_keys = |it: &(&String, &Value)| {
37 if let Some(keys) = exclude_keys {
38 !keys.contains(&it.0.to_lowercase().as_str())
39 } else {
40 true
41 }
42 };
43
44 if table.is_empty() {
45 let columns = obj
46 .iter()
47 .filter(predict_include_keys)
48 .filter(predict_exclude_keys)
49 .map(|it| Cell::new(&it.0.to_title_case()))
50 .collect();
51
52 table.add_row(Row::new(columns));
53 }
54
55 let column_values = obj
56 .iter()
57 .filter(predict_include_keys)
58 .filter(predict_exclude_keys)
59 .map(|it| Cell::new(&to_string_trim(it.1)))
60 .collect();
61
62 table.add_row(Row::new(column_values));
63
64 Ok(())
65 }
66}
67
68impl OutputTrait for ConsoleOutput {
69 fn display<'a, T: Deserialize<'a> + Serialize>(
70 &self,
71 writer: impl Write,
72 obj: &T,
73 include_keys: Option<Vec<&str>>,
74 exclude_keys: Option<Vec<&str>>,
75 ) -> Result<()> {
76 let mut writer = writer;
77 let obj = serde_json::to_value(obj)?;
78
79 let mut table = Table::new();
80 table.set_format(*format::consts::FORMAT_CLEAN);
81
82 match obj {
83 _ if obj.is_array() => {
84 for o in obj.as_array().unwrap() {
85 self.display_obj(&mut table, o, &include_keys, &exclude_keys)?;
86 }
87 }
88
89 _ if obj.is_object() => {
90 self.display_obj(&mut table, &obj, &include_keys, &exclude_keys)?;
91 }
92
93 _ => Err(anyhow!("Unsupported display type: {:?}", obj.type_id()))?,
94 };
95
96 table
97 .print(&mut writer)
98 .map(|_it| ())
99 .map_err(|it| anyhow!(it))
100 }
101}
102
103fn to_string_trim(v: &Value) -> String {
104 match v {
105 Value::Null => "".to_string(),
106 Value::String(s) => truncate_str(s),
107 Value::Bool(b) => b.to_string(),
108 _ => serde_yaml::to_string(v)
109 .unwrap()
110 .trim_start_matches("---\n")
111 .to_string(),
112 }
113}
114
115fn truncate_str(str: &String) -> String {
116 if str.len() > 100 {
117 format!("{}...", &str[0..100])
118 } else {
119 str.clone()
120 }
121}