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