2025-08-12 17:37:28 -07:00
|
|
|
use crate::markdown_stream::AnimatedLineStreamer;
|
|
|
|
|
use crate::markdown_stream::MarkdownStreamCollector;
|
|
|
|
|
pub(crate) mod controller;
|
|
|
|
|
|
|
|
|
|
pub(crate) struct StreamState {
|
|
|
|
|
pub(crate) collector: MarkdownStreamCollector,
|
|
|
|
|
pub(crate) streamer: AnimatedLineStreamer,
|
2025-08-13 18:39:58 -07:00
|
|
|
pub(crate) has_seen_delta: bool,
|
2025-08-12 17:37:28 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl StreamState {
|
|
|
|
|
pub(crate) fn new() -> Self {
|
|
|
|
|
Self {
|
|
|
|
|
collector: MarkdownStreamCollector::new(),
|
|
|
|
|
streamer: AnimatedLineStreamer::new(),
|
2025-08-13 18:39:58 -07:00
|
|
|
has_seen_delta: false,
|
2025-08-12 17:37:28 -07:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
pub(crate) fn clear(&mut self) {
|
|
|
|
|
self.collector.clear();
|
|
|
|
|
self.streamer.clear();
|
2025-08-13 18:39:58 -07:00
|
|
|
self.has_seen_delta = false;
|
2025-08-12 17:37:28 -07:00
|
|
|
}
|
|
|
|
|
pub(crate) fn step(&mut self) -> crate::markdown_stream::StepResult {
|
|
|
|
|
self.streamer.step()
|
|
|
|
|
}
|
|
|
|
|
pub(crate) fn drain_all(&mut self) -> crate::markdown_stream::StepResult {
|
|
|
|
|
self.streamer.drain_all()
|
|
|
|
|
}
|
|
|
|
|
pub(crate) fn is_idle(&self) -> bool {
|
|
|
|
|
self.streamer.is_idle()
|
|
|
|
|
}
|
|
|
|
|
pub(crate) fn enqueue(&mut self, lines: Vec<ratatui::text::Line<'static>>) {
|
|
|
|
|
self.streamer.enqueue(lines)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub(crate) struct HeaderEmitter {
|
2025-08-20 16:58:56 -07:00
|
|
|
emitted_this_turn: bool,
|
|
|
|
|
emitted_in_stream: bool,
|
2025-08-12 17:37:28 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl HeaderEmitter {
|
|
|
|
|
pub(crate) fn new() -> Self {
|
|
|
|
|
Self {
|
2025-08-20 16:58:56 -07:00
|
|
|
emitted_this_turn: false,
|
|
|
|
|
emitted_in_stream: false,
|
2025-08-12 17:37:28 -07:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub(crate) fn reset_for_new_turn(&mut self) {
|
2025-08-20 16:58:56 -07:00
|
|
|
self.emitted_this_turn = false;
|
|
|
|
|
self.emitted_in_stream = false;
|
2025-08-12 17:37:28 -07:00
|
|
|
}
|
|
|
|
|
|
2025-08-20 16:58:56 -07:00
|
|
|
pub(crate) fn reset_for_stream(&mut self) {
|
|
|
|
|
self.emitted_in_stream = false;
|
2025-08-12 17:37:28 -07:00
|
|
|
}
|
|
|
|
|
|
2025-08-20 16:58:56 -07:00
|
|
|
/// Allow emitting the header again within the current turn after a finalize.
|
|
|
|
|
pub(crate) fn allow_reemit_in_turn(&mut self) {
|
|
|
|
|
self.emitted_this_turn = false;
|
2025-08-12 17:37:28 -07:00
|
|
|
}
|
|
|
|
|
|
2025-08-20 16:58:56 -07:00
|
|
|
pub(crate) fn maybe_emit(&mut self, out_lines: &mut Vec<ratatui::text::Line<'static>>) -> bool {
|
|
|
|
|
if !self.emitted_in_stream && !self.emitted_this_turn {
|
2025-08-22 16:32:31 -07:00
|
|
|
// Add a leading blank line before the header for visual spacing
|
|
|
|
|
out_lines.push(ratatui::text::Line::from(""));
|
2025-08-20 16:58:56 -07:00
|
|
|
out_lines.push(render_header_line());
|
|
|
|
|
self.emitted_in_stream = true;
|
|
|
|
|
self.emitted_this_turn = true;
|
|
|
|
|
return true;
|
2025-08-12 17:37:28 -07:00
|
|
|
}
|
2025-08-20 16:58:56 -07:00
|
|
|
false
|
2025-08-12 17:37:28 -07:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2025-08-20 16:58:56 -07:00
|
|
|
fn render_header_line() -> ratatui::text::Line<'static> {
|
2025-08-12 17:37:28 -07:00
|
|
|
use ratatui::style::Stylize;
|
2025-08-20 16:58:56 -07:00
|
|
|
ratatui::text::Line::from("codex".magenta().bold())
|
2025-08-12 17:37:28 -07:00
|
|
|
}
|