gooey/widget/textbox/
make_table.rs1pub macro make_table {
4 ($([$($item:expr),+]),+$(, ($spacing:expr))?) => {
5 mk_table (
6 vec![],
7 vec![$(box_vec!($($item),+)),+]
8 $(,$spacing)?
9 )
10 }
11}
12
13pub macro box_vec {
14 ($($item:expr),*) => {
15 vec![$(Box::new ($item)),*]
16 }
17}
18
19pub fn mk_table (
20 headers : Vec <Vec <Box <dyn ToString>>>,
21 rows : Vec <Vec <Box <dyn ToString>>>,
22 spacing : usize
23) -> String {
24 use std::fmt::Write;
25 let mut cols = vec![];
26 for row in headers.iter().chain (rows.iter()) {
27 for (i, entry) in row.iter().enumerate() {
28 if cols.get (i).is_none() {
29 cols.push (vec![]);
30 }
31 let col = &mut cols[i];
32 col.push (entry.to_string());
33 }
34 }
35 let col_lens = cols.iter().map (|col| col.iter().map (String::len).max().unwrap_or (0))
36 .collect::<Vec <_>>();
37 let col_numeric = cols.iter().map (|col|
38 col.iter().skip (headers.len()).all (|entry| entry.parse::<f32>().is_ok())
39 ).collect::<Vec <_>>();
40 let mut out = String::new();
41 for (i, _) in headers.iter().chain (rows.iter()).enumerate() {
42 for (j, col) in cols.iter().enumerate() {
43 if let Some (entry) = col.get (i) {
44 let col_width = col_lens[j];
45 let col_num = if i < headers.len() {
46 false
47 } else {
48 col_numeric[j]
49 };
50 if col_num {
51 let _ = write!(out, "{entry:>col_width$}");
52 } else {
53 let _ = write!(out, "{entry:col_width$}");
54 }
55 out.push_str (&" ".repeat (spacing));
56 } else {
57 break
58 }
59 }
60 out.push ('\n');
61 }
62 out
63}