mirror of
https://github.com/openai/codex.git
synced 2026-10-20 17:38:45 +00:00
## Why Closing Find previously restored the pre-search view, making it difficult to read a match and its surrounding transcript context. ## What changed - Make `Esc` with a nonempty query close query editing while preserving the query, highlighted match, and expanded output. A second `Esc` returns to the latest output; `Ctrl+C` cancels Find and restores the pre-search presentation. - Allow paging through surrounding context and loading older history without losing the query. Keep `Ctrl+N` and `Ctrl+P` available for match navigation, and reopen Find to edit the retained query. - Show context above matches when space permits, preserve match layouts across resizing, and display navigation and history status while reading results. ## Testing Add regression tests and snapshots for retained results, surrounding context, resizing, paging around live output, older-history loading, and footer status. Update interaction tests for the additional `Esc` transition. GitOrigin-RevId: d822956d3c6ffab88fc1665ebdf0c86ccf110899
89 lines
3.1 KiB
Rust
89 lines
3.1 KiB
Rust
//! Activity follows visible rows and Escape respects transcript interaction ownership.
|
|
|
|
use super::*;
|
|
use crate::history_cell::PlainHistoryCell;
|
|
use crate::motion::MotionMode;
|
|
use crossterm::event::KeyCode;
|
|
use crossterm::event::KeyEvent;
|
|
use crossterm::event::KeyModifiers;
|
|
use pretty_assertions::assert_eq;
|
|
|
|
fn cell(text: &str) -> Arc<dyn HistoryCell> {
|
|
Arc::new(PlainHistoryCell::new(
|
|
text.lines().map(|line| line.to_owned().into()).collect(),
|
|
))
|
|
}
|
|
|
|
fn render(view: &mut TranscriptView, cells: &[Arc<dyn HistoryCell>], height: u16) {
|
|
let area = Rect::new(/*x*/ 0, /*y*/ 0, /*width*/ 32, height);
|
|
view.render(area, &mut Buffer::empty(area), cells);
|
|
}
|
|
|
|
#[test]
|
|
fn visible_updates_and_empty_tail_cells_do_not_report_activity() {
|
|
let mut cells = vec![cell("one\ntwo\nthree\nfour")];
|
|
let mut view = TranscriptView::default();
|
|
render(&mut view, &cells, /*height*/ 3);
|
|
view.scroll(&cells, /*rows*/ -3);
|
|
cells.push(cell(""));
|
|
render(&mut view, &cells, /*height*/ 3);
|
|
assert!(!view.unseen_activity);
|
|
cells.extend([cell("visible output"), cell("")]);
|
|
render(&mut view, &cells, /*height*/ 3);
|
|
assert!(view.unseen_activity);
|
|
render(&mut view, &cells, /*height*/ 8);
|
|
assert!(!view.unseen_activity);
|
|
assert!(view.footer(/*width*/ 80, MotionMode::Reduced).is_none());
|
|
}
|
|
|
|
#[test]
|
|
fn unchanged_live_revisions_do_not_report_activity_but_hidden_text_does() {
|
|
let cells = vec![cell("one\ntwo\nthree\nfour")];
|
|
let mut view = TranscriptView::default();
|
|
for (revision, text, unseen) in [
|
|
(1, "tail", false),
|
|
(2, "tail", false),
|
|
(3, "new tail", true),
|
|
] {
|
|
view.sync_live_tail(
|
|
/*width*/ 32,
|
|
Some(ActiveCellTranscriptKey {
|
|
revision,
|
|
animation_tick: None,
|
|
is_stream_continuation: false,
|
|
cacheable: true,
|
|
}),
|
|
|_| Some(vec![HyperlinkLine::from(text)]),
|
|
);
|
|
render(&mut view, &cells, /*height*/ 3);
|
|
assert_eq!(view.unseen_activity, unseen);
|
|
view.scroll(&cells, /*rows*/ -3);
|
|
}
|
|
}
|
|
|
|
#[test]
|
|
fn escape_closes_selection_and_search_before_returning_to_latest() {
|
|
let mut cells = vec![cell("one\ntwo\nthree\nfour")];
|
|
let mut view = TranscriptView::default();
|
|
render(&mut view, &cells, /*height*/ 3);
|
|
view.scroll(&cells, /*rows*/ -1);
|
|
cells.push(cell("new output"));
|
|
render(&mut view, &cells, /*height*/ 3);
|
|
view.begin_search();
|
|
view.begin_selection(&cells, /*column*/ 0, /*row*/ 0, /*clicks*/ 3);
|
|
let escape = KeyEvent::new(KeyCode::Esc, KeyModifiers::NONE);
|
|
view.handle_key(escape, &cells);
|
|
assert!(view.selection.is_none());
|
|
assert!(view.is_search_editing());
|
|
view.handle_key(escape, &cells);
|
|
assert!(!view.is_search_editing());
|
|
assert!(!view.is_following());
|
|
assert!(matches!(
|
|
view.handle_key(escape, &cells),
|
|
Some(ViewAction::Changed)
|
|
));
|
|
assert!(view.is_following());
|
|
assert!(view.footer(/*width*/ 80, MotionMode::Reduced).is_none());
|
|
assert!(view.handle_key(escape, &cells).is_none());
|
|
}
|