diff --git a/src/app/events/mod.rs b/src/app/events/mod.rs index 9b8249fd..c3fd7e89 100644 --- a/src/app/events/mod.rs +++ b/src/app/events/mod.rs @@ -19,6 +19,8 @@ use super::{ }; use crate::agent::model; use crate::app::keys::reclaim_input_from_inline_prompt_if_needed; +#[cfg(test)] +use crate::app::keys::{CMD_MOD, WORD_NAV_MOD}; use crate::app::todos::apply_plan_todos; #[cfg(test)] use crossterm::event::KeyEvent; @@ -3393,11 +3395,11 @@ mod tests { let mut app = make_test_app(); app.input.set_text("hello world"); - handle_normal_key(&mut app, KeyEvent::new(KeyCode::Backspace, KeyModifiers::CONTROL)); + handle_normal_key(&mut app, KeyEvent::new(KeyCode::Backspace, WORD_NAV_MOD)); assert_eq!(app.input.text(), "hello "); app.input.move_home(); - handle_normal_key(&mut app, KeyEvent::new(KeyCode::Delete, KeyModifiers::CONTROL)); + handle_normal_key(&mut app, KeyEvent::new(KeyCode::Delete, WORD_NAV_MOD)); assert_eq!(app.input.text(), " "); } @@ -3406,13 +3408,16 @@ mod tests { let mut app = make_test_app(); app.input.set_text("hello world"); - handle_normal_key(&mut app, KeyEvent::new(KeyCode::Backspace, KeyModifiers::CONTROL)); + handle_normal_key(&mut app, KeyEvent::new(KeyCode::Backspace, WORD_NAV_MOD)); assert_eq!(app.input.text(), "hello "); - handle_normal_key(&mut app, KeyEvent::new(KeyCode::Char('z'), KeyModifiers::CONTROL)); + handle_normal_key(&mut app, KeyEvent::new(KeyCode::Char('z'), CMD_MOD)); assert_eq!(app.input.text(), "hello world"); - handle_normal_key(&mut app, KeyEvent::new(KeyCode::Char('y'), KeyModifiers::CONTROL)); + #[cfg(target_os = "macos")] + handle_normal_key(&mut app, KeyEvent::new(KeyCode::Char('Z'), CMD_MOD)); + #[cfg(not(target_os = "macos"))] + handle_normal_key(&mut app, KeyEvent::new(KeyCode::Char('y'), CMD_MOD)); assert_eq!(app.input.text(), "hello "); } @@ -3422,10 +3427,10 @@ mod tests { app.input.set_text("hello world"); app.input.move_home(); - handle_normal_key(&mut app, KeyEvent::new(KeyCode::Right, KeyModifiers::CONTROL)); + handle_normal_key(&mut app, KeyEvent::new(KeyCode::Right, WORD_NAV_MOD)); assert!(app.input.cursor_col() > 0); - handle_normal_key(&mut app, KeyEvent::new(KeyCode::Left, KeyModifiers::CONTROL)); + handle_normal_key(&mut app, KeyEvent::new(KeyCode::Left, WORD_NAV_MOD)); assert_eq!(app.input.cursor_col(), 0); } diff --git a/src/app/keys.rs b/src/app/keys.rs index 42e44249..8e105fca 100644 --- a/src/app/keys.rs +++ b/src/app/keys.rs @@ -24,6 +24,21 @@ use std::time::Instant; const HELP_TAB_PREV_KEY: KeyCode = KeyCode::Left; const HELP_TAB_NEXT_KEY: KeyCode = KeyCode::Right; +#[cfg(target_os = "macos")] +pub(crate) const CMD_MOD: KeyModifiers = KeyModifiers::SUPER; +#[cfg(not(target_os = "macos"))] +pub(crate) const CMD_MOD: KeyModifiers = KeyModifiers::CONTROL; + +#[cfg(target_os = "macos")] +pub(crate) const WORD_NAV_MOD: KeyModifiers = KeyModifiers::ALT; +#[cfg(not(target_os = "macos"))] +pub(crate) const WORD_NAV_MOD: KeyModifiers = KeyModifiers::CONTROL; + +#[cfg(target_os = "macos")] +pub(crate) const WORD_NAV_MOD_EXCLUDED: KeyModifiers = KeyModifiers::empty(); +#[cfg(not(target_os = "macos"))] +pub(crate) const WORD_NAV_MOD_EXCLUDED: KeyModifiers = KeyModifiers::ALT; + fn is_ctrl_shortcut(modifiers: KeyModifiers) -> bool { modifiers.contains(KeyModifiers::CONTROL) && !modifiers.contains(KeyModifiers::ALT) } @@ -439,8 +454,21 @@ fn handle_history_key(app: &mut App, key: KeyEvent) -> bool { return false; } match (key.code, key.modifiers) { - (KeyCode::Char('z'), m) if m == KeyModifiers::CONTROL => app.input.textarea_undo(), - (KeyCode::Char('y'), m) if m == KeyModifiers::CONTROL => app.input.textarea_redo(), + (KeyCode::Char('z'), m) if m == CMD_MOD => { + app.input.textarea_undo(); + true + } + + #[cfg(target_os = "macos")] + (KeyCode::Char('Z'), m) if m == CMD_MOD => { + app.input.textarea_redo(); + true + } + #[cfg(not(target_os = "macos"))] + (KeyCode::Char('y'), m) if m == CMD_MOD => { + app.input.textarea_redo(); + true + } _ => false, } } @@ -449,15 +477,15 @@ fn handle_navigation_key(app: &mut App, key: KeyEvent) -> bool { match (key.code, key.modifiers) { (KeyCode::Left, m) if app.focus_owner() != FocusOwner::TodoList - && m.contains(KeyModifiers::CONTROL) - && !m.contains(KeyModifiers::ALT) => + && m.contains(WORD_NAV_MOD) + && !m.intersects(WORD_NAV_MOD_EXCLUDED) => { app.input.textarea_move_word_left() } (KeyCode::Right, m) if app.focus_owner() != FocusOwner::TodoList - && m.contains(KeyModifiers::CONTROL) - && !m.contains(KeyModifiers::ALT) => + && m.contains(WORD_NAV_MOD) + && !m.intersects(WORD_NAV_MOD_EXCLUDED) => { app.input.textarea_move_word_right() } @@ -677,8 +705,8 @@ fn handle_editing_key(app: &mut App, key: KeyEvent) -> bool { match (key.code, key.modifiers) { (KeyCode::Backspace, m) if app.focus_owner() != FocusOwner::TodoList - && m.contains(KeyModifiers::CONTROL) - && !m.contains(KeyModifiers::ALT) => + && m.contains(WORD_NAV_MOD) + && !m.intersects(WORD_NAV_MOD_EXCLUDED) => { reclaim_input_from_inline_prompt_if_needed(app); if try_delete_image_badge(app, "before") { @@ -688,8 +716,8 @@ fn handle_editing_key(app: &mut App, key: KeyEvent) -> bool { } (KeyCode::Delete, m) if app.focus_owner() != FocusOwner::TodoList - && m.contains(KeyModifiers::CONTROL) - && !m.contains(KeyModifiers::ALT) => + && m.contains(WORD_NAV_MOD) + && !m.intersects(WORD_NAV_MOD_EXCLUDED) => { reclaim_input_from_inline_prompt_if_needed(app); if try_delete_image_badge(app, "after") {