Skip to repository content322 lines · 10.7 KB · rust
tenant.openagents/omega
No repository description is available.
OpenAgents Git authority 2026-07-28T05:38:01.103Z Public web read
NIP-34 coordinate
30617:7649603503856e5148d571eac2766b288a8ff1e9e35d380337a1d2b0015b4f92:omegaMaintainersHidden in public view
References2 branches · 1 tag
Read-only clone
git clone https://openagents.com/git/tenant.openagents/omega.gitBrowse files
keybinding_hint.rs
1use crate::KeyBinding;
2use crate::prelude::*;
3use gpui::{AnyElement, App, BoxShadow, FontStyle, Hsla, IntoElement, Window};
4use theme::Appearance;
5
6/// Represents a hint for a keybinding, optionally with a prefix and suffix.
7///
8/// This struct allows for the creation and customization of a keybinding hint,
9/// which can be used to display keyboard shortcuts or commands in a user interface.
10///
11/// # Examples
12///
13/// ```no_run
14/// use gpui::{App, Hsla, KeybindingKeystroke, Keystroke};
15/// use ui::prelude::*;
16/// use ui::{KeyBinding, KeybindingHint};
17///
18/// # fn example(cx: &App) {
19/// let hint = KeybindingHint::new(
20/// KeyBinding::from_keystrokes(vec![KeybindingKeystroke::from_keystroke(Keystroke::parse("ctrl-s").unwrap())].into(), false),
21/// Hsla::black()
22/// )
23/// .prefix("Save:")
24/// .size(Pixels::from(14.0));
25/// # }
26/// ```
27#[derive(Debug, IntoElement, RegisterComponent)]
28pub struct KeybindingHint {
29 prefix: Option<SharedString>,
30 suffix: Option<SharedString>,
31 keybinding: KeyBinding,
32 size: Option<Pixels>,
33 background_color: Hsla,
34}
35
36impl KeybindingHint {
37 /// Creates a new `KeybindingHint` with the specified keybinding.
38 ///
39 /// This method initializes a new `KeybindingHint` instance with the given keybinding,
40 /// setting all other fields to their default values.
41 ///
42 /// # Examples
43 ///
44 /// ```no_run
45 /// use gpui::{App, Hsla, KeybindingKeystroke, Keystroke};
46 /// use ui::prelude::*;
47 /// use ui::{KeyBinding, KeybindingHint};
48 ///
49 /// # fn example(cx: &App) {
50 /// let hint = KeybindingHint::new(
51 /// KeyBinding::from_keystrokes(vec![KeybindingKeystroke::from_keystroke(Keystroke::parse("ctrl-c").unwrap())].into(), false),
52 /// Hsla::black()
53 /// );
54 /// # }
55 /// ```
56 pub fn new(keybinding: KeyBinding, background_color: Hsla) -> Self {
57 Self {
58 prefix: None,
59 suffix: None,
60 keybinding,
61 size: None,
62 background_color,
63 }
64 }
65
66 /// Creates a new `KeybindingHint` with a prefix and keybinding.
67 ///
68 /// This method initializes a new `KeybindingHint` instance with the given prefix and keybinding,
69 /// setting all other fields to their default values.
70 ///
71 /// # Examples
72 ///
73 /// ```no_run
74 /// use gpui::{App, Hsla, KeybindingKeystroke, Keystroke};
75 /// use ui::prelude::*;
76 /// use ui::{KeyBinding, KeybindingHint};
77 ///
78 /// # fn example(cx: &App) {
79 /// let hint = KeybindingHint::with_prefix(
80 /// "Copy:",
81 /// KeyBinding::from_keystrokes(vec![KeybindingKeystroke::from_keystroke(Keystroke::parse("ctrl-c").unwrap())].into(), false),
82 /// Hsla::black()
83 /// );
84 /// # }
85 /// ```
86 pub fn with_prefix(
87 prefix: impl Into<SharedString>,
88 keybinding: KeyBinding,
89 background_color: Hsla,
90 ) -> Self {
91 Self {
92 prefix: Some(prefix.into()),
93 suffix: None,
94 keybinding,
95 size: None,
96 background_color,
97 }
98 }
99
100 /// Creates a new `KeybindingHint` with a keybinding and suffix.
101 ///
102 /// This method initializes a new `KeybindingHint` instance with the given keybinding and suffix,
103 /// setting all other fields to their default values.
104 ///
105 /// # Examples
106 ///
107 /// ```no_run
108 /// use gpui::{App, Hsla, KeybindingKeystroke, Keystroke};
109 /// use ui::prelude::*;
110 /// use ui::{KeyBinding, KeybindingHint};
111 ///
112 /// # fn example(cx: &App) {
113 /// let hint = KeybindingHint::with_suffix(
114 /// KeyBinding::from_keystrokes(vec![KeybindingKeystroke::from_keystroke(Keystroke::parse("ctrl-v").unwrap())].into(), false),
115 /// "Paste",
116 /// Hsla::black()
117 /// );
118 /// # }
119 /// ```
120 pub fn with_suffix(
121 keybinding: KeyBinding,
122 suffix: impl Into<SharedString>,
123 background_color: Hsla,
124 ) -> Self {
125 Self {
126 prefix: None,
127 suffix: Some(suffix.into()),
128 keybinding,
129 size: None,
130 background_color,
131 }
132 }
133
134 /// Sets the prefix for the keybinding hint.
135 ///
136 /// This method allows adding or changing the prefix text that appears before the keybinding.
137 ///
138 /// # Examples
139 ///
140 /// ```no_run
141 /// use gpui::{App, Hsla, KeybindingKeystroke, Keystroke};
142 /// use ui::prelude::*;
143 /// use ui::{KeyBinding, KeybindingHint};
144 ///
145 /// # fn example(cx: &App) {
146 /// let hint = KeybindingHint::new(
147 /// KeyBinding::from_keystrokes(vec![KeybindingKeystroke::from_keystroke(Keystroke::parse("ctrl-x").unwrap())].into(), false),
148 /// Hsla::black()
149 /// )
150 /// .prefix("Cut:");
151 /// # }
152 /// ```
153 pub fn prefix(mut self, prefix: impl Into<SharedString>) -> Self {
154 self.prefix = Some(prefix.into());
155 self
156 }
157
158 /// Sets the suffix for the keybinding hint.
159 ///
160 /// This method allows adding or changing the suffix text that appears after the keybinding.
161 ///
162 /// # Examples
163 ///
164 /// ```no_run
165 /// use gpui::{App, Hsla, KeybindingKeystroke, Keystroke};
166 /// use ui::prelude::*;
167 /// use ui::{KeyBinding, KeybindingHint};
168 ///
169 /// # fn example(cx: &App) {
170 /// let hint = KeybindingHint::new(
171 /// KeyBinding::from_keystrokes(vec![KeybindingKeystroke::from_keystroke(Keystroke::parse("ctrl-f").unwrap())].into(), false),
172 /// Hsla::black()
173 /// )
174 /// .suffix("Find");
175 /// # }
176 /// ```
177 pub fn suffix(mut self, suffix: impl Into<SharedString>) -> Self {
178 self.suffix = Some(suffix.into());
179 self
180 }
181
182 /// Sets the size of the keybinding hint.
183 ///
184 /// This method allows specifying the size of the keybinding hint in pixels.
185 ///
186 /// # Examples
187 ///
188 /// ```no_run
189 /// use gpui::{App, Hsla, KeybindingKeystroke, Keystroke};
190 /// use ui::prelude::*;
191 /// use ui::{KeyBinding, KeybindingHint};
192 ///
193 /// # fn example(cx: &App) {
194 /// let hint = KeybindingHint::new(
195 /// KeyBinding::from_keystrokes(vec![KeybindingKeystroke::from_keystroke(Keystroke::parse("ctrl-z").unwrap())].into(), false),
196 /// Hsla::black()
197 /// )
198 /// .size(Pixels::from(16.0));
199 /// # }
200 /// ```
201 pub fn size(mut self, size: impl Into<Option<Pixels>>) -> Self {
202 self.size = size.into();
203 self
204 }
205}
206
207impl RenderOnce for KeybindingHint {
208 fn render(self, window: &mut Window, cx: &mut App) -> impl IntoElement {
209 let colors = cx.theme().colors();
210 let is_light = cx.theme().appearance() == Appearance::Light;
211
212 let border_color =
213 self.background_color
214 .blend(colors.text.alpha(if is_light { 0.08 } else { 0.16 }));
215
216 let bg_color = self
217 .background_color
218 .blend(colors.text_accent.alpha(if is_light { 0.05 } else { 0.1 }));
219
220 let shadow_color = colors.text.alpha(if is_light { 0.04 } else { 0.08 });
221
222 let size = self
223 .size
224 .unwrap_or(TextSize::Small.rems(cx).to_pixels(window.rem_size()));
225
226 let kb_size = size - px(2.0);
227
228 let mut base = h_flex();
229
230 base.text_style().font_style = Some(FontStyle::Italic);
231
232 base.gap_1()
233 .font_buffer(cx)
234 .text_size(size)
235 .text_color(colors.text_disabled)
236 .children(self.prefix)
237 .child(
238 h_flex()
239 .rounded_sm()
240 .px_0p5()
241 .mr_0p5()
242 .border_1()
243 .border_color(border_color)
244 .bg(bg_color)
245 .shadow(vec![BoxShadow::new(px(0.), px(1.), shadow_color)])
246 .child(self.keybinding.size(rems_from_px(kb_size))),
247 )
248 .children(self.suffix)
249 }
250}
251
252impl Component for KeybindingHint {
253 fn scope() -> ComponentScope {
254 ComponentScope::DataDisplay
255 }
256
257 fn description() -> &'static str {
258 "Displays a keyboard shortcut hint with optional prefix and suffix text"
259 }
260
261 fn preview(_window: &mut Window, cx: &mut App) -> AnyElement {
262 let enter = KeyBinding::for_action(&menu::Confirm, cx);
263
264 let bg_color = cx.theme().colors().surface_background;
265
266 v_flex()
267 .gap_6()
268 .children(vec![
269 example_group_with_title(
270 "Basic",
271 vec![
272 single_example(
273 "With Prefix",
274 KeybindingHint::with_prefix("Go to Start:", enter.clone(), bg_color)
275 .into_any_element(),
276 ),
277 single_example(
278 "With Suffix",
279 KeybindingHint::with_suffix(enter.clone(), "Go to End", bg_color)
280 .into_any_element(),
281 ),
282 single_example(
283 "With Prefix and Suffix",
284 KeybindingHint::new(enter.clone(), bg_color)
285 .prefix("Confirm:")
286 .suffix("Execute selected action")
287 .into_any_element(),
288 ),
289 ],
290 ),
291 example_group_with_title(
292 "Sizes",
293 vec![
294 single_example(
295 "Small",
296 KeybindingHint::new(enter.clone(), bg_color)
297 .size(Pixels::from(12.0))
298 .prefix("Small:")
299 .into_any_element(),
300 ),
301 single_example(
302 "Medium",
303 KeybindingHint::new(enter.clone(), bg_color)
304 .size(Pixels::from(16.0))
305 .suffix("Medium")
306 .into_any_element(),
307 ),
308 single_example(
309 "Large",
310 KeybindingHint::new(enter, bg_color)
311 .size(Pixels::from(20.0))
312 .prefix("Large:")
313 .suffix("Size")
314 .into_any_element(),
315 ),
316 ],
317 ),
318 ])
319 .into_any_element()
320 }
321}
322