tui: fix backtracking past /status (#6335)

Fixes https://github.com/openai/codex/issues/4722

Supersedes https://github.com/openai/codex/pull/5058

Ideally we'd have a clearer way of separating history per-session than
by detecting a specific history cell type, but this is a fairly minimal
fix for now.
This commit is contained in:
Jeremy Rose
2025-11-06 14:50:07 -08:00
committed by GitHub
parent 65d53fd4b1
commit 1bd2d7a659
2 changed files with 23 additions and 6 deletions

View File

@@ -3,7 +3,7 @@ use std::path::PathBuf;
use std::sync::Arc; use std::sync::Arc;
use crate::app::App; use crate::app::App;
use crate::history_cell::CompositeHistoryCell; use crate::history_cell::SessionInfoCell;
use crate::history_cell::UserHistoryCell; use crate::history_cell::UserHistoryCell;
use crate::pager_overlay::Overlay; use crate::pager_overlay::Overlay;
use crate::tui; use crate::tui;
@@ -394,13 +394,13 @@ fn nth_user_position(
fn user_positions_iter( fn user_positions_iter(
cells: &[Arc<dyn crate::history_cell::HistoryCell>], cells: &[Arc<dyn crate::history_cell::HistoryCell>],
) -> impl Iterator<Item = usize> + '_ { ) -> impl Iterator<Item = usize> + '_ {
let header_type = TypeId::of::<CompositeHistoryCell>(); let session_start_type = TypeId::of::<SessionInfoCell>();
let user_type = TypeId::of::<UserHistoryCell>(); let user_type = TypeId::of::<UserHistoryCell>();
let type_of = |cell: &Arc<dyn crate::history_cell::HistoryCell>| cell.as_any().type_id(); let type_of = |cell: &Arc<dyn crate::history_cell::HistoryCell>| cell.as_any().type_id();
let start = cells let start = cells
.iter() .iter()
.rposition(|cell| type_of(cell) == header_type) .rposition(|cell| type_of(cell) == session_start_type)
.map_or(0, |idx| idx + 1); .map_or(0, |idx| idx + 1);
cells cells

View File

@@ -559,11 +559,28 @@ pub(crate) fn padded_emoji(emoji: &str) -> String {
format!("{emoji}\u{200A}") format!("{emoji}\u{200A}")
} }
#[derive(Debug)]
pub struct SessionInfoCell(CompositeHistoryCell);
impl HistoryCell for SessionInfoCell {
fn display_lines(&self, width: u16) -> Vec<Line<'static>> {
self.0.display_lines(width)
}
fn desired_height(&self, width: u16) -> u16 {
self.0.desired_height(width)
}
fn transcript_lines(&self, width: u16) -> Vec<Line<'static>> {
self.0.transcript_lines(width)
}
}
pub(crate) fn new_session_info( pub(crate) fn new_session_info(
config: &Config, config: &Config,
event: SessionConfiguredEvent, event: SessionConfiguredEvent,
is_first_event: bool, is_first_event: bool,
) -> CompositeHistoryCell { ) -> SessionInfoCell {
let SessionConfiguredEvent { let SessionConfiguredEvent {
model, model,
reasoning_effort, reasoning_effort,
@@ -573,7 +590,7 @@ pub(crate) fn new_session_info(
initial_messages: _, initial_messages: _,
rollout_path: _, rollout_path: _,
} = event; } = event;
if is_first_event { SessionInfoCell(if is_first_event {
// Header box rendered as history (so it appears at the very top) // Header box rendered as history (so it appears at the very top)
let header = SessionHeaderHistoryCell::new( let header = SessionHeaderHistoryCell::new(
model, model,
@@ -632,7 +649,7 @@ pub(crate) fn new_session_info(
CompositeHistoryCell { CompositeHistoryCell {
parts: vec![Box::new(PlainHistoryCell { lines })], parts: vec![Box::new(PlainHistoryCell { lines })],
} }
} })
} }
pub(crate) fn new_user_prompt(message: String) -> UserHistoryCell { pub(crate) fn new_user_prompt(message: String) -> UserHistoryCell {