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 pub active_tool: Option<String>,
26}
27
28impl<'a> Widget for StatusLineWidget<'a> {
29 fn render(self, area: Rect, buf: &mut Buffer) {
30 if area.height == 0 || area.width < 10 {
32 return;
33 }
34
35 if self.status == GenerationStatus::Idle {
37 return;
38 }
39
40 let status_text = match (&self.status, &self.active_tool) {
43 (GenerationStatus::RunningTools, Some(tool)) => {
44 format!("{}: {}", self.status.display_text(), tool)
45 },
46 _ => self.status.display_text().to_string(),
47 };
48
49 let info_color = self.theme.colors.info.to_color();
50
51 let (arrow, flow_direction) = match self.status {
53 GenerationStatus::Sending | GenerationStatus::Thinking => ("↑ ", "upstream"),
54 GenerationStatus::Streaming => ("↓ ", "downstream"),
55 GenerationStatus::RunningTools => ("• ", "tools"),
56 GenerationStatus::Compacting => ("• ", "compaction"),
57 GenerationStatus::Cancelling => ("• ", "cleanup"),
58 GenerationStatus::Idle => ("", ""),
59 };
60
61 let spans = vec![
62 Span::styled(arrow, Style::new().fg(info_color)),
64 Span::styled(format!("{}... ", status_text), Style::new().fg(info_color)),
66 Span::styled(
69 format!(
70 "(esc to interrupt • {}s • {} {}{} tokens)",
71 self.elapsed_secs,
72 if flow_direction == "downstream" {
73 "↓"
74 } else if flow_direction == "tools" {
75 "tools"
76 } else if flow_direction == "compaction" {
77 "compact"
78 } else if flow_direction == "cleanup" {
79 "cleanup"
80 } else {
81 "↑"
82 },
83 if self.tokens_estimated { "~" } else { "" },
84 self.tokens_received
85 ),
86 Style::new()
87 .fg(self.theme.colors.text_secondary.to_color())
88 .dim(),
89 ),
90 ];
91
92 let mut lines = vec![Line::from(spans)];
93
94 let max_len = area.width.saturating_sub(4) as usize;
96 for queued in self.queued_messages.iter() {
97 let display_msg = if queued.len() > max_len {
99 let end = queued.floor_char_boundary(max_len.saturating_sub(3));
100 format!("> {}...", &queued[..end])
101 } else {
102 format!("> {}", queued)
103 };
104
105 lines.push(Line::from(vec![Span::styled(
106 display_msg,
107 Style::new()
108 .fg(self.theme.colors.text_primary.to_color())
109 .bg(ratatui::style::Color::Rgb(60, 60, 80)), )]));
111 }
112
113 let paragraph = Paragraph::new(lines);
114
115 paragraph.render(area, buf);
116 }
117}