From 50e0db431f3ebf50c1f96f46f17ed32939aeeec3 Mon Sep 17 00:00:00 2001 From: Ahmed Ibrahim Date: Fri, 22 Aug 2025 10:56:58 -0700 Subject: [PATCH] refactor --- codex-rs/tui/src/app_backtrack.rs | 75 ++++++++++++++------------- codex-rs/tui/src/backtrack_helpers.rs | 50 +++++++++--------- 2 files changed, 65 insertions(+), 60 deletions(-) diff --git a/codex-rs/tui/src/app_backtrack.rs b/codex-rs/tui/src/app_backtrack.rs index 7e39de6217..f1d5196131 100644 --- a/codex-rs/tui/src/app_backtrack.rs +++ b/codex-rs/tui/src/app_backtrack.rs @@ -12,6 +12,8 @@ use crossterm::terminal::EnterAlternateScreen; use crossterm::terminal::LeaveAlternateScreen; impl App { + // Public entrypoints first (most important) + /// Route TUI events to the overlay when present, handling backtrack preview /// interactions (Esc to step target, Enter to confirm) and overlay lifecycle. pub(crate) async fn handle_backtrack_overlay_event( @@ -141,41 +143,7 @@ impl App { } } - /// Re-render the full transcript into the terminal scrollback in one call. - /// Useful when switching sessions to ensure prior history remains visible. - pub(crate) fn render_transcript_once(&mut self, tui: &mut tui::Tui) { - if !self.transcript_lines.is_empty() { - tui.insert_history_lines(self.transcript_lines.clone()); - } - } - - pub(crate) fn open_transcript_overlay(&mut self, tui: &mut tui::Tui) { - // Enter alternate screen and set viewport to full size. - let _ = execute!(tui.terminal.backend_mut(), EnterAlternateScreen); - if let Ok(size) = tui.terminal.size() { - self.transcript_saved_viewport = Some(tui.terminal.viewport_area); - tui.terminal - .set_viewport_area(ratatui::layout::Rect::new(0, 0, size.width, size.height)); - let _ = tui.terminal.clear(); - } - self.transcript_overlay = Some(TranscriptApp::new(self.transcript_lines.clone())); - tui.frame_requester().schedule_frame(); - } - - pub(crate) fn close_transcript_overlay(&mut self, tui: &mut tui::Tui) { - // Exit alternate screen and restore viewport. - let _ = execute!(tui.terminal.backend_mut(), LeaveAlternateScreen); - if let Some(saved) = self.transcript_saved_viewport.take() { - tui.terminal.set_viewport_area(saved); - } - if !self.deferred_history_lines.is_empty() { - let lines = std::mem::take(&mut self.deferred_history_lines); - tui.insert_history_lines(lines); - } - self.transcript_overlay = None; - self.transcript_overlay_is_backtrack = false; - } - + /// Fork the conversation and render the trimmed history; prefill composer. pub(crate) async fn fork_and_render_backtrack( &mut self, tui: &mut tui::Tui, @@ -222,4 +190,41 @@ impl App { tui.frame_requester().schedule_frame(); Ok(()) } + + // Internal helpers + + pub(crate) fn open_transcript_overlay(&mut self, tui: &mut tui::Tui) { + // Enter alternate screen and set viewport to full size. + let _ = execute!(tui.terminal.backend_mut(), EnterAlternateScreen); + if let Ok(size) = tui.terminal.size() { + self.transcript_saved_viewport = Some(tui.terminal.viewport_area); + tui.terminal + .set_viewport_area(ratatui::layout::Rect::new(0, 0, size.width, size.height)); + let _ = tui.terminal.clear(); + } + self.transcript_overlay = Some(TranscriptApp::new(self.transcript_lines.clone())); + tui.frame_requester().schedule_frame(); + } + + pub(crate) fn close_transcript_overlay(&mut self, tui: &mut tui::Tui) { + // Exit alternate screen and restore viewport. + let _ = execute!(tui.terminal.backend_mut(), LeaveAlternateScreen); + if let Some(saved) = self.transcript_saved_viewport.take() { + tui.terminal.set_viewport_area(saved); + } + if !self.deferred_history_lines.is_empty() { + let lines = std::mem::take(&mut self.deferred_history_lines); + tui.insert_history_lines(lines); + } + self.transcript_overlay = None; + self.transcript_overlay_is_backtrack = false; + } + + /// Re-render the full transcript into the terminal scrollback in one call. + /// Useful when switching sessions to ensure prior history remains visible. + pub(crate) fn render_transcript_once(&mut self, tui: &mut tui::Tui) { + if !self.transcript_lines.is_empty() { + tui.insert_history_lines(self.transcript_lines.clone()); + } + } } diff --git a/codex-rs/tui/src/backtrack_helpers.rs b/codex-rs/tui/src/backtrack_helpers.rs index 64e42d435c..d129ab6fb7 100644 --- a/codex-rs/tui/src/backtrack_helpers.rs +++ b/codex-rs/tui/src/backtrack_helpers.rs @@ -1,5 +1,26 @@ use ratatui::text::Line; +// Public helpers (most important first) + +/// Convenience: compute the highlight range for the Nth last user message. +pub(crate) fn highlight_range_for_nth_last_user( + lines: &[Line<'_>], + n: usize, +) -> Option<(usize, usize)> { + let header = find_nth_last_user_header_index(lines, n)?; + Some(highlight_range_from_header(lines, header)) +} + +/// Compute the wrapped display-line offset before `header_idx`, for a given width. +pub(crate) fn wrapped_offset_before( + lines: &[Line<'_>], + header_idx: usize, + width: u16, +) -> usize { + let before = &lines[0..header_idx]; + crate::insert_history::word_wrap_lines(before, width).len() +} + /// Find the header index for the Nth last user message in the transcript. /// Returns `None` if `n == 0` or there are fewer than `n` user messages. pub(crate) fn find_nth_last_user_header_index(lines: &[Line<'_>], n: usize) -> Option { @@ -32,11 +53,10 @@ pub(crate) fn nth_last_user_text(lines: &[Line<'_>], n: usize) -> Option extract_message_text_after_header(lines, header_idx) } +// Private helpers + /// Extract message text starting after `header_idx` until the first blank line. -pub(crate) fn extract_message_text_after_header( - lines: &[Line<'_>], - header_idx: usize, -) -> Option { +fn extract_message_text_after_header(lines: &[Line<'_>], header_idx: usize) -> Option { let start = header_idx + 1; let mut out: Vec = Vec::new(); for line in lines.iter().skip(start) { @@ -58,20 +78,10 @@ pub(crate) fn extract_message_text_after_header( if out.is_empty() { None } else { Some(out.join("\n")) } } -/// Compute the wrapped display-line offset before `header_idx`, for a given width. -pub(crate) fn wrapped_offset_before( - lines: &[Line<'_>], - header_idx: usize, - width: u16, -) -> usize { - let before = &lines[0..header_idx]; - crate::insert_history::word_wrap_lines(before, width).len() -} - /// Given a header index, return the inclusive range for the message block /// [header_idx, end) where end is the first blank line after the header or the /// end of the transcript. -pub(crate) fn highlight_range_from_header(lines: &[Line<'_>], header_idx: usize) -> (usize, usize) { +fn highlight_range_from_header(lines: &[Line<'_>], header_idx: usize) -> (usize, usize) { let mut end = header_idx + 1; while end < lines.len() { let is_blank = lines[end] @@ -85,13 +95,3 @@ pub(crate) fn highlight_range_from_header(lines: &[Line<'_>], header_idx: usize) } (header_idx, end) } - -/// Convenience: compute the highlight range for the Nth last user message. -pub(crate) fn highlight_range_for_nth_last_user( - lines: &[Line<'_>], - n: usize, -) -> Option<(usize, usize)> { - let header = find_nth_last_user_header_index(lines, n)?; - Some(highlight_range_from_header(lines, header)) -} -