mermaid_cli/render/widgets/
status_line.rs1use ratatui::{
2 buffer::Buffer,
3 layout::Rect,
4 style::Style,
5 text::{Line, Span},
6 widgets::{Paragraph, Widget},
7};
8use std::collections::VecDeque;
9
10use super::GenerationStatus;
11use crate::render::theme::Theme;
12
13pub struct StatusLineWidget<'a> {
15 pub status: GenerationStatus,
16 pub elapsed_secs: u64,
17 pub tokens_received: usize,
18 pub tokens_estimated: bool,
20 pub theme: &'a Theme,
21 pub queued_messages: &'a VecDeque<String>,
23}
24
25impl<'a> Widget for StatusLineWidget<'a> {
26 fn render(self, area: Rect, buf: &mut Buffer) {
27 if area.height == 0 || area.width < 10 {
29 return;
30 }
31
32 if self.status == GenerationStatus::Idle {
34 return;
35 }
36
37 let status_text = self.status.display_text();
38
39 let info_color = self.theme.colors.info.to_color();
40
41 let (arrow, flow_direction) = match self.status {
43 GenerationStatus::Sending | GenerationStatus::Thinking => ("↑ ", "upstream"),
44 GenerationStatus::Streaming => ("↓ ", "downstream"),
45 GenerationStatus::RunningTools => ("• ", "tools"),
46 GenerationStatus::Compacting => ("• ", "compaction"),
47 GenerationStatus::Cancelling => ("• ", "cleanup"),
48 GenerationStatus::Idle => ("", ""),
49 };
50
51 let spans = vec![
52 Span::styled(arrow, Style::new().fg(info_color)),
54 Span::styled(format!("{}... ", status_text), Style::new().fg(info_color)),
56 Span::styled(
59 format!(
60 "(esc to interrupt • {}s • {} {}{} tokens)",
61 self.elapsed_secs,
62 if flow_direction == "downstream" {
63 "↓"
64 } else if flow_direction == "tools" {
65 "tools"
66 } else if flow_direction == "compaction" {
67 "compact"
68 } else if flow_direction == "cleanup" {
69 "cleanup"
70 } else {
71 "↑"
72 },
73 if self.tokens_estimated { "~" } else { "" },
74 self.tokens_received
75 ),
76 Style::new()
77 .fg(self.theme.colors.text_secondary.to_color())
78 .dim(),
79 ),
80 ];
81
82 let mut lines = vec![Line::from(spans)];
83
84 let max_len = area.width.saturating_sub(4) as usize;
86 for queued in self.queued_messages.iter() {
87 let display_msg = if queued.len() > max_len {
89 let end = queued.floor_char_boundary(max_len.saturating_sub(3));
90 format!("> {}...", &queued[..end])
91 } else {
92 format!("> {}", queued)
93 };
94
95 lines.push(Line::from(vec![Span::styled(
96 display_msg,
97 Style::new()
98 .fg(self.theme.colors.text_primary.to_color())
99 .bg(ratatui::style::Color::Rgb(60, 60, 80)), )]));
101 }
102
103 let paragraph = Paragraph::new(lines);
104
105 paragraph.render(area, buf);
106 }
107}