use crate::{ BoolExt, MacDispatcher, MacDisplay, MacKeyboardLayout, MacKeyboardMapper, MacWindow, events::key_to_native, ns_string, pasteboard::Pasteboard, renderer, set_active_window_cursor_style,};use anyhow::{Context as _, anyhow};use block::ConcreteBlock;use cocoa::{ appkit::{ NSAppearanceNameVibrantDark, NSAppearanceNameVibrantLight, NSApplication, NSApplicationActivationPolicy::NSApplicationActivationPolicyRegular, NSControl as _, NSEventModifierFlags, NSMenu, NSMenuItem, NSModalResponse, NSOpenPanel, NSSavePanel, NSVisualEffectState, NSVisualEffectView, NSWindow, }, base::{BOOL, NO, YES, id, nil, selector}, foundation::{ NSArray, NSAutoreleasePool, NSBundle, NSInteger, NSProcessInfo, NSString, NSUInteger, NSURL, },};use core_foundation::{ base::{CFRelease, CFType, CFTypeRef, OSStatus, TCFType}, boolean::CFBoolean, data::CFData, dictionary::{CFDictionary, CFDictionaryRef, CFMutableDictionary}, runloop::CFRunLoopRun, string::{CFString, CFStringRef},};use ctor::ctor;use dispatch2::DispatchQueue;use futures::channel::oneshot;use gpui::{ Action, AnyWindowHandle, BackgroundExecutor, ClipboardItem, CursorStyle, ForegroundExecutor, KeyContext, Keymap, Menu, MenuItem, OsMenu, OwnedMenu, PathPromptOptions, Platform, PlatformDisplay, PlatformKeyboardLayout, PlatformKeyboardMapper, PlatformTextSystem, PlatformWindow, Result, SystemMenuType, Task, ThermalState, WindowAppearance, WindowKind, WindowParams, popup::PopupNotSupportedError,};use gpui_util::{ResultExt, new_std_command};use itertools::Itertools;use objc::{ class, declare::ClassDecl, msg_send, runtime::{Class, Object, Sel}, sel, sel_impl,};use parking_lot::Mutex;use ptr::null_mut;use semver::Version;use std::{ cell::Cell, ffi::{CStr, OsStr, c_void}, os::{raw::c_char, unix::ffi::OsStrExt}, path::{Path, PathBuf}, ptr, rc::Rc, slice, str, sync::{ Arc, OnceLock, atomic::{AtomicBool, Ordering}, },}; #[allow(non_upper_case_globals)]const NSUTF8StringEncoding: NSUInteger = 4; const MAC_PLATFORM_IVAR: &str = "platform";static mut APP_CLASS: *const Class = ptr::null();static mut APP_DELEGATE_CLASS: *const Class = ptr::null(); #[ctor(unsafe)]unsafe fn build_classes() { unsafe { APP_CLASS = { let mut decl = ClassDecl::new("GPUIApplication", class!(NSApplication)).unwrap(); decl.add_ivar::<*mut c_void>(MAC_PLATFORM_IVAR); decl.register() } }; unsafe { APP_DELEGATE_CLASS = { let mut decl = ClassDecl::new("GPUIApplicationDelegate", class!(NSResponder)).unwrap(); decl.add_ivar::<*mut c_void>(MAC_PLATFORM_IVAR); decl.add_method( sel!(applicationWillFinishLaunching:), will_finish_launching as extern "C" fn(&mut Object, Sel, id), ); decl.add_method( sel!(applicationDidFinishLaunching:), did_finish_launching as extern "C" fn(&mut Object, Sel, id), ); decl.add_method( sel!(applicationShouldHandleReopen:hasVisibleWindows:), should_handle_reopen as extern "C" fn(&mut Object, Sel, id, bool), ); decl.add_method( sel!(applicationWillTerminate:), will_terminate as extern "C" fn(&mut Object, Sel, id), ); decl.add_method( sel!(handleGPUIMenuItem:), handle_menu_item as extern "C" fn(&mut Object, Sel, id), ); // Add menu item handlers so that OS save panels have the correct key commands decl.add_method( sel!(cut:), handle_menu_item as extern "C" fn(&mut Object, Sel, id), ); decl.add_method( sel!(copy:), handle_menu_item as extern "C" fn(&mut Object, Sel, id), ); decl.add_method( sel!(paste:), handle_menu_item as extern "C" fn(&mut Object, Sel, id), ); decl.add_method( sel!(selectAll:), handle_menu_item as extern "C" fn(&mut Object, Sel, id), ); decl.add_method( sel!(undo:), handle_menu_item as extern "C" fn(&mut Object, Sel, id), ); decl.add_method( sel!(redo:), handle_menu_item as extern "C" fn(&mut Object, Sel, id), ); decl.add_method( 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!(applicationDockMenu:), handle_dock_menu as extern "C" fn(&mut Object, Sel, id) -> id, ); decl.add_method( sel!(application:openURLs:), open_urls as extern "C" fn(&mut Object, Sel, id, id), ); decl.add_method( sel!(onKeyboardLayoutChange:), on_keyboard_layout_change as extern "C" fn(&mut Object, Sel, id), ); decl.add_method( sel!(onThermalStateChange:), on_thermal_state_change as extern "C" fn(&mut Object, Sel, id), ); decl.add_method( sel!(onSystemWake:), on_system_wake as extern "C" fn(&mut Object, Sel, id), ); decl.register() } }} pub struct MacPlatform(Mutex<MacPlatformState>); pub(crate) struct MacPlatformState { background_executor: BackgroundExecutor, foreground_executor: ForegroundExecutor, text_system: Arc<dyn PlatformTextSystem>, renderer_context: renderer::Context, headless: bool, general_pasteboard: Pasteboard, find_pasteboard: Pasteboard, reopen: Option<Box<dyn FnMut()>>, on_keyboard_layout_change: Option<Box<dyn FnMut()>>, on_thermal_state_change: Option<Box<dyn FnMut()>>, on_system_wake: Option<Box<dyn FnMut()>>, system_wake_observer_registered: bool, quit: Option<Box<dyn FnMut()>>, menu_command: Option<Box<dyn FnMut(&dyn Action)>>, validate_menu_command: Option<Box<dyn FnMut(&dyn Action) -> bool>>, will_open_menu: Option<Box<dyn FnMut()>>, menu_actions: Vec<Box<dyn Action>>, open_urls: Option<Box<dyn FnMut(Vec<String>)>>, finish_launching: Option<Box<dyn FnOnce()>>, dock_menu: Option<id>, menus: Option<Vec<OwnedMenu>>, keyboard_mapper: Rc<MacKeyboardMapper>, /// Mirrors `[NSCursor setHiddenUntilMouseMoves:]` state, which AppKit doesn't expose. cursor_visible: Arc<AtomicBool>, system_notifications: crate::system_notifications::SystemNotificationState,} impl MacPlatform { pub fn new(headless: bool) -> Self { let dispatcher = Arc::new(MacDispatcher::new()); #[cfg(feature = "font-kit")] let text_system = Arc::new(crate::MacTextSystem::new()); #[cfg(not(feature = "font-kit"))] let text_system = { if !headless { log::warn!( "gpui_macos was compiled without the `font-kit` feature, so no text will be rendered." ); } Arc::new(gpui::NoopTextSystem::new()) }; let keyboard_layout = MacKeyboardLayout::new(); let keyboard_mapper = Rc::new(MacKeyboardMapper::new(keyboard_layout.id())); Self(Mutex::new(MacPlatformState { headless, text_system, background_executor: BackgroundExecutor::new(dispatcher.clone()), foreground_executor: ForegroundExecutor::new(dispatcher), renderer_context: renderer::Context::default(), general_pasteboard: Pasteboard::general(), find_pasteboard: Pasteboard::find(), reopen: None, quit: None, menu_command: None, validate_menu_command: None, will_open_menu: None, menu_actions: Default::default(), open_urls: None, finish_launching: None, dock_menu: None, on_keyboard_layout_change: None, on_thermal_state_change: None, on_system_wake: None, system_wake_observer_registered: false, menus: None, keyboard_mapper, cursor_visible: Arc::new(AtomicBool::new(true)), system_notifications: crate::system_notifications::SystemNotificationState::new(), })) } unsafe fn create_menu_bar( &self, menus: &Vec<Menu>, delegate: id, actions: &mut Vec<Box<dyn Action>>, keymap: &Keymap, ) -> id { unsafe { let application_menu = NSMenu::new(nil).autorelease(); application_menu.setDelegate_(delegate); for menu_config in menus { let menu = NSMenu::new(nil).autorelease(); let menu_title = ns_string(&menu_config.name); menu.setTitle_(menu_title); menu.setDelegate_(delegate); for item_config in &menu_config.items { menu.addItem_(Self::create_menu_item( item_config, delegate, actions, keymap, )); } let menu_item = NSMenuItem::new(nil).autorelease(); menu_item.setTitle_(menu_title); menu_item.setSubmenu_(menu); application_menu.addItem_(menu_item); if menu_config.name == "Window" { let app: id = msg_send![APP_CLASS, sharedApplication]; app.setWindowsMenu_(menu); } } application_menu } } unsafe fn create_dock_menu( &self, menu_items: Vec<MenuItem>, delegate: id, actions: &mut Vec<Box<dyn Action>>, keymap: &Keymap, ) -> id { unsafe { let dock_menu = NSMenu::new(nil); dock_menu.setDelegate_(delegate); for item_config in menu_items { dock_menu.addItem_(Self::create_menu_item( &item_config, delegate, actions, keymap, )); } dock_menu } } unsafe fn create_menu_item( item: &MenuItem, delegate: id, actions: &mut Vec<Box<dyn Action>>, keymap: &Keymap, ) -> id { static DEFAULT_CONTEXT: OnceLock<Vec<KeyContext>> = OnceLock::new(); unsafe { match item { MenuItem::Separator => NSMenuItem::separatorItem(nil), MenuItem::Action { name, action, os_action, checked, disabled, } => { // Note that this is intentionally using earlier bindings, whereas typically // later ones take display precedence. See the discussion on // https://github.com/zed-industries/zed/issues/23621 let keystrokes = keymap .bindings_for_action(action.as_ref()) .find_or_first(|binding| { binding.predicate().is_none_or(|predicate| { predicate.eval(DEFAULT_CONTEXT.get_or_init(|| { let mut workspace_context = KeyContext::new_with_defaults(); workspace_context.add("Workspace"); let mut pane_context = KeyContext::new_with_defaults(); pane_context.add("Pane"); let mut editor_context = KeyContext::new_with_defaults(); editor_context.add("Editor"); pane_context.extend(&editor_context); workspace_context.extend(&pane_context); vec![workspace_context] })) }) }) .map(|binding| binding.keystrokes()); let selector = match os_action { Some(gpui::OsAction::Cut) => selector("cut:"), Some(gpui::OsAction::Copy) => selector("copy:"), Some(gpui::OsAction::Paste) => selector("paste:"), Some(gpui::OsAction::SelectAll) => selector("selectAll:"), // "undo:" and "redo:" are always disabled in our case, as // we don't have a NSTextView/NSTextField to enable them on. Some(gpui::OsAction::Undo) => selector("handleGPUIMenuItem:"), Some(gpui::OsAction::Redo) => selector("handleGPUIMenuItem:"), None => selector("handleGPUIMenuItem:"), }; let item; if let Some(keystrokes) = keystrokes { if keystrokes.len() == 1 { let keystroke = &keystrokes[0]; let mut mask = NSEventModifierFlags::empty(); for (modifier, flag) in &[ ( keystroke.modifiers().platform, NSEventModifierFlags::NSCommandKeyMask, ), ( keystroke.modifiers().control, NSEventModifierFlags::NSControlKeyMask, ), ( keystroke.modifiers().alt, NSEventModifierFlags::NSAlternateKeyMask, ), ( keystroke.modifiers().shift, NSEventModifierFlags::NSShiftKeyMask, ), ] { if *modifier { mask |= *flag; } } item = NSMenuItem::alloc(nil) .initWithTitle_action_keyEquivalent_( ns_string(name), selector, ns_string(key_to_native(keystroke.key()).as_ref()), ) .autorelease(); if Self::os_version() >= Version::new(12, 0, 0) { let _: () = msg_send![item, setAllowsAutomaticKeyEquivalentLocalization: NO]; } item.setKeyEquivalentModifierMask_(mask); } else { item = NSMenuItem::alloc(nil) .initWithTitle_action_keyEquivalent_( ns_string(name), selector, ns_string(""), ) .autorelease(); } } else { item = NSMenuItem::alloc(nil) .initWithTitle_action_keyEquivalent_( ns_string(name), selector, ns_string(""), ) .autorelease(); } if *checked { item.setState_(NSVisualEffectState::Active); } item.setEnabled_(if *disabled { NO } else { YES }); let tag = actions.len() as NSInteger; let _: () = msg_send![item, setTag: tag]; actions.push(action.boxed_clone()); item } MenuItem::Submenu(Menu { name, items, disabled, }) => { let item = NSMenuItem::new(nil).autorelease(); let submenu = NSMenu::new(nil).autorelease(); submenu.setDelegate_(delegate); for item in items { submenu.addItem_(Self::create_menu_item(item, delegate, actions, keymap)); } item.setSubmenu_(submenu); item.setEnabled_(if *disabled { NO } else { YES }); item.setTitle_(ns_string(name)); item } MenuItem::SystemMenu(OsMenu { name, menu_type }) => { let item = NSMenuItem::new(nil).autorelease(); let submenu = NSMenu::new(nil).autorelease(); submenu.setDelegate_(delegate); item.setSubmenu_(submenu); item.setTitle_(ns_string(name)); match menu_type { SystemMenuType::Services => { let app: id = msg_send![APP_CLASS, sharedApplication]; app.setServicesMenu_(item); } } item } } } } fn os_version() -> Version { let version = unsafe { let process_info = NSProcessInfo::processInfo(nil); process_info.operatingSystemVersion() }; Version::new( version.majorVersion, version.minorVersion, version.patchVersion, ) }} impl Platform for MacPlatform { fn background_executor(&self) -> BackgroundExecutor { self.0.lock().background_executor.clone() } fn foreground_executor(&self) -> gpui::ForegroundExecutor { self.0.lock().foreground_executor.clone() } fn text_system(&self) -> Arc<dyn PlatformTextSystem> { self.0.lock().text_system.clone() } fn run(&self, on_finish_launching: Box<dyn FnOnce()>) { let mut state = self.0.lock(); if state.headless { drop(state); on_finish_launching(); unsafe { CFRunLoopRun() }; } else { state.finish_launching = Some(on_finish_launching); drop(state); }Lines 1–500 of 1561. Load more
use crate::{ BoolExt, MacDispatcher, MacDisplay, MacKeyboardLayout, MacKeyboardMapper, MacWindow, events::key_to_native, ns_string, pasteboard::Pasteboard, renderer, set_active_window_cursor_style, }; use anyhow::{Context as _, anyhow}; use block::ConcreteBlock; use cocoa::{ appkit::{ NSAppearanceNameVibrantDark, NSAppearanceNameVibrantLight, NSApplication, NSApplicationActivationPolicy::NSApplicationActivationPolicyRegular, NSControl as _, NSEventModifierFlags, NSMenu, NSMenuItem, NSModalResponse, NSOpenPanel, NSSavePanel, NSVisualEffectState, NSVisualEffectView, NSWindow, }, base::{BOOL, NO, YES, id, nil, selector}, foundation::{ NSArray, NSAutoreleasePool, NSBundle, NSInteger, NSProcessInfo, NSString, NSUInteger, NSURL, }, }; use core_foundation::{ base::{CFRelease, CFType, CFTypeRef, OSStatus, TCFType}, boolean::CFBoolean, data::CFData, dictionary::{CFDictionary, CFDictionaryRef, CFMutableDictionary}, runloop::CFRunLoopRun, string::{CFString, CFStringRef}, }; use ctor::ctor; use dispatch2::DispatchQueue; use futures::channel::oneshot; use gpui::{ Action, AnyWindowHandle, BackgroundExecutor, ClipboardItem, CursorStyle, ForegroundExecutor, KeyContext, Keymap, Menu, MenuItem, OsMenu, OwnedMenu, PathPromptOptions, Platform, PlatformDisplay, PlatformKeyboardLayout, PlatformKeyboardMapper, PlatformTextSystem, PlatformWindow, Result, SystemMenuType, Task, ThermalState, WindowAppearance, WindowKind, WindowParams, popup::PopupNotSupportedError, }; use gpui_util::{ResultExt, new_std_command}; use itertools::Itertools; use objc::{ class, declare::ClassDecl, msg_send, runtime::{Class, Object, Sel}, sel, sel_impl, }; use parking_lot::Mutex; use ptr::null_mut; use semver::Version; use std::{ cell::Cell, ffi::{CStr, OsStr, c_void}, os::{raw::c_char, unix::ffi::OsStrExt}, path::{Path, PathBuf}, ptr, rc::Rc, slice, str, sync::{ Arc, OnceLock, atomic::{AtomicBool, Ordering}, }, }; #[allow(non_upper_case_globals)] const NSUTF8StringEncoding: NSUInteger = 4; const MAC_PLATFORM_IVAR: &str = "platform"; static mut APP_CLASS: *const Class = ptr::null(); static mut APP_DELEGATE_CLASS: *const Class = ptr::null(); #[ctor(unsafe)] unsafe fn build_classes() { unsafe { APP_CLASS = { let mut decl = ClassDecl::new("GPUIApplication", class!(NSApplication)).unwrap(); decl.add_ivar::<*mut c_void>(MAC_PLATFORM_IVAR); decl.register() } }; unsafe { APP_DELEGATE_CLASS = { let mut decl = ClassDecl::new("GPUIApplicationDelegate", class!(NSResponder)).unwrap(); decl.add_ivar::<*mut c_void>(MAC_PLATFORM_IVAR); decl.add_method( sel!(applicationWillFinishLaunching:), will_finish_launching as extern "C" fn(&mut Object, Sel, id), ); decl.add_method( sel!(applicationDidFinishLaunching:), did_finish_launching as extern "C" fn(&mut Object, Sel, id), ); decl.add_method( sel!(applicationShouldHandleReopen:hasVisibleWindows:), should_handle_reopen as extern "C" fn(&mut Object, Sel, id, bool), ); decl.add_method( sel!(applicationWillTerminate:), will_terminate as extern "C" fn(&mut Object, Sel, id), ); decl.add_method( sel!(handleGPUIMenuItem:), handle_menu_item as extern "C" fn(&mut Object, Sel, id), ); // Add menu item handlers so that OS save panels have the correct key commands decl.add_method( sel!(cut:), handle_menu_item as extern "C" fn(&mut Object, Sel, id), ); decl.add_method( sel!(copy:), handle_menu_item as extern "C" fn(&mut Object, Sel, id), ); decl.add_method( sel!(paste:), handle_menu_item as extern "C" fn(&mut Object, Sel, id), ); decl.add_method( sel!(selectAll:), handle_menu_item as extern "C" fn(&mut Object, Sel, id), ); decl.add_method( sel!(undo:), handle_menu_item as extern "C" fn(&mut Object, Sel, id), ); decl.add_method( sel!(redo:), handle_menu_item as extern "C" fn(&mut Object, Sel, id), ); decl.add_method( 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!(applicationDockMenu:), handle_dock_menu as extern "C" fn(&mut Object, Sel, id) -> id, ); decl.add_method( sel!(application:openURLs:), open_urls as extern "C" fn(&mut Object, Sel, id, id), ); decl.add_method( sel!(onKeyboardLayoutChange:), on_keyboard_layout_change as extern "C" fn(&mut Object, Sel, id), ); decl.add_method( sel!(onThermalStateChange:), on_thermal_state_change as extern "C" fn(&mut Object, Sel, id), ); decl.add_method( sel!(onSystemWake:), on_system_wake as extern "C" fn(&mut Object, Sel, id), ); decl.register() } } } pub struct MacPlatform(Mutex<MacPlatformState>); pub(crate) struct MacPlatformState { background_executor: BackgroundExecutor, foreground_executor: ForegroundExecutor, text_system: Arc<dyn PlatformTextSystem>, renderer_context: renderer::Context, headless: bool, general_pasteboard: Pasteboard, find_pasteboard: Pasteboard, reopen: Option<Box<dyn FnMut()>>, on_keyboard_layout_change: Option<Box<dyn FnMut()>>, on_thermal_state_change: Option<Box<dyn FnMut()>>, on_system_wake: Option<Box<dyn FnMut()>>, system_wake_observer_registered: bool, quit: Option<Box<dyn FnMut()>>, menu_command: Option<Box<dyn FnMut(&dyn Action)>>, validate_menu_command: Option<Box<dyn FnMut(&dyn Action) -> bool>>, will_open_menu: Option<Box<dyn FnMut()>>, menu_actions: Vec<Box<dyn Action>>, open_urls: Option<Box<dyn FnMut(Vec<String>)>>, finish_launching: Option<Box<dyn FnOnce()>>, dock_menu: Option<id>, menus: Option<Vec<OwnedMenu>>, keyboard_mapper: Rc<MacKeyboardMapper>, /// Mirrors `[NSCursor setHiddenUntilMouseMoves:]` state, which AppKit doesn't expose. cursor_visible: Arc<AtomicBool>, system_notifications: crate::system_notifications::SystemNotificationState, } impl MacPlatform { pub fn new(headless: bool) -> Self { let dispatcher = Arc::new(MacDispatcher::new()); #[cfg(feature = "font-kit")] let text_system = Arc::new(crate::MacTextSystem::new()); #[cfg(not(feature = "font-kit"))] let text_system = { if !headless { log::warn!( "gpui_macos was compiled without the `font-kit` feature, so no text will be rendered." ); } Arc::new(gpui::NoopTextSystem::new()) }; let keyboard_layout = MacKeyboardLayout::new(); let keyboard_mapper = Rc::new(MacKeyboardMapper::new(keyboard_layout.id())); Self(Mutex::new(MacPlatformState { headless, text_system, background_executor: BackgroundExecutor::new(dispatcher.clone()), foreground_executor: ForegroundExecutor::new(dispatcher), renderer_context: renderer::Context::default(), general_pasteboard: Pasteboard::general(), find_pasteboard: Pasteboard::find(), reopen: None, quit: None, menu_command: None, validate_menu_command: None, will_open_menu: None, menu_actions: Default::default(), open_urls: None, finish_launching: None, dock_menu: None, on_keyboard_layout_change: None, on_thermal_state_change: None, on_system_wake: None, system_wake_observer_registered: false, menus: None, keyboard_mapper, cursor_visible: Arc::new(AtomicBool::new(true)), system_notifications: crate::system_notifications::SystemNotificationState::new(), })) } unsafe fn create_menu_bar( &self, menus: &Vec<Menu>, delegate: id, actions: &mut Vec<Box<dyn Action>>, keymap: &Keymap, ) -> id { unsafe { let application_menu = NSMenu::new(nil).autorelease(); application_menu.setDelegate_(delegate); for menu_config in menus { let menu = NSMenu::new(nil).autorelease(); let menu_title = ns_string(&menu_config.name); menu.setTitle_(menu_title); menu.setDelegate_(delegate); for item_config in &menu_config.items { menu.addItem_(Self::create_menu_item( item_config, delegate, actions, keymap, )); } let menu_item = NSMenuItem::new(nil).autorelease(); menu_item.setTitle_(menu_title); menu_item.setSubmenu_(menu); application_menu.addItem_(menu_item); if menu_config.name == "Window" { let app: id = msg_send![APP_CLASS, sharedApplication]; app.setWindowsMenu_(menu); } } application_menu } } unsafe fn create_dock_menu( &self, menu_items: Vec<MenuItem>, delegate: id, actions: &mut Vec<Box<dyn Action>>, keymap: &Keymap, ) -> id { unsafe { let dock_menu = NSMenu::new(nil); dock_menu.setDelegate_(delegate); for item_config in menu_items { dock_menu.addItem_(Self::create_menu_item( &item_config, delegate, actions, keymap, )); } dock_menu } } unsafe fn create_menu_item( item: &MenuItem, delegate: id, actions: &mut Vec<Box<dyn Action>>, keymap: &Keymap, ) -> id { static DEFAULT_CONTEXT: OnceLock<Vec<KeyContext>> = OnceLock::new(); unsafe { match item { MenuItem::Separator => NSMenuItem::separatorItem(nil), MenuItem::Action { name, action, os_action, checked, disabled, } => { // Note that this is intentionally using earlier bindings, whereas typically // later ones take display precedence. See the discussion on // https://github.com/zed-industries/zed/issues/23621 let keystrokes = keymap .bindings_for_action(action.as_ref()) .find_or_first(|binding| { binding.predicate().is_none_or(|predicate| { predicate.eval(DEFAULT_CONTEXT.get_or_init(|| { let mut workspace_context = KeyContext::new_with_defaults(); workspace_context.add("Workspace"); let mut pane_context = KeyContext::new_with_defaults(); pane_context.add("Pane"); let mut editor_context = KeyContext::new_with_defaults(); editor_context.add("Editor"); pane_context.extend(&editor_context); workspace_context.extend(&pane_context); vec![workspace_context] })) }) }) .map(|binding| binding.keystrokes()); let selector = match os_action { Some(gpui::OsAction::Cut) => selector("cut:"), Some(gpui::OsAction::Copy) => selector("copy:"), Some(gpui::OsAction::Paste) => selector("paste:"), Some(gpui::OsAction::SelectAll) => selector("selectAll:"), // "undo:" and "redo:" are always disabled in our case, as // we don't have a NSTextView/NSTextField to enable them on. Some(gpui::OsAction::Undo) => selector("handleGPUIMenuItem:"), Some(gpui::OsAction::Redo) => selector("handleGPUIMenuItem:"), None => selector("handleGPUIMenuItem:"), }; let item; if let Some(keystrokes) = keystrokes { if keystrokes.len() == 1 { let keystroke = &keystrokes[0]; let mut mask = NSEventModifierFlags::empty(); for (modifier, flag) in &[ ( keystroke.modifiers().platform, NSEventModifierFlags::NSCommandKeyMask, ), ( keystroke.modifiers().control, NSEventModifierFlags::NSControlKeyMask, ), ( keystroke.modifiers().alt, NSEventModifierFlags::NSAlternateKeyMask, ), ( keystroke.modifiers().shift, NSEventModifierFlags::NSShiftKeyMask, ), ] { if *modifier { mask |= *flag; } } item = NSMenuItem::alloc(nil) .initWithTitle_action_keyEquivalent_( ns_string(name), selector, ns_string(key_to_native(keystroke.key()).as_ref()), ) .autorelease(); if Self::os_version() >= Version::new(12, 0, 0) { let _: () = msg_send![item, setAllowsAutomaticKeyEquivalentLocalization: NO]; } item.setKeyEquivalentModifierMask_(mask); } else { item = NSMenuItem::alloc(nil) .initWithTitle_action_keyEquivalent_( ns_string(name), selector, ns_string(""), ) .autorelease(); } } else { item = NSMenuItem::alloc(nil) .initWithTitle_action_keyEquivalent_( ns_string(name), selector, ns_string(""), ) .autorelease(); } if *checked { item.setState_(NSVisualEffectState::Active); } item.setEnabled_(if *disabled { NO } else { YES }); let tag = actions.len() as NSInteger; let _: () = msg_send![item, setTag: tag]; actions.push(action.boxed_clone()); item } MenuItem::Submenu(Menu { name, items, disabled, }) => { let item = NSMenuItem::new(nil).autorelease(); let submenu = NSMenu::new(nil).autorelease(); submenu.setDelegate_(delegate); for item in items { submenu.addItem_(Self::create_menu_item(item, delegate, actions, keymap)); } item.setSubmenu_(submenu); item.setEnabled_(if *disabled { NO } else { YES }); item.setTitle_(ns_string(name)); item } MenuItem::SystemMenu(OsMenu { name, menu_type }) => { let item = NSMenuItem::new(nil).autorelease(); let submenu = NSMenu::new(nil).autorelease(); submenu.setDelegate_(delegate); item.setSubmenu_(submenu); item.setTitle_(ns_string(name)); match menu_type { SystemMenuType::Services => { let app: id = msg_send![APP_CLASS, sharedApplication]; app.setServicesMenu_(item); } } item } } } } fn os_version() -> Version { let version = unsafe { let process_info = NSProcessInfo::processInfo(nil); process_info.operatingSystemVersion() }; Version::new( version.majorVersion, version.minorVersion, version.patchVersion, ) } } impl Platform for MacPlatform { fn background_executor(&self) -> BackgroundExecutor { self.0.lock().background_executor.clone() } fn foreground_executor(&self) -> gpui::ForegroundExecutor { self.0.lock().foreground_executor.clone() } fn text_system(&self) -> Arc<dyn PlatformTextSystem> { self.0.lock().text_system.clone() } fn run(&self, on_finish_launching: Box<dyn FnOnce()>) { let mut state = self.0.lock(); if state.headless { drop(state); on_finish_launching(); unsafe { CFRunLoopRun() }; } else { state.finish_launching = Some(on_finish_launching); drop(state); }