Skip to main content

fur_cli/renderer/
table.rs

1use colored::*;
2
3/// `spaced` puts a blank line between rows. Right for a flat list, wrong for a
4/// nested one: in a tree the vertical gap competes with the indentation for the
5/// reader's sense of structure.
6pub fn render_table(
7    title: &str,
8    headers: &[&str],
9    rows: Vec<Vec<String>>,
10    active_idx: Option<usize>,
11    spaced: bool,
12) {
13    // Compute column widths
14    // Rust pads `{:width$}` by character count, so widths must be measured the
15    // same way. Byte length silently over-pads any cell containing box-drawing
16    // glyphs or accented text.
17    let width_of = |s: &str| s.chars().count();
18
19    let col_widths: Vec<usize> = headers
20        .iter()
21        .enumerate()
22        .map(|(i, h)| {
23            let max_cell = rows
24                .iter()
25                .map(|r| r.get(i).map(|s| width_of(s)).unwrap_or(0))
26                .max()
27                .unwrap_or(0);
28            max_cell.max(width_of(h))
29        })
30        .collect();
31
32    // Total table width
33    let total_width: usize = col_widths.iter().map(|w| w + 4).sum::<usize>() + 2;
34
35    // Top title bar
36    println!("{}", format!("=== {} ===", title).bold().bright_cyan());
37    println!("{}", "-".repeat(total_width));
38
39    // Header
40    let mut header_line = String::new();
41    for (i, h) in headers.iter().enumerate() {
42        header_line.push_str(&format!("{:width$}    ", h, width = col_widths[i]));
43    }
44    println!("{}", header_line.bold());
45    println!("{}", "=".repeat(total_width));
46
47    for (i, row) in rows.iter().enumerate() {
48        let mut line = String::new();
49        for (j, cell) in row.iter().enumerate() {
50            line.push_str(&format!("{:width$}    ", cell, width = col_widths[j]));
51        }
52
53        if Some(i) == active_idx {
54            println!("{}", line.bold().bright_yellow());
55        } else {
56            println!("{}", line);
57        }
58
59        if spaced {
60            println!();
61        }
62    }
63
64    // Bottom border
65    println!("{}", "-".repeat(total_width));
66}