ghostscope_ui/components/loading/
progress.rs1use ratatui::{
2 style::{Color, Style},
3 text::{Line, Span},
4 widgets::{Block, Borders, Gauge, Paragraph},
5 Frame,
6};
7
8use super::{LoadingProgress, ModuleState};
9
10pub struct ProgressRenderer;
12
13impl ProgressRenderer {
14 pub fn render_progress_bar(
16 f: &mut Frame,
17 area: ratatui::layout::Rect,
18 progress: &LoadingProgress,
19 ) {
20 let ratio = progress.progress_ratio();
21 let completed = progress.completed_count;
22 let total = progress.total_modules();
23
24 let progress_bar = Gauge::default()
25 .block(Block::default().borders(Borders::NONE))
26 .gauge_style(Style::default().fg(Color::Cyan))
27 .ratio(ratio)
28 .label(format!(
29 "{completed}/{total} modules ({}%)",
30 (ratio * 100.0) as u8
31 ));
32
33 f.render_widget(progress_bar, area);
34 }
35
36 pub fn render_recent_modules(
38 f: &mut Frame,
39 area: ratatui::layout::Rect,
40 progress: &LoadingProgress,
41 max_items: usize,
42 ) {
43 let recent = progress.recently_finished(max_items);
44 let mut lines = Vec::new();
45
46 for module in recent {
47 let path = if module.path.len() > 50 {
48 format!("...{}", &module.path[module.path.len() - 47..])
49 } else {
50 module.path.clone()
51 };
52
53 match &module.state {
54 ModuleState::Completed => {
55 if let Some(stats) = &module.stats {
56 let load_time = module.load_time.unwrap_or(0.0);
57 let line = Line::from(vec![
58 Span::styled("✅ ", Style::default().fg(Color::Green)),
59 Span::styled(path, Style::default().fg(Color::White)),
60 Span::styled(
61 format!(
62 " 📈 Functions: {} | Variables: {} | Types: {} | Time: {:.1}s",
63 stats.functions, stats.variables, stats.types, load_time
64 ),
65 Style::default().fg(Color::Gray),
66 ),
67 ]);
68 lines.push(line);
69 }
70 }
71 ModuleState::Failed(error) => {
72 let load_time = module.load_time.unwrap_or(0.0);
73 let line = Line::from(vec![
74 Span::styled("✗ ", Style::default().fg(Color::Red)),
75 Span::styled(path, Style::default().fg(Color::White)),
76 Span::styled(
77 format!(" ❌ Failed: {error} | Time: {load_time:.1}s"),
78 Style::default().fg(Color::Red),
79 ),
80 ]);
81 lines.push(line);
82 }
83 _ => {} }
85 }
86
87 if lines.is_empty() {
88 lines.push(Line::from(Span::styled(
89 "No modules processed yet...",
90 Style::default().fg(Color::DarkGray),
91 )));
92 }
93
94 let title = if progress.failed_count > 0 {
95 format!("📁 Recently processed: ({} failed)", progress.failed_count)
96 } else {
97 "📁 Recently loaded:".to_string()
98 };
99
100 let paragraph = Paragraph::new(lines).block(
101 Block::default()
102 .title(title)
103 .borders(Borders::NONE)
104 .title_style(Style::default().fg(Color::Yellow)),
105 );
106
107 f.render_widget(paragraph, area);
108 }
109
110 pub fn render_current_status(
112 f: &mut Frame,
113 area: ratatui::layout::Rect,
114 progress: &LoadingProgress,
115 ) {
116 let status_line = if let Some(current) = &progress.current_loading {
117 let path = if current.len() > 60 {
118 format!("...{}", ¤t[current.len() - 57..])
119 } else {
120 current.clone()
121 };
122 Line::from(vec![
123 Span::styled("⏳ Loading: ", Style::default().fg(Color::Yellow)),
124 Span::styled(path, Style::default().fg(Color::White)),
125 ])
126 } else {
127 Line::from(Span::styled(
128 "Waiting for next module...",
129 Style::default().fg(Color::DarkGray),
130 ))
131 };
132
133 let paragraph = Paragraph::new(status_line);
134 f.render_widget(paragraph, area);
135 }
136
137 pub fn render_stats(f: &mut Frame, area: ratatui::layout::Rect, progress: &LoadingProgress) {
139 let stats = progress.total_stats();
140 let elapsed = progress.elapsed_time();
141
142 let stats_line = Line::from(vec![
143 Span::styled("⏱️ Elapsed: ", Style::default().fg(Color::DarkGray)),
144 Span::styled(format!("{elapsed:.1}s"), Style::default().fg(Color::White)),
145 Span::styled(" | ", Style::default().fg(Color::DarkGray)),
146 Span::styled("📊 Total: ", Style::default().fg(Color::DarkGray)),
147 Span::styled(
148 format!(
149 "{} functions | {} variables | {} types",
150 stats.functions, stats.variables, stats.types
151 ),
152 Style::default().fg(Color::Cyan),
153 ),
154 ]);
155
156 let paragraph = Paragraph::new(stats_line);
157 f.render_widget(paragraph, area);
158 }
159}