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 let mut cols = vec![];
25 for row in headers.iter().chain (rows.iter()) {
26 for (i, entry) in row.iter().enumerate() {
27 if cols.get (i).is_none() {
28 cols.push (vec![]);
29 }
30 let col = &mut cols[i];
31 col.push (entry.to_string());
32 }
33 }
34 let col_lens = cols.iter()
35 .map (|col| col.iter().map (|entry| entry.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 out.push_str (&format!("{:>col_width$}", entry))
52 } else {
53 out.push_str (&format!("{:col_width$}", entry))
54 }
55 out.push_str (&" ".repeat (spacing));
56 } else {
57 break
58 }
59 }
60 out.push ('\n');
61 }
62 out
63}