1use gpui::{Action, FocusHandle, KeyBinding, Keystroke, WindowContext};
2
3use crate::PlatformStyle;
4
5/// Returns a textual representation of the key binding for the given [`Action`].
6pub fn text_for_action(action: &dyn Action, cx: &mut WindowContext) -> Option<String> {
7 let key_binding = cx.bindings_for_action(action).last().cloned()?;
8 Some(text_for_key_binding(key_binding, PlatformStyle::platform()))
9}
10
11/// Returns a textual representation of the key binding for the given [`Action`]
12/// as if the provided [`FocusHandle`] was focused.
13pub fn text_for_action_in(
14 action: &dyn Action,
15 focus: &FocusHandle,
16 cx: &mut WindowContext,
17) -> Option<String> {
18 let key_binding = cx.bindings_for_action_in(action, focus).last().cloned()?;
19 Some(text_for_key_binding(key_binding, PlatformStyle::platform()))
20}
21
22/// Returns a textual representation of the given key binding for the specified platform.
23pub fn text_for_key_binding(key_binding: KeyBinding, platform_style: PlatformStyle) -> String {
24 key_binding
25 .keystrokes()
26 .into_iter()
27 .map(|keystroke| text_for_keystroke(keystroke, platform_style))
28 .collect::<Vec<_>>()
29 .join(" ")
30}
31
32/// Returns a textual representation of the given [`Keystroke`].
33pub fn text_for_keystroke(keystroke: &Keystroke, platform_style: PlatformStyle) -> String {
34 let mut text = String::new();
35
36 let delimiter = match platform_style {
37 PlatformStyle::Mac => '-',
38 PlatformStyle::Linux | PlatformStyle::Windows => '+',
39 };
40
41 if keystroke.modifiers.function {
42 match platform_style {
43 PlatformStyle::Mac => text.push_str("fn"),
44 PlatformStyle::Linux | PlatformStyle::Windows => text.push_str("Fn"),
45 }
46
47 text.push(delimiter);
48 }
49
50 if keystroke.modifiers.control {
51 match platform_style {
52 PlatformStyle::Mac => text.push_str("Control"),
53 PlatformStyle::Linux | PlatformStyle::Windows => text.push_str("Ctrl"),
54 }
55
56 text.push(delimiter);
57 }
58
59 if keystroke.modifiers.alt {
60 match platform_style {
61 PlatformStyle::Mac => text.push_str("Option"),
62 PlatformStyle::Linux | PlatformStyle::Windows => text.push_str("Alt"),
63 }
64
65 text.push(delimiter);
66 }
67
68 if keystroke.modifiers.platform {
69 match platform_style {
70 PlatformStyle::Mac => text.push_str("Command"),
71 PlatformStyle::Linux => text.push_str("Super"),
72 PlatformStyle::Windows => text.push_str("Win"),
73 }
74
75 text.push(delimiter);
76 }
77
78 if keystroke.modifiers.shift {
79 match platform_style {
80 PlatformStyle::Mac | PlatformStyle::Linux | PlatformStyle::Windows => {
81 text.push_str("Shift")
82 }
83 }
84
85 text.push(delimiter);
86 }
87
88 fn capitalize(str: &str) -> String {
89 let mut chars = str.chars();
90 match chars.next() {
91 None => String::new(),
92 Some(first_char) => first_char.to_uppercase().collect::<String>() + chars.as_str(),
93 }
94 }
95
96 let key = match keystroke.key.as_str() {
97 "pageup" => "PageUp",
98 "pagedown" => "PageDown",
99 key => &capitalize(key),
100 };
101
102 text.push_str(key);
103
104 text
105}
106
107#[cfg(test)]
108mod tests {
109 use super::*;
110
111 #[test]
112 fn test_text_for_keystroke() {
113 assert_eq!(
114 text_for_keystroke(&Keystroke::parse("cmd-c").unwrap(), PlatformStyle::Mac),
115 "Command-C".to_string()
116 );
117 assert_eq!(
118 text_for_keystroke(&Keystroke::parse("cmd-c").unwrap(), PlatformStyle::Linux),
119 "Super+C".to_string()
120 );
121 assert_eq!(
122 text_for_keystroke(&Keystroke::parse("cmd-c").unwrap(), PlatformStyle::Windows),
123 "Win+C".to_string()
124 );
125
126 assert_eq!(
127 text_for_keystroke(
128 &Keystroke::parse("ctrl-alt-delete").unwrap(),
129 PlatformStyle::Mac
130 ),
131 "Control-Option-Delete".to_string()
132 );
133 assert_eq!(
134 text_for_keystroke(
135 &Keystroke::parse("ctrl-alt-delete").unwrap(),
136 PlatformStyle::Linux
137 ),
138 "Ctrl+Alt+Delete".to_string()
139 );
140 assert_eq!(
141 text_for_keystroke(
142 &Keystroke::parse("ctrl-alt-delete").unwrap(),
143 PlatformStyle::Windows
144 ),
145 "Ctrl+Alt+Delete".to_string()
146 );
147
148 assert_eq!(
149 text_for_keystroke(
150 &Keystroke::parse("shift-pageup").unwrap(),
151 PlatformStyle::Mac
152 ),
153 "Shift-PageUp".to_string()
154 );
155 assert_eq!(
156 text_for_keystroke(
157 &Keystroke::parse("shift-pageup").unwrap(),
158 PlatformStyle::Linux
159 ),
160 "Shift+PageUp".to_string()
161 );
162 assert_eq!(
163 text_for_keystroke(
164 &Keystroke::parse("shift-pageup").unwrap(),
165 PlatformStyle::Windows
166 ),
167 "Shift+PageUp".to_string()
168 );
169 }
170}