1use crate::{Action, AppContext, Platform};
2use util::ResultExt;
3
4/// A menu of the application, either a main menu or a submenu
5pub struct Menu<'a> {
6 /// The name of the menu
7 pub name: &'a str,
8
9 /// The items in the menu
10 pub items: Vec<MenuItem<'a>>,
11}
12
13/// The different kinds of items that can be in a menu
14pub enum MenuItem<'a> {
15 /// A separator between items
16 Separator,
17
18 /// A submenu
19 Submenu(Menu<'a>),
20
21 /// An action that can be performed
22 Action {
23 /// The name of this menu item
24 name: &'a str,
25
26 /// the action to perform when this menu item is selected
27 action: Box<dyn Action>,
28
29 /// The OS Action that corresponds to this action, if any
30 /// See [`OsAction`] for more information
31 os_action: Option<OsAction>,
32 },
33}
34
35impl<'a> MenuItem<'a> {
36 /// Creates a new menu item that is a separator
37 pub fn separator() -> Self {
38 Self::Separator
39 }
40
41 /// Creates a new menu item that is a submenu
42 pub fn submenu(menu: Menu<'a>) -> Self {
43 Self::Submenu(menu)
44 }
45
46 /// Creates a new menu item that invokes an action
47 pub fn action(name: &'a str, action: impl Action) -> Self {
48 Self::Action {
49 name,
50 action: Box::new(action),
51 os_action: None,
52 }
53 }
54
55 /// Creates a new menu item that invokes an action and has an OS action
56 pub fn os_action(name: &'a str, action: impl Action, os_action: OsAction) -> Self {
57 Self::Action {
58 name,
59 action: Box::new(action),
60 os_action: Some(os_action),
61 }
62 }
63}
64
65// TODO: As part of the global selections refactor, these should
66// be moved to GPUI-provided actions that make this association
67// without leaking the platform details to GPUI users
68
69/// OS actions are actions that are recognized by the operating system
70/// This allows the operating system to provide specialized behavior for
71/// these actions
72#[derive(Copy, Clone, Eq, PartialEq)]
73pub enum OsAction {
74 /// The 'cut' action
75 Cut,
76
77 /// The 'copy' action
78 Copy,
79
80 /// The 'paste' action
81 Paste,
82
83 /// The 'select all' action
84 SelectAll,
85
86 /// The 'undo' action
87 Undo,
88
89 /// The 'redo' action
90 Redo,
91}
92
93pub(crate) fn init_app_menus(platform: &dyn Platform, cx: &mut AppContext) {
94 platform.on_will_open_app_menu(Box::new({
95 let cx = cx.to_async();
96 move || {
97 cx.update(|cx| cx.clear_pending_keystrokes()).ok();
98 }
99 }));
100
101 platform.on_validate_app_menu_command(Box::new({
102 let cx = cx.to_async();
103 move |action| {
104 cx.update(|cx| cx.is_action_available(action))
105 .unwrap_or(false)
106 }
107 }));
108
109 platform.on_app_menu_action(Box::new({
110 let cx = cx.to_async();
111 move |action| {
112 cx.update(|cx| cx.dispatch_action(action)).log_err();
113 }
114 }));
115}