From fb3f6456cff9e4ea98fe72a0bd10b2d59ce8aa10 Mon Sep 17 00:00:00 2001 From: vinaybantupalli Date: Wed, 27 Aug 2025 05:07:46 +0530 Subject: [PATCH] fix issue #2713: adding support for alt+ctrl+h to delete backward word (#2717) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This pr addresses the fix for https://github.com/openai/codex/issues/2713 ### Changes: - Added key handler for `Alt+Ctrl+H` → `delete_backward_word()` - Added test coverage in `delete_backward_word_alt_keys()` that verifies both: - Standard `Alt+Backspace` binding continues to work - New `Alt+Ctrl+H` binding works correctly for backward word deletion ### Testing: The test ensures both key combinations produce identical behavior: - Delete the previous word from "hello world" → "hello " - Cursor positioned correctly after deletion ### Backward Compatibility: This change is backward compatible - existing `Alt+Backspace` functionality remains unchanged while adding support for the terminal-specific `Alt+Ctrl+H` variant --- codex-rs/tui/src/bottom_pane/textarea.rs | 57 ++++++++++++++++++++---- 1 file changed, 49 insertions(+), 8 deletions(-) diff --git a/codex-rs/tui/src/bottom_pane/textarea.rs b/codex-rs/tui/src/bottom_pane/textarea.rs index e2c83f55..2ad8c440 100644 --- a/codex-rs/tui/src/bottom_pane/textarea.rs +++ b/codex-rs/tui/src/bottom_pane/textarea.rs @@ -231,6 +231,13 @@ impl TextArea { code: KeyCode::Enter, .. } => self.insert_str("\n"), + KeyEvent { + code: KeyCode::Char('h'), + modifiers, + .. + } if modifiers == (KeyModifiers::CONTROL | KeyModifiers::ALT) => { + self.delete_backward_word() + }, KeyEvent { code: KeyCode::Backspace, modifiers: KeyModifiers::ALT, @@ -1138,10 +1145,6 @@ mod tests { #[test] fn control_b_and_f_move_cursor() { - use crossterm::event::KeyCode; - use crossterm::event::KeyEvent; - use crossterm::event::KeyModifiers; - let mut t = ta_with("abcd"); t.set_cursor(1); @@ -1154,10 +1157,6 @@ mod tests { #[test] fn control_b_f_fallback_control_chars_move_cursor() { - use crossterm::event::KeyCode; - use crossterm::event::KeyEvent; - use crossterm::event::KeyModifiers; - let mut t = ta_with("abcd"); t.set_cursor(2); @@ -1171,6 +1170,48 @@ mod tests { assert_eq!(t.cursor(), 2); } + #[test] + fn delete_backward_word_alt_keys() { + // Test the custom Alt+Ctrl+h binding + let mut t = ta_with("hello world"); + t.set_cursor(t.text().len()); // cursor at the end + t.input(KeyEvent::new( + KeyCode::Char('h'), + KeyModifiers::CONTROL | KeyModifiers::ALT, + )); + assert_eq!(t.text(), "hello "); + assert_eq!(t.cursor(), 6); + + // Test the standard Alt+Backspace binding + let mut t = ta_with("hello world"); + t.set_cursor(t.text().len()); // cursor at the end + t.input(KeyEvent::new(KeyCode::Backspace, KeyModifiers::ALT)); + assert_eq!(t.text(), "hello "); + assert_eq!(t.cursor(), 6); + } + + #[test] + fn control_h_backspace() { + // Test Ctrl+H as backspace + let mut t = ta_with("12345"); + t.set_cursor(3); // cursor after '3' + t.input(KeyEvent::new(KeyCode::Char('h'), KeyModifiers::CONTROL)); + assert_eq!(t.text(), "1245"); + assert_eq!(t.cursor(), 2); + + // Test Ctrl+H at beginning (should be no-op) + t.set_cursor(0); + t.input(KeyEvent::new(KeyCode::Char('h'), KeyModifiers::CONTROL)); + assert_eq!(t.text(), "1245"); + assert_eq!(t.cursor(), 0); + + // Test Ctrl+H at end + t.set_cursor(t.text().len()); + t.input(KeyEvent::new(KeyCode::Char('h'), KeyModifiers::CONTROL)); + assert_eq!(t.text(), "124"); + assert_eq!(t.cursor(), 3); + } + #[test] fn cursor_vertical_movement_across_lines_and_bounds() { let mut t = ta_with("short\nloooooooooong\nmid");