mirror of
https://github.com/openai/codex.git
synced 2026-10-19 17:28:46 +00:00
Honor pager bindings for transcript page keys (#50396)
## Why Transcript scrolling hardcoded `PageUp` and `PageDown` to full-page movement, ignoring customized pager bindings. ## What changed Resolve unmodified `PageUp` and `PageDown` through the pager's scroll bindings so they can scroll by a full page, half a page, or one row, or remain unbound. Preserve the one-row overlap for full-page scrolling and leave pager typing shortcuts unhandled by the transcript. ## Testing Add a regression test and snapshot covering default, half-page, single-row, and unbound configurations. Verify that `PageDown` reverses `PageUp` scrolling and that `j` and `Ctrl+u` remain unhandled. GitOrigin-RevId: 945e99d7370f84f326ab71037be2924dddada32c
This commit is contained in:
committed by
copyberry
parent
f88a6efe43
commit
d61c7a824f
+43
@@ -0,0 +1,43 @@
|
||||
---
|
||||
source: tui/src/transcript_view_tests.rs
|
||||
expression: "frames.join(\"\\n\\n\")"
|
||||
---
|
||||
default
|
||||
row 16
|
||||
row 17
|
||||
row 18
|
||||
row 19
|
||||
row 20
|
||||
row 21
|
||||
row 22
|
||||
row 23
|
||||
|
||||
half page
|
||||
row 19
|
||||
row 20
|
||||
row 21
|
||||
row 22
|
||||
row 23
|
||||
row 24
|
||||
row 25
|
||||
row 26
|
||||
|
||||
single row
|
||||
row 22
|
||||
row 23
|
||||
row 24
|
||||
row 25
|
||||
row 26
|
||||
row 27
|
||||
row 28
|
||||
row 29
|
||||
|
||||
unbound
|
||||
row 23
|
||||
row 24
|
||||
row 25
|
||||
row 26
|
||||
row 27
|
||||
row 28
|
||||
row 29
|
||||
row 30
|
||||
@@ -343,17 +343,24 @@ impl TranscriptView {
|
||||
) -> Option<ViewAction> {
|
||||
let jump = JumpTarget::from_key(key);
|
||||
match (key.code, key.modifiers) {
|
||||
(KeyCode::PageUp, KeyModifiers::NONE) => {
|
||||
self.scroll(
|
||||
cells,
|
||||
-(self.area.height.saturating_sub(/*rhs*/ 1).max(/*other*/ 1) as isize),
|
||||
);
|
||||
}
|
||||
(KeyCode::PageDown, KeyModifiers::NONE) => {
|
||||
self.scroll(
|
||||
cells,
|
||||
self.area.height.saturating_sub(/*rhs*/ 1).max(/*other*/ 1) as isize,
|
||||
);
|
||||
(KeyCode::PageUp | KeyCode::PageDown, KeyModifiers::NONE) => {
|
||||
// Share page-key configuration without taking the pager's typing shortcuts.
|
||||
// Full pages retain the main view's existing one-row overlap.
|
||||
let keymap = &self.disclosure.keymap.pager;
|
||||
let height = self.area.height.max(/*other*/ 1) as isize;
|
||||
let page = (height - 1).max(/*other*/ 1);
|
||||
let half = (height + 1) / 2;
|
||||
let delta = [
|
||||
(&keymap.scroll_up, -1),
|
||||
(&keymap.scroll_down, 1),
|
||||
(&keymap.page_up, -page),
|
||||
(&keymap.page_down, page),
|
||||
(&keymap.half_page_up, -half),
|
||||
(&keymap.half_page_down, half),
|
||||
]
|
||||
.into_iter()
|
||||
.find_map(|(bindings, delta)| bindings.is_pressed(key).then_some(delta))?;
|
||||
self.scroll(cells, delta);
|
||||
}
|
||||
(KeyCode::Esc, KeyModifiers::NONE) if self.can_return_to_latest() => {
|
||||
self.jump_to_latest();
|
||||
|
||||
@@ -63,6 +63,77 @@ pub(super) fn text(buffer: &Buffer) -> String {
|
||||
.join("\n")
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn page_keys_follow_pager_scroll_bindings() {
|
||||
let cells = [cell(
|
||||
(1..=30)
|
||||
.map(|row| format!("row {row}\n"))
|
||||
.collect::<String>(),
|
||||
)];
|
||||
let mut frames = Vec::new();
|
||||
for (label, pager, rows) in [
|
||||
("default", serde_json::json!({}), 7),
|
||||
(
|
||||
"half page",
|
||||
serde_json::json!({
|
||||
"page_up": [], "page_down": [],
|
||||
"half_page_up": "page-up", "half_page_down": "page-down"
|
||||
}),
|
||||
4,
|
||||
),
|
||||
(
|
||||
"single row",
|
||||
serde_json::json!({
|
||||
"page_up": [], "page_down": [],
|
||||
"scroll_up": "page-up", "scroll_down": "page-down"
|
||||
}),
|
||||
1,
|
||||
),
|
||||
(
|
||||
"unbound",
|
||||
serde_json::json!({"page_up": [], "page_down": []}),
|
||||
0,
|
||||
),
|
||||
] {
|
||||
let config = serde_json::from_value(serde_json::json!({"pager": pager})).unwrap();
|
||||
let keymap = crate::keymap::RuntimeKeymap::from_config(&config).unwrap();
|
||||
let mut view = TranscriptView::default();
|
||||
view.set_keymap_bindings(&keymap);
|
||||
let pre_scroll = render(&mut view, &cells, /*width*/ 20, /*height*/ 8);
|
||||
assert_eq!(
|
||||
view.handle_key(KeyCode::PageUp.into(), &cells).is_some(),
|
||||
rows != 0
|
||||
);
|
||||
let scrolled = render(&mut view, &cells, /*width*/ 20, /*height*/ 8);
|
||||
let mut expected = TranscriptView::default();
|
||||
render(&mut expected, &cells, /*width*/ 20, /*height*/ 8);
|
||||
expected.scroll(&cells, -rows);
|
||||
assert_eq!(
|
||||
scrolled,
|
||||
render(&mut expected, &cells, /*width*/ 20, /*height*/ 8)
|
||||
);
|
||||
frames.push(format!("{label}\n{}", text(&scrolled)));
|
||||
assert_eq!(
|
||||
view.handle_key(KeyCode::PageDown.into(), &cells).is_some(),
|
||||
rows != 0
|
||||
);
|
||||
assert_eq!(
|
||||
render(&mut view, &cells, /*width*/ 20, /*height*/ 8),
|
||||
pre_scroll
|
||||
);
|
||||
for key in [
|
||||
KeyCode::Char('j').into(),
|
||||
KeyEvent::new(KeyCode::Char('u'), KeyModifiers::CONTROL),
|
||||
] {
|
||||
assert!(view.handle_key(key, &cells).is_none());
|
||||
}
|
||||
}
|
||||
insta::assert_snapshot!(
|
||||
"page_keys_follow_pager_scroll_bindings",
|
||||
frames.join("\n\n")
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn terminal_output_disclosure_follows_live_history_and_keymap() {
|
||||
use crate::exec_cell::CommandOutput;
|
||||
|
||||
Reference in New Issue
Block a user