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:
@@ -427,8 +427,9 @@ impl App {
|
|||||||
tui.frame_requester().schedule_frame();
|
tui.frame_requester().schedule_frame();
|
||||||
}
|
}
|
||||||
// Esc primes/advances backtracking only in normal (not working) mode
|
// Esc primes/advances backtracking only in normal (not working) mode
|
||||||
// with an empty composer. In any other state, forward Esc so the
|
// with the composer focused and empty. In any other state, forward
|
||||||
// active UI (e.g. status indicator, modals, popups) handles it.
|
// Esc so the active UI (e.g. status indicator, modals, popups)
|
||||||
|
// handles it.
|
||||||
KeyEvent {
|
KeyEvent {
|
||||||
code: KeyCode::Esc,
|
code: KeyCode::Esc,
|
||||||
kind: KeyEventKind::Press | KeyEventKind::Repeat,
|
kind: KeyEventKind::Press | KeyEventKind::Repeat,
|
||||||
|
|||||||
@@ -82,15 +82,16 @@ impl App {
|
|||||||
|
|
||||||
/// Handle global Esc presses for backtracking when no overlay is present.
|
/// Handle global Esc presses for backtracking when no overlay is present.
|
||||||
pub(crate) fn handle_backtrack_esc_key(&mut self, tui: &mut tui::Tui) {
|
pub(crate) fn handle_backtrack_esc_key(&mut self, tui: &mut tui::Tui) {
|
||||||
// Only handle backtracking when composer is empty to avoid clobbering edits.
|
if !self.chat_widget.composer_is_empty() {
|
||||||
if self.chat_widget.composer_is_empty() {
|
return;
|
||||||
if !self.backtrack.primed {
|
}
|
||||||
self.prime_backtrack();
|
|
||||||
} else if self.overlay.is_none() {
|
if !self.backtrack.primed {
|
||||||
self.open_backtrack_preview(tui);
|
self.prime_backtrack();
|
||||||
} else if self.backtrack.overlay_preview_active {
|
} else if self.overlay.is_none() {
|
||||||
self.step_backtrack_and_highlight(tui);
|
self.open_backtrack_preview(tui);
|
||||||
}
|
} else if self.backtrack.overlay_preview_active {
|
||||||
|
self.step_backtrack_and_highlight(tui);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -857,10 +857,12 @@ impl ChatComposer {
|
|||||||
return (InputResult::None, true);
|
return (InputResult::None, true);
|
||||||
}
|
}
|
||||||
if key_event.code == KeyCode::Esc {
|
if key_event.code == KeyCode::Esc {
|
||||||
let next_mode = esc_hint_mode(self.footer_mode, self.is_task_running);
|
if self.is_empty() {
|
||||||
if next_mode != self.footer_mode {
|
let next_mode = esc_hint_mode(self.footer_mode, self.is_task_running);
|
||||||
self.footer_mode = next_mode;
|
if next_mode != self.footer_mode {
|
||||||
return (InputResult::None, true);
|
self.footer_mode = next_mode;
|
||||||
|
return (InputResult::None, true);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
self.footer_mode = reset_mode_after_activity(self.footer_mode);
|
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]
|
#[test]
|
||||||
fn question_mark_only_toggles_on_first_char() {
|
fn question_mark_only_toggles_on_first_char() {
|
||||||
use crossterm::event::KeyCode;
|
use crossterm::event::KeyCode;
|
||||||
|
|||||||
Reference in New Issue
Block a user