Introduce an OSAction that can be associated with menu items for mac platform compatibility.

Co-authored-by: Antonio <antonio@zed.dev>
This commit is contained in:
Mikayla Maki 2023-02-22 09:02:31 -08:00
parent 24fcad3fa2
commit 71d8ead318
4 changed files with 148 additions and 313 deletions

View file

@ -11,9 +11,46 @@ pub enum MenuItem<'a> {
Action { Action {
name: &'a str, name: &'a str,
action: Box<dyn Action>, action: Box<dyn Action>,
os_action: Option<OsAction>,
}, },
} }
impl<'a> MenuItem<'a> {
pub fn separator() -> Self {
Self::Separator
}
pub fn submenu(menu: Menu<'a>) -> Self {
Self::Submenu(menu)
}
pub fn action(name: &'a str, action: impl Action) -> Self {
Self::Action {
name,
action: Box::new(action),
os_action: None,
}
}
pub fn os_action(name: &'a str, action: impl Action, os_action: OsAction) -> Self {
Self::Action {
name,
action: Box::new(action),
os_action: Some(os_action),
}
}
}
#[derive(Copy, Clone, Eq, PartialEq)]
pub enum OsAction {
Cut,
Copy,
Paste,
SelectAll,
Undo,
Redo,
}
impl MutableAppContext { impl MutableAppContext {
pub fn set_menus(&mut self, menus: Vec<Menu>) { pub fn set_menus(&mut self, menus: Vec<Menu>) {
self.foreground_platform self.foreground_platform

View file

@ -193,7 +193,8 @@ impl MacForegroundPlatform {
) -> id { ) -> id {
match item { match item {
MenuItem::Separator => NSMenuItem::separatorItem(nil), MenuItem::Separator => NSMenuItem::separatorItem(nil),
MenuItem::Action { name, action } => { MenuItem::Action { name, action, .. } => {
// TODO
let keystrokes = keystroke_matcher let keystrokes = keystroke_matcher
.bindings_for_action_type(action.as_any().type_id()) .bindings_for_action_type(action.as_any().type_id())
.find(|binding| binding.action().eq(action.as_ref())) .find(|binding| binding.action().eq(action.as_ref()))

View file

@ -20,6 +20,7 @@ fn main() {
items: vec![MenuItem::Action { items: vec![MenuItem::Action {
name: "Quit", name: "Quit",
action: Box::new(Quit), action: Box::new(Quit),
os_action: None,
}], }],
}]); }]);

View file

@ -1,4 +1,4 @@
use gpui::{Menu, MenuItem}; use gpui::{Menu, MenuItem, OsAction};
#[cfg(target_os = "macos")] #[cfg(target_os = "macos")]
pub fn menus() -> Vec<Menu<'static>> { pub fn menus() -> Vec<Menu<'static>> {
@ -6,363 +6,159 @@ pub fn menus() -> Vec<Menu<'static>> {
Menu { Menu {
name: "Zed", name: "Zed",
items: vec![ items: vec![
MenuItem::Action { MenuItem::action("About Zed…", super::About),
name: "About Zed…", MenuItem::action("Check for Updates", auto_update::Check),
action: Box::new(super::About), MenuItem::separator(),
}, MenuItem::submenu(Menu {
MenuItem::Action {
name: "Check for Updates",
action: Box::new(auto_update::Check),
},
MenuItem::Separator,
MenuItem::Submenu(Menu {
name: "Preferences", name: "Preferences",
items: vec![ items: vec![
MenuItem::Action { MenuItem::action("Open Settings", super::OpenSettings),
name: "Open Settings", MenuItem::action("Open Key Bindings", super::OpenKeymap),
action: Box::new(super::OpenSettings), MenuItem::action("Open Default Settings", super::OpenDefaultSettings),
}, MenuItem::action("Open Default Key Bindings", super::OpenDefaultKeymap),
MenuItem::Action { MenuItem::action("Select Theme", theme_selector::Toggle),
name: "Open Key Bindings",
action: Box::new(super::OpenKeymap),
},
MenuItem::Action {
name: "Open Default Settings",
action: Box::new(super::OpenDefaultSettings),
},
MenuItem::Action {
name: "Open Default Key Bindings",
action: Box::new(super::OpenDefaultKeymap),
},
MenuItem::Action {
name: "Select Theme",
action: Box::new(theme_selector::Toggle),
},
], ],
}), }),
MenuItem::Action { MenuItem::action("Install CLI", super::InstallCommandLineInterface),
name: "Install CLI", MenuItem::separator(),
action: Box::new(super::InstallCommandLineInterface), MenuItem::action("Hide Zed", super::Hide),
}, MenuItem::action("Hide Others", super::HideOthers),
MenuItem::Separator, MenuItem::action("Show All", super::ShowAll),
MenuItem::Action { MenuItem::action("Quit", super::Quit),
name: "Hide Zed",
action: Box::new(super::Hide),
},
MenuItem::Action {
name: "Hide Others",
action: Box::new(super::HideOthers),
},
MenuItem::Action {
name: "Show All",
action: Box::new(super::ShowAll),
},
MenuItem::Action {
name: "Quit",
action: Box::new(super::Quit),
},
], ],
}, },
Menu { Menu {
name: "File", name: "File",
items: vec![ items: vec![
MenuItem::Action { MenuItem::action("New", workspace::NewFile),
name: "New", MenuItem::action("New Window", workspace::NewWindow),
action: Box::new(workspace::NewFile), MenuItem::separator(),
}, MenuItem::action("Open…", workspace::Open),
MenuItem::Action { MenuItem::action("Open Recent...", recent_projects::OpenRecent),
name: "New Window", MenuItem::separator(),
action: Box::new(workspace::NewWindow), MenuItem::action("Add Folder to Project…", workspace::AddFolderToProject),
}, MenuItem::action("Save", workspace::Save),
MenuItem::Separator, MenuItem::action("Save As…", workspace::SaveAs),
MenuItem::Action { MenuItem::action("Save All", workspace::SaveAll),
name: "Open…", MenuItem::action("Close Editor", workspace::CloseActiveItem),
action: Box::new(workspace::Open), MenuItem::action("Close Window", workspace::CloseWindow),
},
MenuItem::Action {
name: "Open Recent...",
action: Box::new(recent_projects::OpenRecent),
},
MenuItem::Separator,
MenuItem::Action {
name: "Add Folder to Project…",
action: Box::new(workspace::AddFolderToProject),
},
MenuItem::Action {
name: "Save",
action: Box::new(workspace::Save),
},
MenuItem::Action {
name: "Save As…",
action: Box::new(workspace::SaveAs),
},
MenuItem::Action {
name: "Save All",
action: Box::new(workspace::SaveAll),
},
MenuItem::Action {
name: "Close Editor",
action: Box::new(workspace::CloseActiveItem),
},
MenuItem::Action {
name: "Close Window",
action: Box::new(workspace::CloseWindow),
},
], ],
}, },
Menu { Menu {
name: "Edit", name: "Edit",
items: vec![ items: vec![
MenuItem::Action { MenuItem::os_action("Undo", editor::Undo, OsAction::Undo),
name: "Undo", MenuItem::os_action("Redo", editor::Redo, OsAction::Redo),
action: Box::new(editor::Undo), MenuItem::separator(),
}, MenuItem::os_action("Cut", editor::Cut, OsAction::Cut),
MenuItem::Action { MenuItem::os_action("Copy", editor::Copy, OsAction::Copy),
name: "Redo", MenuItem::os_action("Paste", editor::Paste, OsAction::Paste),
action: Box::new(editor::Redo), MenuItem::separator(),
}, MenuItem::action("Find", search::buffer_search::Deploy { focus: true }),
MenuItem::Separator, MenuItem::action("Find In Project", workspace::NewSearch),
MenuItem::Action { MenuItem::separator(),
name: "Cut", MenuItem::action("Toggle Line Comment", editor::ToggleComments::default()),
action: Box::new(editor::Cut), MenuItem::action("Emoji & Symbols", editor::ShowCharacterPalette),
},
MenuItem::Action {
name: "Copy",
action: Box::new(editor::Copy),
},
MenuItem::Action {
name: "Paste",
action: Box::new(editor::Paste),
},
MenuItem::Separator,
MenuItem::Action {
name: "Find",
action: Box::new(search::buffer_search::Deploy { focus: true }),
},
MenuItem::Action {
name: "Find In Project",
action: Box::new(workspace::NewSearch),
},
MenuItem::Separator,
MenuItem::Action {
name: "Toggle Line Comment",
action: Box::new(editor::ToggleComments::default()),
},
MenuItem::Action {
name: "Emoji & Symbols",
action: Box::new(editor::ShowCharacterPalette),
},
], ],
}, },
Menu { Menu {
name: "Selection", name: "Selection",
items: vec![ items: vec![
MenuItem::Action { MenuItem::os_action("Select All", editor::SelectAll, OsAction::SelectAll),
name: "Select All", MenuItem::action("Expand Selection", editor::SelectLargerSyntaxNode),
action: Box::new(editor::SelectAll), MenuItem::action("Shrink Selection", editor::SelectSmallerSyntaxNode),
}, MenuItem::separator(),
MenuItem::Action { MenuItem::action("Add Cursor Above", editor::AddSelectionAbove),
name: "Expand Selection", MenuItem::action("Add Cursor Below", editor::AddSelectionBelow),
action: Box::new(editor::SelectLargerSyntaxNode), MenuItem::action(
}, "Select Next Occurrence",
MenuItem::Action { editor::SelectNext {
name: "Shrink Selection",
action: Box::new(editor::SelectSmallerSyntaxNode),
},
MenuItem::Separator,
MenuItem::Action {
name: "Add Cursor Above",
action: Box::new(editor::AddSelectionAbove),
},
MenuItem::Action {
name: "Add Cursor Below",
action: Box::new(editor::AddSelectionBelow),
},
MenuItem::Action {
name: "Select Next Occurrence",
action: Box::new(editor::SelectNext {
replace_newest: false, replace_newest: false,
}), },
}, ),
MenuItem::Separator, MenuItem::separator(),
MenuItem::Action { MenuItem::action("Move Line Up", editor::MoveLineUp),
name: "Move Line Up", MenuItem::action("Move Line Down", editor::MoveLineDown),
action: Box::new(editor::MoveLineUp), MenuItem::action("Duplicate Selection", editor::DuplicateLine),
},
MenuItem::Action {
name: "Move Line Down",
action: Box::new(editor::MoveLineDown),
},
MenuItem::Action {
name: "Duplicate Selection",
action: Box::new(editor::DuplicateLine),
},
], ],
}, },
Menu { Menu {
name: "View", name: "View",
items: vec![ items: vec![
MenuItem::Action { MenuItem::action("Zoom In", super::IncreaseBufferFontSize),
name: "Zoom In", MenuItem::action("Zoom Out", super::DecreaseBufferFontSize),
action: Box::new(super::IncreaseBufferFontSize), MenuItem::action("Reset Zoom", super::ResetBufferFontSize),
}, MenuItem::separator(),
MenuItem::Action { MenuItem::action("Toggle Left Sidebar", workspace::ToggleLeftSidebar),
name: "Zoom Out", MenuItem::submenu(Menu {
action: Box::new(super::DecreaseBufferFontSize),
},
MenuItem::Action {
name: "Reset Zoom",
action: Box::new(super::ResetBufferFontSize),
},
MenuItem::Separator,
MenuItem::Action {
name: "Toggle Left Sidebar",
action: Box::new(workspace::ToggleLeftSidebar),
},
MenuItem::Submenu(Menu {
name: "Editor Layout", name: "Editor Layout",
items: vec![ items: vec![
MenuItem::Action { MenuItem::action("Split Up", workspace::SplitUp),
name: "Split Up", MenuItem::action("Split Down", workspace::SplitDown),
action: Box::new(workspace::SplitUp), MenuItem::action("Split Left", workspace::SplitLeft),
}, MenuItem::action("Split Right", workspace::SplitRight),
MenuItem::Action {
name: "Split Down",
action: Box::new(workspace::SplitDown),
},
MenuItem::Action {
name: "Split Left",
action: Box::new(workspace::SplitLeft),
},
MenuItem::Action {
name: "Split Right",
action: Box::new(workspace::SplitRight),
},
], ],
}), }),
MenuItem::Separator, MenuItem::separator(),
MenuItem::Action { MenuItem::action("Project Panel", project_panel::ToggleFocus),
name: "Project Panel", MenuItem::action("Command Palette", command_palette::Toggle),
action: Box::new(project_panel::ToggleFocus), MenuItem::action("Diagnostics", diagnostics::Deploy),
}, MenuItem::separator(),
MenuItem::Action {
name: "Command Palette",
action: Box::new(command_palette::Toggle),
},
MenuItem::Action {
name: "Diagnostics",
action: Box::new(diagnostics::Deploy),
},
MenuItem::Separator,
], ],
}, },
Menu { Menu {
name: "Go", name: "Go",
items: vec![ items: vec![
MenuItem::Action { MenuItem::action("Back", workspace::GoBack { pane: None }),
name: "Back", MenuItem::action("Forward", workspace::GoForward { pane: None }),
action: Box::new(workspace::GoBack { pane: None }), MenuItem::separator(),
}, MenuItem::action("Go to File", file_finder::Toggle),
MenuItem::Action { MenuItem::action("Go to Symbol in Project", project_symbols::Toggle),
name: "Forward", MenuItem::action("Go to Symbol in Editor", outline::Toggle),
action: Box::new(workspace::GoForward { pane: None }), MenuItem::action("Go to Definition", editor::GoToDefinition),
}, MenuItem::action("Go to Type Definition", editor::GoToTypeDefinition),
MenuItem::Separator, MenuItem::action("Find All References", editor::FindAllReferences),
MenuItem::Action { MenuItem::action("Go to Line/Column", go_to_line::Toggle),
name: "Go to File", MenuItem::separator(),
action: Box::new(file_finder::Toggle), MenuItem::action("Next Problem", editor::GoToDiagnostic),
}, MenuItem::action("Previous Problem", editor::GoToPrevDiagnostic),
MenuItem::Action {
name: "Go to Symbol in Project",
action: Box::new(project_symbols::Toggle),
},
MenuItem::Action {
name: "Go to Symbol in Editor",
action: Box::new(outline::Toggle),
},
MenuItem::Action {
name: "Go to Definition",
action: Box::new(editor::GoToDefinition),
},
MenuItem::Action {
name: "Go to Type Definition",
action: Box::new(editor::GoToTypeDefinition),
},
MenuItem::Action {
name: "Find All References",
action: Box::new(editor::FindAllReferences),
},
MenuItem::Action {
name: "Go to Line/Column",
action: Box::new(go_to_line::Toggle),
},
MenuItem::Separator,
MenuItem::Action {
name: "Next Problem",
action: Box::new(editor::GoToDiagnostic),
},
MenuItem::Action {
name: "Previous Problem",
action: Box::new(editor::GoToPrevDiagnostic),
},
], ],
}, },
Menu { Menu {
name: "Window", name: "Window",
items: vec![ items: vec![
MenuItem::Action { MenuItem::action("Minimize", super::Minimize),
name: "Minimize", MenuItem::action("Zoom", super::Zoom),
action: Box::new(super::Minimize), MenuItem::separator(),
},
MenuItem::Action {
name: "Zoom",
action: Box::new(super::Zoom),
},
MenuItem::Separator,
], ],
}, },
Menu { Menu {
name: "Help", name: "Help",
items: vec![ items: vec![
MenuItem::Action { MenuItem::action("Command Palette", command_palette::Toggle),
name: "Command Palette", MenuItem::separator(),
action: Box::new(command_palette::Toggle), MenuItem::action("View Telemetry Log", crate::OpenTelemetryLog),
}, MenuItem::action("View Dependency Licenses", crate::OpenLicenses),
MenuItem::Separator, MenuItem::separator(),
MenuItem::Action { MenuItem::action(
name: "View Telemetry Log", "Copy System Specs Into Clipboard",
action: Box::new(crate::OpenTelemetryLog), feedback::CopySystemSpecsIntoClipboard,
}, ),
MenuItem::Action { MenuItem::action("File Bug Report", feedback::FileBugReport),
name: "View Dependency Licenses", MenuItem::action("Request Feature", feedback::RequestFeature),
action: Box::new(crate::OpenLicenses), MenuItem::separator(),
}, MenuItem::action(
MenuItem::Separator, "Documentation",
MenuItem::Action { crate::OpenBrowser {
name: "Copy System Specs Into Clipboard",
action: Box::new(feedback::CopySystemSpecsIntoClipboard),
},
MenuItem::Action {
name: "File Bug Report",
action: Box::new(feedback::FileBugReport),
},
MenuItem::Action {
name: "Request Feature",
action: Box::new(feedback::RequestFeature),
},
MenuItem::Separator,
MenuItem::Action {
name: "Documentation",
action: Box::new(crate::OpenBrowser {
url: "https://zed.dev/docs".into(), url: "https://zed.dev/docs".into(),
}), },
}, ),
MenuItem::Action { MenuItem::action(
name: "Zed Twitter", "Zed Twitter",
action: Box::new(crate::OpenBrowser { crate::OpenBrowser {
url: "https://twitter.com/zeddotdev".into(), url: "https://twitter.com/zeddotdev".into(),
}), },
}, ),
], ],
}, },
] ]