steer_tui/tui/widgets/chat_widgets/
command_response.rs1use crate::tui::theme::{Component, Theme};
2use crate::tui::widgets::chat_list_state::ViewMode;
3use crate::tui::widgets::chat_widgets::chat_widget::{ChatRenderable, HeightCache};
4use ratatui::text::{Line, Span};
5
6pub struct CommandResponseWidget {
8 command: String,
9 response: String,
10 cache: HeightCache,
11 rendered_lines: Option<Vec<Line<'static>>>,
12}
13
14impl CommandResponseWidget {
15 pub fn new(command: String, response: String) -> Self {
16 Self {
17 command,
18 response,
19 cache: HeightCache::new(),
20 rendered_lines: None,
21 }
22 }
23}
24
25impl ChatRenderable for CommandResponseWidget {
26 fn lines(&mut self, width: u16, _mode: ViewMode, theme: &Theme) -> &[Line<'static>] {
27 if self.rendered_lines.is_none() || self.cache.last_width != width {
28 let mut lines = vec![];
29 let wrap_width = width.saturating_sub(2) as usize;
30
31 let response_lines: Vec<&str> = self.response.lines().collect();
33
34 if response_lines.is_empty()
35 || (response_lines.len() == 1 && response_lines[0].len() <= 50)
36 {
37 let spans = vec![
39 Span::styled(self.command.clone(), theme.style(Component::CommandPrompt)),
40 Span::raw(": "),
41 Span::styled(self.response.clone(), theme.style(Component::CommandText)),
42 ];
43 lines.push(Line::from(spans));
44 } else {
45 lines.push(Line::from(vec![
47 Span::styled(self.command.clone(), theme.style(Component::CommandPrompt)),
48 Span::raw(":"),
49 ]));
50
51 for line in response_lines {
53 let wrapped = textwrap::wrap(line, wrap_width);
54 if wrapped.is_empty() {
55 lines.push(Line::from(""));
56 } else {
57 for wrapped_line in wrapped {
58 lines.push(Line::from(Span::styled(
59 wrapped_line.to_string(),
60 theme.style(Component::CommandText),
61 )));
62 }
63 }
64 }
65 }
66
67 self.rendered_lines = Some(lines);
68 }
69
70 self.rendered_lines.as_ref().unwrap()
71 }
72}
73
74#[cfg(test)]
75mod tests {
76 use super::*;
77
78 #[test]
79 fn test_command_response_widget_inline() {
80 let theme = Theme::default();
81 let mut widget = CommandResponseWidget::new("/help".to_string(), "Shows help".to_string());
82
83 let height = widget.lines(80, ViewMode::Compact, &theme).len();
84 assert_eq!(height, 1); }
86
87 #[test]
88 fn test_command_response_widget_multiline() {
89 let theme = Theme::default();
90 let mut widget =
91 CommandResponseWidget::new("/help".to_string(), "Line 1\nLine 2\nLine 3".to_string());
92
93 let height = widget.lines(80, ViewMode::Compact, &theme).len();
94 assert_eq!(height, 4); }
96}