diff --git a/codex-rs/tui/src/bottom_pane/chat_composer.rs b/codex-rs/tui/src/bottom_pane/chat_composer.rs index 3b02c59334..541f3817b4 100644 --- a/codex-rs/tui/src/bottom_pane/chat_composer.rs +++ b/codex-rs/tui/src/bottom_pane/chat_composer.rs @@ -1204,17 +1204,25 @@ impl ChatComposer { } fn handle_shortcut_overlay_key(&mut self, key_event: &KeyEvent) -> bool { - if key_event.kind == KeyEventKind::Press - && key_event.modifiers.is_empty() - && matches!(key_event.code, KeyCode::Char('?')) - { - let next = toggle_shortcut_mode(self.footer_mode, self.ctrl_c_quit_hint); - let changed = next != self.footer_mode; - self.footer_mode = next; - changed - } else { - false + if key_event.kind != KeyEventKind::Press { + return false; + } + + let toggles = match key_event.code { + KeyCode::Char('?') if key_event.modifiers.is_empty() => true, + KeyCode::BackTab => true, + KeyCode::Tab if key_event.modifiers.contains(KeyModifiers::SHIFT) => true, + _ => false, + }; + + if !toggles { + return false; } + + let next = toggle_shortcut_mode(self.footer_mode, self.ctrl_c_quit_hint); + let changed = next != self.footer_mode; + self.footer_mode = next; + changed } fn footer_props(&self) -> FooterProps { diff --git a/codex-rs/tui/src/bottom_pane/footer.rs b/codex-rs/tui/src/bottom_pane/footer.rs index 2e63493e31..aa0659ed9f 100644 --- a/codex-rs/tui/src/bottom_pane/footer.rs +++ b/codex-rs/tui/src/bottom_pane/footer.rs @@ -140,6 +140,7 @@ fn build_columns(entries: Vec) -> Vec> { const COLUMNS: usize = 3; const MAX_PADDED_WIDTHS: [usize; COLUMNS - 1] = [24, 28]; + const MIN_PADDED_WIDTHS: [usize; COLUMNS - 1] = [22, 0]; let rows = entries.len().div_ceil(COLUMNS); let mut column_widths = [0usize; COLUMNS]; @@ -160,7 +161,8 @@ fn build_columns(entries: Vec) -> Vec> { let entry = &entries[idx]; if col < COLUMNS - 1 { let max_width = MAX_PADDED_WIDTHS[col]; - let target_width = column_widths[col].min(max_width); + let mut target_width = column_widths[col]; + target_width = target_width.max(MIN_PADDED_WIDTHS[col]).min(max_width); let pad_width = target_width + 2; line.push_str(&format!("{entry:) -> Vec> { #[derive(Clone, Copy, Debug, Eq, PartialEq)] enum ShortcutId { Commands, - FilePaths, InsertNewline, + ChangeMode, + FilePaths, PasteImage, + EditPrevious, Quit, ShowTranscript, - ToggleOverlay, - EditPrevious, } #[derive(Clone, Copy, Debug, Eq, PartialEq)] @@ -272,17 +274,6 @@ const SHORTCUTS: &[ShortcutDescriptor] = &[ prefix: "", label: " for commands", }, - ShortcutDescriptor { - id: ShortcutId::FilePaths, - bindings: &[ShortcutBinding { - code: KeyCode::Char('@'), - modifiers: KeyModifiers::NONE, - overlay_text: "@", - condition: DisplayCondition::Always, - }], - prefix: "", - label: " for file paths", - }, ShortcutDescriptor { id: ShortcutId::InsertNewline, bindings: &[ @@ -302,6 +293,28 @@ const SHORTCUTS: &[ShortcutDescriptor] = &[ prefix: "", label: " for newline", }, + ShortcutDescriptor { + id: ShortcutId::ChangeMode, + bindings: &[ShortcutBinding { + code: KeyCode::BackTab, + modifiers: KeyModifiers::SHIFT, + overlay_text: "shift + tab", + condition: DisplayCondition::Always, + }], + prefix: "", + label: " to change mode", + }, + ShortcutDescriptor { + id: ShortcutId::FilePaths, + bindings: &[ShortcutBinding { + code: KeyCode::Char('@'), + modifiers: KeyModifiers::NONE, + overlay_text: "@", + condition: DisplayCondition::Always, + }], + prefix: "", + label: " for file paths", + }, ShortcutDescriptor { id: ShortcutId::PasteImage, bindings: &[ShortcutBinding { @@ -313,6 +326,17 @@ const SHORTCUTS: &[ShortcutDescriptor] = &[ prefix: "", label: " to paste images", }, + ShortcutDescriptor { + id: ShortcutId::EditPrevious, + bindings: &[ShortcutBinding { + code: KeyCode::Esc, + modifiers: KeyModifiers::NONE, + overlay_text: "esc", + condition: DisplayCondition::Always, + }], + prefix: "", + label: "", + }, ShortcutDescriptor { id: ShortcutId::Quit, bindings: &[ShortcutBinding { @@ -335,28 +359,6 @@ const SHORTCUTS: &[ShortcutDescriptor] = &[ prefix: "", label: " to view transcript", }, - ShortcutDescriptor { - id: ShortcutId::ToggleOverlay, - bindings: &[ShortcutBinding { - code: KeyCode::Char('?'), - modifiers: KeyModifiers::NONE, - overlay_text: "?", - condition: DisplayCondition::Always, - }], - prefix: "", - label: " to hide shortcuts", - }, - ShortcutDescriptor { - id: ShortcutId::EditPrevious, - bindings: &[ShortcutBinding { - code: KeyCode::Esc, - modifiers: KeyModifiers::NONE, - overlay_text: "esc", - condition: DisplayCondition::Always, - }], - prefix: "", - label: "", - }, ]; #[cfg(test)] diff --git a/codex-rs/tui/src/bottom_pane/snapshots/codex_tui__bottom_pane__chat_composer__tests__footer_mode_shortcut_overlay.snap b/codex-rs/tui/src/bottom_pane/snapshots/codex_tui__bottom_pane__chat_composer__tests__footer_mode_shortcut_overlay.snap index c08e7f2d83..9633aab2ae 100644 --- a/codex-rs/tui/src/bottom_pane/snapshots/codex_tui__bottom_pane__chat_composer__tests__footer_mode_shortcut_overlay.snap +++ b/codex-rs/tui/src/bottom_pane/snapshots/codex_tui__bottom_pane__chat_composer__tests__footer_mode_shortcut_overlay.snap @@ -10,6 +10,6 @@ expression: terminal.backend() " " " " " " -" / for commands @ for file paths shift + enter for newline " -" ctrl + v to paste images ctrl + c to exit ctrl + t to view transcript " -" ? to hide shortcuts esc again to edit previous message " +" / for commands shift + enter for newline shift + tab to change mode " +" @ for file paths ctrl + v to paste images esc again to edit previous message " +" ctrl + c to exit ctrl + t to view transcript " diff --git a/codex-rs/tui/src/bottom_pane/snapshots/codex_tui__bottom_pane__footer__tests__footer_shortcuts_shift_and_esc.snap b/codex-rs/tui/src/bottom_pane/snapshots/codex_tui__bottom_pane__footer__tests__footer_shortcuts_shift_and_esc.snap index 96c10733dc..111c14136a 100644 --- a/codex-rs/tui/src/bottom_pane/snapshots/codex_tui__bottom_pane__footer__tests__footer_shortcuts_shift_and_esc.snap +++ b/codex-rs/tui/src/bottom_pane/snapshots/codex_tui__bottom_pane__footer__tests__footer_shortcuts_shift_and_esc.snap @@ -2,6 +2,6 @@ source: tui/src/bottom_pane/footer.rs expression: terminal.backend() --- -" / for commands @ for file paths shift + enter for ne" -" ctrl + v to paste images ctrl + c to exit ctrl + t to view tra" -" ? to hide shortcuts esc again to edit previous message " +" / for commands shift + enter for newline shift + tab to change m" +" @ for file paths ctrl + v to paste images esc again to edit previ" +" ctrl + c to exit ctrl + t to view transcript "