composition_cli/display/
mod.rs

1use colored::Colorize;
2
3use crate::{context::AppContext, core::CompositionEntry};
4
5pub mod spinner;
6
7pub fn display_composition(
8    app_context: &AppContext,
9    composition_entries: &mut Vec<CompositionEntry>,
10) {
11    // reorder based on line count
12    composition_entries.sort_by_key(|e| std::cmp::Reverse(e.line_count));
13
14    let total_lines: usize = composition_entries.iter().map(|e| e.line_count).sum();
15    composition_entries.iter_mut().for_each(|e| {
16        let percentage = (e.line_count as f32 / total_lines as f32) * 100.0;
17        e.percentage = percentage;
18    });
19
20    let max_display_width = composition_entries
21        .iter()
22        .map(|e| e.tracked.display.len())
23        .max()
24        .unwrap_or(20);
25
26    let max_lines_width = composition_entries
27        .iter()
28        .map(|e| e.line_count.ilog10() + 1)
29        .max()
30        .unwrap_or(10) as usize;
31
32    for entry in composition_entries {
33        if entry.line_count == 0 {
34            continue;
35        }
36
37        // set bar width and color
38        // divide by 2 to set max_width to 50 instead of 100
39        let bar_width = (entry.percentage * app_context.scale_bar / 2.0).round() as usize;
40        let bar = "█".repeat(bar_width);
41        let bar = match (app_context.config.use_color, &entry.tracked.color) {
42            (true, Some(hex)) => {
43                if let Some((r, g, b)) = hex_to_rgb(hex) {
44                    bar.truecolor(r, g, b)
45                } else {
46                    bar.normal()
47                }
48            }
49            (true, None) | (false, _) => bar.normal(),
50        };
51
52        println!(
53            "{:>width_display$} | {:>width_lines$} lines | {:>5.2}% | {}",
54            entry.tracked.display,
55            entry.line_count,
56            entry.percentage,
57            bar,
58            width_display = max_display_width + 1,
59            width_lines = max_lines_width,
60        );
61    }
62}
63
64fn hex_to_rgb(hex: &str) -> Option<(u8, u8, u8)> {
65    let hex = hex.trim_start_matches('#');
66    if hex.len() != 6 {
67        return None;
68    }
69
70    let r = u8::from_str_radix(&hex[0..2], 16).ok()?;
71    let g = u8::from_str_radix(&hex[2..4], 16).ok()?;
72    let b = u8::from_str_radix(&hex[4..6], 16).ok()?;
73
74    Some((r, g, b))
75}