codetether_agent/tui/ui/chat_view/
streaming.rs1use std::cell::RefCell;
9
10use ratatui::{
11 style::{Color, Modifier, Style},
12 text::{Line, Span},
13};
14
15use crate::tui::app::state::AppState;
16use crate::tui::message_formatter::MessageFormatter;
17use crate::tui::ui::status_bar::format_timestamp;
18
19const STREAM_REPARSE_THRESHOLD: usize = 48;
22
23thread_local! {
24 static STREAM_PARSE_CACHE: RefCell<Option<(usize, Vec<Line<'static>>)>> =
27 const { RefCell::new(None) };
28}
29
30pub fn push_streaming_preview(
39 lines: &mut Vec<Line<'static>>,
40 state: &AppState,
41 separator_width: usize,
42 formatter: &MessageFormatter,
43) {
44 if !state.processing || state.streaming_text.is_empty() {
45 return;
46 }
47 lines.push(Line::from(Span::styled(
48 "─".repeat(separator_width.min(40)),
49 Style::default().fg(Color::DarkGray).dim(),
50 )));
51 lines.push(Line::from(vec![
52 Span::styled(
53 format!("[{}] ", format_timestamp(std::time::SystemTime::now())),
54 Style::default().fg(Color::DarkGray).dim(),
55 ),
56 Span::styled("◆ ", Style::default().fg(Color::Cyan).bold()),
57 Span::styled("assistant", Style::default().fg(Color::Cyan).bold()),
58 Span::styled(
59 " (streaming…)",
60 Style::default()
61 .fg(Color::DarkGray)
62 .add_modifier(Modifier::DIM),
63 ),
64 ]));
65 let formatted = cached_format(&state.streaming_text, formatter);
66 for line in formatted {
67 let mut spans = vec![Span::styled(" ", Style::default().fg(Color::Cyan))];
68 spans.extend(line.spans);
69 lines.push(Line::from(spans));
70 }
71}
72
73fn cached_format(text: &str, formatter: &MessageFormatter) -> Vec<Line<'static>> {
74 STREAM_PARSE_CACHE.with(|cell| {
75 let cur_len = text.len();
76 if let Some((parsed_len, ref lines)) = *cell.borrow()
77 && cur_len >= parsed_len
78 && cur_len - parsed_len < STREAM_REPARSE_THRESHOLD
79 {
80 return lines.clone();
81 }
82 let formatted = formatter.format_content(text, "assistant");
83 *cell.borrow_mut() = Some((cur_len, formatted.clone()));
84 formatted
85 })
86}
87
88pub fn reset_stream_parse_cache() {
92 STREAM_PARSE_CACHE.with(|cell| *cell.borrow_mut() = None);
93}