Skip to content

Commit 907afc9

Browse files
authored
Fix esc (#2661)
Esc should have other functionalities when it's not used in a backtracking situation. i.e. to cancel pop up menu when selecting model/approvals or to interrupt an active turn.
1 parent 7f7d1e3 commit 907afc9

File tree

4 files changed

+36
-2
lines changed

4 files changed

+36
-2
lines changed

codex-rs/tui/src/app.rs

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -303,13 +303,21 @@ impl App {
303303
self.transcript_overlay = Some(TranscriptApp::new(self.transcript_lines.clone()));
304304
tui.frame_requester().schedule_frame();
305305
}
306-
// Esc primes/advances backtracking when composer is empty.
306+
// Esc primes/advances backtracking only in normal (not working) mode
307+
// with an empty composer. In any other state, forward Esc so the
308+
// active UI (e.g. status indicator, modals, popups) handles it.
307309
KeyEvent {
308310
code: KeyCode::Esc,
309311
kind: KeyEventKind::Press | KeyEventKind::Repeat,
310312
..
311313
} => {
312-
self.handle_backtrack_esc_key(tui);
314+
if self.chat_widget.is_normal_backtrack_mode()
315+
&& self.chat_widget.composer_is_empty()
316+
{
317+
self.handle_backtrack_esc_key(tui);
318+
} else {
319+
self.chat_widget.handle_key_event(key_event);
320+
}
313321
}
314322
// Enter confirms backtrack when primed + count > 0. Otherwise pass to widget.
315323
KeyEvent {

codex-rs/tui/src/bottom_pane/chat_composer.rs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -307,6 +307,11 @@ impl ChatComposer {
307307
result
308308
}
309309

310+
/// Return true if either the slash-command popup or the file-search popup is active.
311+
pub(crate) fn popup_active(&self) -> bool {
312+
!matches!(self.active_popup, ActivePopup::None)
313+
}
314+
310315
/// Handle key event when the slash-command popup is visible.
311316
fn handle_key_event_with_slash_popup(&mut self, key_event: KeyEvent) -> (InputResult, bool) {
312317
let ActivePopup::Command(popup) = &mut self.active_popup else {
@@ -327,6 +332,13 @@ impl ChatComposer {
327332
popup.move_down();
328333
(InputResult::None, true)
329334
}
335+
KeyEvent {
336+
code: KeyCode::Esc, ..
337+
} => {
338+
// Dismiss the slash popup; keep the current input untouched.
339+
self.active_popup = ActivePopup::None;
340+
(InputResult::None, true)
341+
}
330342
KeyEvent {
331343
code: KeyCode::Tab, ..
332344
} => {

codex-rs/tui/src/bottom_pane/mod.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -337,6 +337,13 @@ impl BottomPane {
337337
self.is_task_running
338338
}
339339

340+
/// Return true when the pane is in the regular composer state without any
341+
/// overlays or popups and not running a task. This is the safe context to
342+
/// use Esc-Esc for backtracking from the main view.
343+
pub(crate) fn is_normal_backtrack_mode(&self) -> bool {
344+
!self.is_task_running && self.active_view.is_none() && !self.composer.popup_active()
345+
}
346+
340347
/// Update the *context-window remaining* indicator in the composer. This
341348
/// is forwarded directly to the underlying `ChatComposer`.
342349
pub(crate) fn set_token_usage(

codex-rs/tui/src/chatwidget.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1125,6 +1125,13 @@ impl ChatWidget {
11251125
self.bottom_pane.composer_is_empty()
11261126
}
11271127

1128+
/// True when the UI is in the regular composer state with no running task,
1129+
/// no modal overlay (e.g. approvals or status indicator), and no composer popups.
1130+
/// In this state Esc-Esc backtracking is enabled.
1131+
pub(crate) fn is_normal_backtrack_mode(&self) -> bool {
1132+
self.bottom_pane.is_normal_backtrack_mode()
1133+
}
1134+
11281135
pub(crate) fn insert_str(&mut self, text: &str) {
11291136
self.bottom_pane.insert_str(text);
11301137
}

0 commit comments

Comments
 (0)