Derive application menu key equivalents from the keymap

This commit is contained in:
Max Brunsfeld 2022-05-19 10:04:01 -07:00
parent 8dd6ad3116
commit 7445197f4d
6 changed files with 23 additions and 34 deletions

View file

@ -18,7 +18,8 @@
"cmd-s": "workspace::Save", "cmd-s": "workspace::Save",
"cmd-=": "zed::IncreaseBufferFontSize", "cmd-=": "zed::IncreaseBufferFontSize",
"cmd--": "zed::DecreaseBufferFontSize", "cmd--": "zed::DecreaseBufferFontSize",
"cmd-,": "zed::OpenSettings" "cmd-,": "zed::OpenSettings",
"cmd-q": "zed::Quit"
} }
}, },
{ {

View file

@ -154,7 +154,6 @@ pub struct Menu<'a> {
pub enum MenuItem<'a> { pub enum MenuItem<'a> {
Action { Action {
name: &'a str, name: &'a str,
keystroke: Option<&'a str>,
action: Box<dyn Action>, action: Box<dyn Action>,
}, },
Separator, Separator,
@ -1070,7 +1069,8 @@ impl MutableAppContext {
} }
pub fn set_menus(&mut self, menus: Vec<Menu>) { pub fn set_menus(&mut self, menus: Vec<Menu>) {
self.foreground_platform.set_menus(menus); self.foreground_platform
.set_menus(menus, &self.keystroke_matcher);
} }
fn prompt( fn prompt(

View file

@ -14,6 +14,7 @@ use crate::{
rect::{RectF, RectI}, rect::{RectF, RectI},
vector::Vector2F, vector::Vector2F,
}, },
keymap,
text_layout::{LineLayout, RunStyle}, text_layout::{LineLayout, RunStyle},
Action, ClipboardItem, Menu, Scene, Action, ClipboardItem, Menu, Scene,
}; };
@ -72,7 +73,7 @@ pub(crate) trait ForegroundPlatform {
fn run(&self, on_finish_launching: Box<dyn FnOnce() -> ()>); fn run(&self, on_finish_launching: Box<dyn FnOnce() -> ()>);
fn on_menu_command(&self, callback: Box<dyn FnMut(&dyn Action)>); fn on_menu_command(&self, callback: Box<dyn FnMut(&dyn Action)>);
fn set_menus(&self, menus: Vec<Menu>); fn set_menus(&self, menus: Vec<Menu>, matcher: &keymap::Matcher);
fn prompt_for_paths( fn prompt_for_paths(
&self, &self,
options: PathPromptOptions, options: PathPromptOptions,

View file

@ -1,7 +1,6 @@
use super::{BoolExt as _, Dispatcher, FontSystem, Window}; use super::{BoolExt as _, Dispatcher, FontSystem, Window};
use crate::{ use crate::{
executor, executor, keymap,
keymap::Keystroke,
platform::{self, CursorStyle}, platform::{self, CursorStyle},
Action, ClipboardItem, Event, Menu, MenuItem, Action, ClipboardItem, Event, Menu, MenuItem,
}; };
@ -114,7 +113,7 @@ pub struct MacForegroundPlatformState {
} }
impl MacForegroundPlatform { impl MacForegroundPlatform {
unsafe fn create_menu_bar(&self, menus: Vec<Menu>) -> id { unsafe fn create_menu_bar(&self, menus: Vec<Menu>, keystroke_matcher: &keymap::Matcher) -> id {
let menu_bar = NSMenu::new(nil).autorelease(); let menu_bar = NSMenu::new(nil).autorelease();
let mut state = self.0.borrow_mut(); let mut state = self.0.borrow_mut();
@ -134,19 +133,18 @@ impl MacForegroundPlatform {
MenuItem::Separator => { MenuItem::Separator => {
item = NSMenuItem::separatorItem(nil); item = NSMenuItem::separatorItem(nil);
} }
MenuItem::Action { MenuItem::Action { name, action } => {
name, let mut keystroke = None;
keystroke, if let Some(binding) = keystroke_matcher
action, .bindings_for_action_type(action.as_any().type_id())
} => { .next()
if let Some(keystroke) = keystroke { {
let keystroke = Keystroke::parse(keystroke).unwrap_or_else(|err| { if binding.keystrokes().len() == 1 {
panic!( keystroke = binding.keystrokes().first()
"Invalid keystroke for menu item {}:{} - {:?}", }
menu_name, name, err }
)
});
if let Some(keystroke) = keystroke {
let mut mask = NSEventModifierFlags::empty(); let mut mask = NSEventModifierFlags::empty();
for (modifier, flag) in &[ for (modifier, flag) in &[
(keystroke.cmd, NSEventModifierFlags::NSCommandKeyMask), (keystroke.cmd, NSEventModifierFlags::NSCommandKeyMask),
@ -239,10 +237,10 @@ impl platform::ForegroundPlatform for MacForegroundPlatform {
self.0.borrow_mut().menu_command = Some(callback); self.0.borrow_mut().menu_command = Some(callback);
} }
fn set_menus(&self, menus: Vec<Menu>) { fn set_menus(&self, menus: Vec<Menu>, keystroke_matcher: &keymap::Matcher) {
unsafe { unsafe {
let app: id = msg_send![APP_CLASS, sharedApplication]; let app: id = msg_send![APP_CLASS, sharedApplication];
app.setMainMenu_(self.create_menu_bar(menus)); app.setMainMenu_(self.create_menu_bar(menus, keystroke_matcher));
} }
} }

View file

@ -1,7 +1,7 @@
use super::{AppVersion, CursorStyle, WindowBounds}; use super::{AppVersion, CursorStyle, WindowBounds};
use crate::{ use crate::{
geometry::vector::{vec2f, Vector2F}, geometry::vector::{vec2f, Vector2F},
Action, ClipboardItem, keymap, Action, ClipboardItem,
}; };
use anyhow::{anyhow, Result}; use anyhow::{anyhow, Result};
use parking_lot::Mutex; use parking_lot::Mutex;
@ -74,7 +74,7 @@ impl super::ForegroundPlatform for ForegroundPlatform {
fn on_menu_command(&self, _: Box<dyn FnMut(&dyn Action)>) {} fn on_menu_command(&self, _: Box<dyn FnMut(&dyn Action)>) {}
fn set_menus(&self, _: Vec<crate::Menu>) {} fn set_menus(&self, _: Vec<crate::Menu>, _: &keymap::Matcher) {}
fn prompt_for_paths( fn prompt_for_paths(
&self, &self,

View file

@ -10,24 +10,20 @@ pub fn menus(state: &Arc<AppState>) -> Vec<Menu<'static>> {
items: vec![ items: vec![
MenuItem::Action { MenuItem::Action {
name: "About Zed…", name: "About Zed…",
keystroke: None,
action: Box::new(super::About), action: Box::new(super::About),
}, },
MenuItem::Action { MenuItem::Action {
name: "Check for Updates", name: "Check for Updates",
keystroke: None,
action: Box::new(auto_update::Check), action: Box::new(auto_update::Check),
}, },
MenuItem::Separator, MenuItem::Separator,
MenuItem::Action { MenuItem::Action {
name: "Install CLI", name: "Install CLI",
keystroke: None,
action: Box::new(super::InstallCommandLineInterface), action: Box::new(super::InstallCommandLineInterface),
}, },
MenuItem::Separator, MenuItem::Separator,
MenuItem::Action { MenuItem::Action {
name: "Quit", name: "Quit",
keystroke: Some("cmd-q"),
action: Box::new(super::Quit), action: Box::new(super::Quit),
}, },
], ],
@ -37,13 +33,11 @@ pub fn menus(state: &Arc<AppState>) -> Vec<Menu<'static>> {
items: vec![ items: vec![
MenuItem::Action { MenuItem::Action {
name: "New", name: "New",
keystroke: Some("cmd-n"),
action: Box::new(workspace::OpenNew(state.clone())), action: Box::new(workspace::OpenNew(state.clone())),
}, },
MenuItem::Separator, MenuItem::Separator,
MenuItem::Action { MenuItem::Action {
name: "Open…", name: "Open…",
keystroke: Some("cmd-o"),
action: Box::new(workspace::Open(state.clone())), action: Box::new(workspace::Open(state.clone())),
}, },
], ],
@ -53,28 +47,23 @@ pub fn menus(state: &Arc<AppState>) -> Vec<Menu<'static>> {
items: vec![ items: vec![
MenuItem::Action { MenuItem::Action {
name: "Undo", name: "Undo",
keystroke: Some("cmd-z"),
action: Box::new(editor::Undo), action: Box::new(editor::Undo),
}, },
MenuItem::Action { MenuItem::Action {
name: "Redo", name: "Redo",
keystroke: Some("cmd-Z"),
action: Box::new(editor::Redo), action: Box::new(editor::Redo),
}, },
MenuItem::Separator, MenuItem::Separator,
MenuItem::Action { MenuItem::Action {
name: "Cut", name: "Cut",
keystroke: Some("cmd-x"),
action: Box::new(editor::Cut), action: Box::new(editor::Cut),
}, },
MenuItem::Action { MenuItem::Action {
name: "Copy", name: "Copy",
keystroke: Some("cmd-c"),
action: Box::new(editor::Copy), action: Box::new(editor::Copy),
}, },
MenuItem::Action { MenuItem::Action {
name: "Paste", name: "Paste",
keystroke: Some("cmd-v"),
action: Box::new(editor::Paste), action: Box::new(editor::Paste),
}, },
], ],