diff --git a/crates/gpui/src/app.rs b/crates/gpui/src/app.rs index 5dc0f0c49d1353a21520cd641b2415d88a532bf2..a7ff52e19e1349b5ff4e21523167cea23d2a2f04 100644 --- a/crates/gpui/src/app.rs +++ b/crates/gpui/src/app.rs @@ -192,11 +192,18 @@ impl App { cx.borrow_mut().quit(); } })); + foreground_platform.on_will_open_menu(Box::new({ + let cx = app.0.clone(); + move || { + let mut cx = cx.borrow_mut(); + cx.keystroke_matcher.clear_pending(); + } + })); foreground_platform.on_validate_menu_command(Box::new({ let cx = app.0.clone(); move |action| { let cx = cx.borrow_mut(); - cx.is_action_available(action) + !cx.keystroke_matcher.has_pending_keystrokes() && cx.is_action_available(action) } })); foreground_platform.on_menu_command(Box::new({ diff --git a/crates/gpui/src/keymap.rs b/crates/gpui/src/keymap.rs index c42fbff907061e5e6813da2411477b62a697c28c..bd156ed66149007068b2b8fc4f1b9be58c479390 100644 --- a/crates/gpui/src/keymap.rs +++ b/crates/gpui/src/keymap.rs @@ -123,6 +123,10 @@ impl Matcher { self.pending.clear(); } + pub fn has_pending_keystrokes(&self) -> bool { + !self.pending.is_empty() + } + pub fn push_keystroke( &mut self, keystroke: Keystroke, diff --git a/crates/gpui/src/platform.rs b/crates/gpui/src/platform.rs index 68eefeca67ec19466aac030454f18838f354892a..c4b68c0741703530cba643c67515d6e90a06f452 100644 --- a/crates/gpui/src/platform.rs +++ b/crates/gpui/src/platform.rs @@ -74,6 +74,7 @@ pub(crate) trait ForegroundPlatform { fn on_menu_command(&self, callback: Box); fn on_validate_menu_command(&self, callback: Box bool>); + fn on_will_open_menu(&self, callback: Box); fn set_menus(&self, menus: Vec, matcher: &keymap::Matcher); fn prompt_for_paths( &self, diff --git a/crates/gpui/src/platform/mac/platform.rs b/crates/gpui/src/platform/mac/platform.rs index 46c2b50f4e4bc197759f799eaba714ead95d0a48..26cde46c0492eb82138192c962e83f553baeb876 100644 --- a/crates/gpui/src/platform/mac/platform.rs +++ b/crates/gpui/src/platform/mac/platform.rs @@ -93,6 +93,10 @@ unsafe fn build_classes() { sel!(validateMenuItem:), validate_menu_item as extern "C" fn(&mut Object, Sel, id) -> bool, ); + decl.add_method( + sel!(menuWillOpen:), + menu_will_open as extern "C" fn(&mut Object, Sel, id), + ); decl.add_method( sel!(application:openURLs:), open_urls as extern "C" fn(&mut Object, Sel, id, id), @@ -112,14 +116,21 @@ pub struct MacForegroundPlatformState { event: Option bool>>, menu_command: Option>, validate_menu_command: Option bool>>, + will_open_menu: Option>, open_urls: Option)>>, finish_launching: Option ()>>, menu_actions: Vec>, } impl MacForegroundPlatform { - unsafe fn create_menu_bar(&self, menus: Vec, keystroke_matcher: &keymap::Matcher) -> id { + unsafe fn create_menu_bar( + &self, + menus: Vec, + delegate: id, + keystroke_matcher: &keymap::Matcher, + ) -> id { let menu_bar = NSMenu::new(nil).autorelease(); + menu_bar.setDelegate_(delegate); let mut state = self.0.borrow_mut(); state.menu_actions.clear(); @@ -130,6 +141,7 @@ impl MacForegroundPlatform { let menu_name = menu_config.name; menu.setTitle_(ns_string(menu_name)); + menu.setDelegate_(delegate); for item_config in menu_config.items { let item; @@ -242,6 +254,10 @@ impl platform::ForegroundPlatform for MacForegroundPlatform { self.0.borrow_mut().menu_command = Some(callback); } + fn on_will_open_menu(&self, callback: Box) { + self.0.borrow_mut().will_open_menu = Some(callback); + } + fn on_validate_menu_command(&self, callback: Box bool>) { self.0.borrow_mut().validate_menu_command = Some(callback); } @@ -249,7 +265,7 @@ impl platform::ForegroundPlatform for MacForegroundPlatform { fn set_menus(&self, menus: Vec, keystroke_matcher: &keymap::Matcher) { unsafe { let app: id = msg_send![APP_CLASS, sharedApplication]; - app.setMainMenu_(self.create_menu_bar(menus, keystroke_matcher)); + app.setMainMenu_(self.create_menu_bar(menus, app.delegate(), keystroke_matcher)); } } @@ -764,6 +780,17 @@ extern "C" fn validate_menu_item(this: &mut Object, _: Sel, item: id) -> bool { } } +extern "C" fn menu_will_open(this: &mut Object, _: Sel, _: id) { + unsafe { + let platform = get_foreground_platform(this); + let mut platform = platform.0.borrow_mut(); + if let Some(mut callback) = platform.will_open_menu.take() { + callback(); + platform.will_open_menu = Some(callback); + } + } +} + unsafe fn ns_string(string: &str) -> id { NSString::alloc(nil).init_str(string).autorelease() } diff --git a/crates/gpui/src/platform/test.rs b/crates/gpui/src/platform/test.rs index ce64fdf01a828ee077d34840869eb651292ed638..30ceec335e6dc219bb43f4adefed6a91a9ee0f18 100644 --- a/crates/gpui/src/platform/test.rs +++ b/crates/gpui/src/platform/test.rs @@ -73,9 +73,8 @@ impl super::ForegroundPlatform for ForegroundPlatform { } fn on_menu_command(&self, _: Box) {} - fn on_validate_menu_command(&self, _: Box bool>) {} - + fn on_will_open_menu(&self, _: Box) {} fn set_menus(&self, _: Vec, _: &keymap::Matcher) {} fn prompt_for_paths(