Skip to main content

semantic_diff/ui/
summary.rs

1use crate::app::App;
2use ratatui::layout::Rect;
3use ratatui::style::{Color, Modifier, Style};
4use ratatui::text::{Line, Span};
5use ratatui::Frame;
6
7/// Render the summary bar at the bottom of the screen.
8pub fn render_summary(app: &App, frame: &mut Frame, area: Rect) {
9    let total_files = app.diff_data.files.len() + app.diff_data.binary_files.len();
10    let total_added: usize = app.diff_data.files.iter().map(|f| f.added_count).sum();
11    let total_removed: usize = app.diff_data.files.iter().map(|f| f.removed_count).sum();
12
13    let mut spans = vec![
14        Span::styled(
15            format!(" {total_files} file(s) changed  "),
16            Style::default().add_modifier(Modifier::BOLD),
17        ),
18        Span::styled(
19            format!("+{total_added}"),
20            Style::default()
21                .fg(Color::Green)
22                .add_modifier(Modifier::BOLD),
23        ),
24        Span::styled(
25            format!(" -{total_removed}"),
26            Style::default()
27                .fg(Color::Red)
28                .add_modifier(Modifier::BOLD),
29        ),
30    ];
31
32    if !app.diff_data.binary_files.is_empty() {
33        spans.push(Span::styled(
34            format!(" ({} binary)", app.diff_data.binary_files.len()),
35            Style::default().fg(Color::Yellow),
36        ));
37    }
38
39    // Show active filter indicator
40    if let Some(ref filter) = app.active_filter {
41        spans.push(Span::styled(
42            format!("  [filter: {filter}]"),
43            Style::default()
44                .fg(Color::Cyan)
45                .add_modifier(Modifier::BOLD),
46        ));
47    }
48
49    // Show grouping status
50    use crate::grouper::GroupingStatus;
51    match &app.grouping_status {
52        GroupingStatus::Loading => {
53            spans.push(Span::styled(
54                " | Grouping...",
55                Style::default().fg(Color::Yellow),
56            ));
57        }
58        GroupingStatus::Done => {
59            if let Some(ref groups) = app.semantic_groups {
60                spans.push(Span::styled(
61                    format!(" | {} groups", groups.len()),
62                    Style::default().fg(Color::Cyan),
63                ));
64            }
65        }
66        GroupingStatus::Error(_) => {
67            spans.push(Span::styled(
68                " | Ungrouped",
69                Style::default().fg(Color::DarkGray),
70            ));
71        }
72        GroupingStatus::Idle => {} // nothing extra
73    }
74
75    // Show preview mode indicator
76    if app.preview_mode {
77        spans.push(Span::styled(
78            " | Preview",
79            Style::default()
80                .fg(Color::Black)
81                .bg(Color::Cyan)
82                .add_modifier(Modifier::BOLD),
83        ));
84    } else {
85        spans.push(Span::styled(
86            " | Raw",
87            Style::default().fg(Color::DarkGray),
88        ));
89    }
90
91    // Right-align the shortcut hint
92    spans.push(Span::styled(
93        "  ? help",
94        Style::default().fg(Color::DarkGray),
95    ));
96
97    let line = Line::from(spans);
98    let paragraph = ratatui::widgets::Paragraph::new(line);
99    frame.render_widget(paragraph, area);
100}