add transcript mode (#2525)

this adds a new 'transcript mode' that shows the full event history in a
"pager"-style interface.


https://github.com/user-attachments/assets/52df7a14-adb2-4ea7-a0f9-7f5eb8235182
This commit is contained in:
Jeremy Rose
2025-08-20 16:57:35 -07:00
committed by GitHub
parent 050b9baeb6
commit 2ec5a28528
3 changed files with 247 additions and 2 deletions

View File

@@ -4,6 +4,7 @@ use crate::chatwidget::ChatWidget;
use crate::file_search::FileSearchManager;
use crate::get_git_diff::get_git_diff;
use crate::slash_command::SlashCommand;
use crate::transcript_app::run_transcript_app;
use crate::tui;
use crate::tui::TuiEvent;
use codex_core::ConversationManager;
@@ -16,6 +17,7 @@ use crossterm::event::KeyCode;
use crossterm::event::KeyEvent;
use crossterm::event::KeyEventKind;
use crossterm::terminal::supports_keyboard_enhancement;
use ratatui::text::Line;
use std::path::PathBuf;
use std::sync::Arc;
use std::sync::atomic::AtomicBool;
@@ -35,6 +37,8 @@ pub(crate) struct App {
file_search: FileSearchManager,
transcript_lines: Vec<Line<'static>>,
enhanced_keys_supported: bool,
/// Controls the animation thread that sends CommitTick events.
@@ -75,6 +79,7 @@ impl App {
config,
file_search,
enhanced_keys_supported,
transcript_lines: Vec::new(),
commit_anim_running: Arc::new(AtomicBool::new(false)),
};
@@ -102,7 +107,7 @@ impl App {
) -> Result<bool> {
match event {
TuiEvent::Key(key_event) => {
self.handle_key_event(key_event).await;
self.handle_key_event(tui, key_event).await;
}
TuiEvent::Paste(pasted) => {
// Many terminals convert newlines to \r when pasting (e.g., iTerm2),
@@ -136,6 +141,7 @@ impl App {
fn handle_event(&mut self, tui: &mut tui::Tui, event: AppEvent) -> Result<bool> {
match event {
AppEvent::InsertHistory(lines) => {
self.transcript_lines.extend(lines.clone());
tui.insert_history_lines(lines);
}
AppEvent::StartCommitAnimation => {
@@ -303,7 +309,7 @@ impl App {
self.chat_widget.token_usage().clone()
}
async fn handle_key_event(&mut self, key_event: KeyEvent) {
async fn handle_key_event(&mut self, tui: &mut tui::Tui, key_event: KeyEvent) {
match key_event {
KeyEvent {
code: KeyCode::Char('c'),
@@ -321,6 +327,14 @@ impl App {
} if self.chat_widget.composer_is_empty() => {
self.app_event_tx.send(AppEvent::ExitRequest);
}
KeyEvent {
code: KeyCode::Char('t'),
modifiers: crossterm::event::KeyModifiers::CONTROL,
kind: KeyEventKind::Press,
..
} => {
run_transcript_app(tui, self.transcript_lines.clone()).await;
}
KeyEvent {
kind: KeyEventKind::Press | KeyEventKind::Repeat,
..