Skip to repository content

tenant.openagents/omega

No repository description is available.

OpenAgents Git authority 2026-07-28T05:38:01.103Z Public web read
NIP-34 coordinate30617:7649603503856e5148d571eac2766b288a8ff1e9e35d380337a1d2b0015b4f92:omega
MaintainersHidden in public view
References2 branches · 1 tag
Read-only clonegit clone https://openagents.com/git/tenant.openagents/omega.git
Browse files

keybinding_hint.rs

322 lines · 10.7 KB · rust
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
Served at tenant.openagents/omega Member data and write actions are omitted.