diff --git a/codex-rs/tui/src/bottom_pane/chat_composer.rs b/codex-rs/tui/src/bottom_pane/chat_composer.rs index 36aacd0519..23c788478f 100644 --- a/codex-rs/tui/src/bottom_pane/chat_composer.rs +++ b/codex-rs/tui/src/bottom_pane/chat_composer.rs @@ -784,9 +784,13 @@ impl ChatComposer { enabled } + pub(crate) fn is_vim_insert(&self) -> bool { + self.textarea.is_vim_insert() + } + fn vim_mode_indicator_span(&self) -> Option> { self.textarea.vim_mode_label().map(|label| match label { - "Normal" => "Vim: Normal".yellow(), + "Normal" => "Vim: Normal".magenta(), "Insert" => "Vim: Insert".green(), _ => unreachable!(), }) diff --git a/codex-rs/tui/src/bottom_pane/mod.rs b/codex-rs/tui/src/bottom_pane/mod.rs index 947a9166ac..7794c906da 100644 --- a/codex-rs/tui/src/bottom_pane/mod.rs +++ b/codex-rs/tui/src/bottom_pane/mod.rs @@ -751,7 +751,10 @@ impl BottomPane { /// overlays or popups and not running a task. This is the safe context to /// use Esc-Esc for backtracking from the main view. pub(crate) fn is_normal_backtrack_mode(&self) -> bool { - !self.is_task_running && self.view_stack.is_empty() && !self.composer.popup_active() + !self.is_task_running + && self.view_stack.is_empty() + && !self.composer.popup_active() + && !self.composer.is_vim_insert() } /// Return true when no popups or modal views are active, regardless of task state. @@ -1498,6 +1501,31 @@ mod tests { ); } + #[test] + fn normal_backtrack_mode_excludes_vim_insert() { + let (tx_raw, _rx) = unbounded_channel::(); + let tx = AppEventSender::new(tx_raw); + let mut pane = BottomPane::new(BottomPaneParams { + app_event_tx: tx, + frame_requester: FrameRequester::test_dummy(), + has_input_focus: true, + enhanced_keys_supported: false, + placeholder_text: "Ask Codex to do anything".to_string(), + disable_paste_burst: false, + animations_enabled: true, + skills: Some(Vec::new()), + }); + + pane.toggle_vim_enabled(); + assert!(pane.is_normal_backtrack_mode()); + + pane.handle_key_event(KeyEvent::new(KeyCode::Char('i'), KeyModifiers::NONE)); + assert!(!pane.is_normal_backtrack_mode()); + + pane.handle_key_event(KeyEvent::new(KeyCode::Esc, KeyModifiers::NONE)); + assert!(pane.is_normal_backtrack_mode()); + } + #[test] fn esc_routes_to_handle_key_event_when_requested() { #[derive(Default)]