Keep backtrack Esc hint gated on empty composer (#5076)

## Summary
- only prime backtrack and show the ESC hint when the composer is empty
- keep the composer-side ESC hint unchanged when drafts or attachments
exist and cover it with a regression test

Fixes #5030

------
https://chatgpt.com/codex/tasks/task_i_68e95ba59cd8832caec8e72ae2efeb55
This commit is contained in:
Jeremy Rose
2025-10-15 13:57:50 -07:00
committed by GitHub
parent 0016346dfb
commit 9b53a306e3
3 changed files with 48 additions and 15 deletions

View File

@@ -857,10 +857,12 @@ impl ChatComposer {
return (InputResult::None, true);
}
if key_event.code == KeyCode::Esc {
let next_mode = esc_hint_mode(self.footer_mode, self.is_task_running);
if next_mode != self.footer_mode {
self.footer_mode = next_mode;
return (InputResult::None, true);
if self.is_empty() {
let next_mode = esc_hint_mode(self.footer_mode, self.is_task_running);
if next_mode != self.footer_mode {
self.footer_mode = next_mode;
return (InputResult::None, true);
}
}
} else {
self.footer_mode = reset_mode_after_activity(self.footer_mode);
@@ -1797,6 +1799,35 @@ mod tests {
});
}
#[test]
fn esc_hint_stays_hidden_with_draft_content() {
use crossterm::event::KeyCode;
use crossterm::event::KeyEvent;
use crossterm::event::KeyModifiers;
let (tx, _rx) = unbounded_channel::<AppEvent>();
let sender = AppEventSender::new(tx);
let mut composer = ChatComposer::new(
true,
sender,
true,
"Ask Codex to do anything".to_string(),
false,
);
type_chars_humanlike(&mut composer, &['d']);
assert!(!composer.is_empty());
assert_eq!(composer.current_text(), "d");
assert_eq!(composer.footer_mode, FooterMode::ShortcutSummary);
assert!(matches!(composer.active_popup, ActivePopup::None));
let _ = composer.handle_key_event(KeyEvent::new(KeyCode::Esc, KeyModifiers::NONE));
assert_eq!(composer.footer_mode, FooterMode::ShortcutSummary);
assert!(!composer.esc_backtrack_hint);
}
#[test]
fn question_mark_only_toggles_on_first_char() {
use crossterm::event::KeyCode;