mirror of
https://github.com/openai/codex.git
synced 2026-11-14 21:40:39 +00:00
Add transcript search and per-activity detail controls (#46734)
## What changed - Add incremental, case-insensitive literal search across transcript details, loading older history as needed. Use `F3` to start Find, or `/` in the transcript pager, and navigate matches in either direction. Closing Find restores the previous presentation and reading position. - Add clickable activity detail controls and `F4` keyboard focus for inspecting individual activity groups in the owned transcript. Preserve expansion state as live activity becomes history. - Expose configurable `global.find_transcript`, `global.focus_activity`, and `pager.find` bindings under `tui.keymap`. Let new defaults yield to existing custom bindings and show available completions for pending chords. ## Testing Add regression coverage for Unicode matching, bounded scanning, paginated and changing history, selection during search, composer input isolation, activity controls, and custom shortcut conflicts. GitOrigin-RevId: 5bcbcdfbca7c5c296c635ec9b079ccd7a908e336
This commit is contained in:
@@ -148,6 +148,52 @@ fn beginning_wait_keeps_live_content_through_new_output_prepend_and_resize() {
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn transcript_interaction_cancels_pending_beginning_without_losing_received_history() {
|
||||
for key in [
|
||||
None,
|
||||
Some(KeyEvent::new(KeyCode::PageUp, KeyModifiers::NONE)),
|
||||
Some(KeyEvent::new(KeyCode::F(3), KeyModifiers::NONE)),
|
||||
Some(KeyEvent::new(KeyCode::Char(' '), KeyModifiers::CONTROL)),
|
||||
] {
|
||||
let mut cells = (0..20)
|
||||
.map(|index| cell(format!("line {index}")))
|
||||
.collect::<Vec<_>>();
|
||||
let mut view = TranscriptView {
|
||||
history: TranscriptHistoryState::Partial,
|
||||
..TranscriptView::default()
|
||||
};
|
||||
render(&mut view, &cells, /*width*/ 24, /*height*/ 3);
|
||||
view.jump_to_beginning(&cells);
|
||||
match key {
|
||||
Some(key) if key.code == KeyCode::F(3) => view.begin_search(),
|
||||
Some(key) => {
|
||||
view.handle_key(key, &cells);
|
||||
}
|
||||
None => {
|
||||
view.handle_mouse(
|
||||
MouseEvent {
|
||||
kind: MouseEventKind::ScrollUp,
|
||||
column: 0,
|
||||
row: 0,
|
||||
modifiers: KeyModifiers::NONE,
|
||||
},
|
||||
&cells,
|
||||
);
|
||||
}
|
||||
}
|
||||
assert_eq!(view.history, TranscriptHistoryState::LoadingOlder);
|
||||
let before = render(&mut view, &cells, /*width*/ 24, /*height*/ 3);
|
||||
cells.insert(/*index*/ 0, cell("received older history"));
|
||||
view.history_loaded(&cells, 0..1);
|
||||
view.history = TranscriptHistoryState::Complete;
|
||||
assert_eq!(
|
||||
render(&mut view, &cells, /*width*/ 24, /*height*/ 3),
|
||||
before
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn returning_to_latest_cancels_beginning_intent_while_retaining_the_loaded_page() {
|
||||
for (beginning, latest) in [
|
||||
@@ -518,6 +564,29 @@ fn mutable_history_formats_once_per_frame_and_refreshes_the_next_frame() {
|
||||
version 2 row 6
|
||||
version 2 row 7
|
||||
");
|
||||
view.begin_search();
|
||||
view.paste_search("version 2");
|
||||
assert!(!view.advance_search(&cells));
|
||||
let matched = text(&render(
|
||||
&mut view, &cells, /*width*/ 24, /*height*/ 5,
|
||||
));
|
||||
view.begin_selection(&cells, /*column*/ 0, /*row*/ 0, /*clicks*/ 3);
|
||||
version.store(/*val*/ 3, Ordering::Relaxed);
|
||||
view.end_selection(&cells);
|
||||
assert_eq!(
|
||||
text(&render(
|
||||
&mut view, &cells, /*width*/ 24, /*height*/ 5
|
||||
)),
|
||||
matched
|
||||
);
|
||||
view.handle_key(KeyCode::Enter.into(), &cells);
|
||||
assert!(!view.advance_search(&cells));
|
||||
assert!(
|
||||
text(&render(
|
||||
&mut view, &cells, /*width*/ 24, /*height*/ 5
|
||||
))
|
||||
.contains("version 3")
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -575,6 +644,15 @@ fn live_reader_survives_commit_new_tail_resize_and_selection_then_rejoins_latest
|
||||
);
|
||||
view.begin_selection(&cells, /*column*/ 0, /*row*/ 0, /*clicks*/ 3);
|
||||
assert_eq!(view.selected_text(&cells), Some("live two\n".to_string()));
|
||||
view.begin_search();
|
||||
assert!(!view.advance_search(&cells));
|
||||
view.handle_key(KeyCode::Esc.into(), &cells);
|
||||
assert_eq!(
|
||||
text(&render(
|
||||
&mut view, &cells, /*width*/ 20, /*height*/ 2
|
||||
)),
|
||||
before
|
||||
);
|
||||
view.jump_to_latest();
|
||||
assert!(view.snapshot().is_none());
|
||||
insta::assert_snapshot!(text(&render(&mut view, &cells, /*width*/ 20, /*height*/ 2)), @"
|
||||
|
||||
Reference in New Issue
Block a user