vantage_cli_util/
table_display.rs1use comfy_table::{Attribute, Cell, Color, Table as ComfyTable};
2use indexmap::IndexMap;
3use vantage_dataset::prelude::ReadableValueSet;
4use vantage_table::prelude::ColumnLike;
5use vantage_table::table::Table;
6use vantage_table::traits::table_source::TableSource;
7use vantage_types::{Entity, Record, TerminalRender};
8
9fn hint_to_color(hint: &str) -> Option<Color> {
11 match hint {
12 "green" => Some(Color::Green),
13 "red" => Some(Color::Red),
14 "blue" => Some(Color::Blue),
15 "yellow" => Some(Color::Yellow),
16 "cyan" => Some(Color::Cyan),
17 "magenta" => Some(Color::Magenta),
18 _ => None,
19 }
20}
21
22fn render_cell<V: TerminalRender>(value: &V) -> Cell {
24 let text = value.render();
25 let mut cell = Cell::new(&text);
26
27 if let Some(hint) = value.color_hint() {
28 if hint == "dim" {
29 cell = cell.add_attribute(Attribute::Dim);
30 } else if let Some(color) = hint_to_color(hint) {
31 cell = cell.fg(color);
32 }
33 }
34
35 cell
36}
37
38pub async fn print_table<T, E>(table: &Table<T, E>) -> vantage_core::Result<()>
43where
44 T: TableSource,
45 T::Value: TerminalRender,
46 T::Id: std::fmt::Display,
47 E: Entity<T::Value>,
48{
49 let id_field = table.id_field().map(|col| col.name().to_string());
50 let records = table.list_values().await?;
51 render_records(&records, id_field.as_deref());
52 Ok(())
53}
54
55pub fn render_records<Id: std::fmt::Display, V: TerminalRender>(
60 records: &IndexMap<Id, Record<V>>,
61 id_field: Option<&str>,
62) {
63 if records.is_empty() {
64 println!("No records found.");
65 return;
66 }
67
68 let first_record = records.values().next().unwrap();
69 let columns: Vec<&String> = first_record
70 .keys()
71 .filter(|k| k.as_str() != "id" && Some(k.as_str()) != id_field)
72 .collect();
73
74 let mut table = ComfyTable::new();
75
76 let mut header = vec![Cell::new("id").add_attribute(Attribute::Bold)];
77 header.extend(
78 columns
79 .iter()
80 .map(|c| Cell::new(c).add_attribute(Attribute::Bold)),
81 );
82 table.set_header(header);
83
84 for (id, record) in records {
85 let mut row = vec![Cell::new(id)];
86 for col in &columns {
87 if let Some(value) = record.get(col.as_str()) {
88 row.push(render_cell(value));
89 } else {
90 row.push(Cell::new(""));
91 }
92 }
93 table.add_row(row);
94 }
95
96 println!("{table}");
97 println!("Found {} records", records.len());
98}