Skip to repository content

tenant.openagents/omega

No repository description is available.

OpenAgents Git authority 2026-07-28T03:35:58.123Z 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

font_picker.rs

187 lines · 5.5 KB · rust
1use std::sync::Arc;
2
3use fuzzy::{StringMatch, StringMatchCandidate};
4use gpui::{AnyElement, App, Context, DismissEvent, SharedString, Task, Window};
5use picker::{Picker, PickerDelegate};
6use theme::FontFamilyCache;
7use ui::{ListItem, ListItemSpacing, prelude::*};
8
9type FontPicker = Picker<FontPickerDelegate>;
10
11pub struct FontPickerDelegate {
12    fonts: Vec<SharedString>,
13    filtered_fonts: Vec<StringMatch>,
14    selected_index: usize,
15    current_font: SharedString,
16    on_font_changed: Arc<dyn Fn(SharedString, &mut Window, &mut App) + 'static>,
17}
18
19impl FontPickerDelegate {
20    fn new(
21        current_font: SharedString,
22        on_font_changed: impl Fn(SharedString, &mut Window, &mut App) + 'static,
23        cx: &mut Context<FontPicker>,
24    ) -> Self {
25        let font_family_cache = FontFamilyCache::global(cx);
26
27        let fonts = font_family_cache
28            .try_list_font_families()
29            .unwrap_or_else(|| vec![current_font.clone()]);
30        let selected_index = fonts
31            .iter()
32            .position(|font| *font == current_font)
33            .unwrap_or(0);
34
35        let filtered_fonts = fonts
36            .iter()
37            .enumerate()
38            .map(|(index, font)| StringMatch {
39                candidate_id: index,
40                string: font.to_string(),
41                positions: Vec::new(),
42                score: 0.0,
43            })
44            .collect();
45
46        Self {
47            fonts,
48            filtered_fonts,
49            selected_index,
50            current_font,
51            on_font_changed: Arc::new(on_font_changed),
52        }
53    }
54}
55
56impl PickerDelegate for FontPickerDelegate {
57    type ListItem = AnyElement;
58
59    fn name() -> &'static str {
60        "font picker"
61    }
62
63    fn match_count(&self) -> usize {
64        self.filtered_fonts.len()
65    }
66
67    fn selected_index(&self) -> usize {
68        self.selected_index
69    }
70
71    fn set_selected_index(&mut self, ix: usize, _: &mut Window, cx: &mut Context<FontPicker>) {
72        self.selected_index = ix.min(self.filtered_fonts.len().saturating_sub(1));
73        cx.notify();
74    }
75
76    fn placeholder_text(&self, _window: &mut Window, _cx: &mut App) -> Arc<str> {
77        "Search fonts…".into()
78    }
79
80    fn update_matches(
81        &mut self,
82        query: String,
83        _window: &mut Window,
84        cx: &mut Context<FontPicker>,
85    ) -> Task<()> {
86        let fonts = self.fonts.clone();
87        let current_font = self.current_font.clone();
88
89        let matches: Vec<StringMatch> = if query.is_empty() {
90            fonts
91                .iter()
92                .enumerate()
93                .map(|(index, font)| StringMatch {
94                    candidate_id: index,
95                    string: font.to_string(),
96                    positions: Vec::new(),
97                    score: 0.0,
98                })
99                .collect()
100        } else {
101            let _candidates: Vec<StringMatchCandidate> = fonts
102                .iter()
103                .enumerate()
104                .map(|(id, font)| StringMatchCandidate::new(id, font.as_ref()))
105                .collect();
106
107            fonts
108                .iter()
109                .enumerate()
110                .filter(|(_, font)| font.to_lowercase().contains(&query.to_lowercase()))
111                .map(|(index, font)| StringMatch {
112                    candidate_id: index,
113                    string: font.to_string(),
114                    positions: Vec::new(),
115                    score: 0.0,
116                })
117                .collect()
118        };
119
120        let selected_index = if query.is_empty() {
121            fonts
122                .iter()
123                .position(|font| *font == current_font)
124                .unwrap_or(0)
125        } else {
126            matches
127                .iter()
128                .position(|m| fonts[m.candidate_id] == current_font)
129                .unwrap_or(0)
130        };
131
132        self.filtered_fonts = matches;
133        self.selected_index = selected_index;
134        cx.notify();
135
136        Task::ready(())
137    }
138
139    fn confirm(&mut self, _secondary: bool, window: &mut Window, cx: &mut Context<FontPicker>) {
140        if let Some(font_match) = self.filtered_fonts.get(self.selected_index) {
141            let font = font_match.string.clone();
142            (self.on_font_changed)(font.into(), window, cx);
143        }
144    }
145
146    fn dismissed(&mut self, window: &mut Window, cx: &mut Context<FontPicker>) {
147        cx.defer_in(window, |picker, window, cx| {
148            picker.set_query("", window, cx);
149        });
150        cx.emit(DismissEvent);
151    }
152
153    fn render_match(
154        &self,
155        ix: usize,
156        selected: bool,
157        _window: &mut Window,
158        _cx: &mut Context<FontPicker>,
159    ) -> Option<Self::ListItem> {
160        let font_match = self.filtered_fonts.get(ix)?;
161
162        Some(
163            ListItem::new(ix)
164                .inset(true)
165                .spacing(ListItemSpacing::Sparse)
166                .toggle_state(selected)
167                .child(Label::new(font_match.string.clone()))
168                .into_any_element(),
169        )
170    }
171}
172
173pub fn font_picker(
174    current_font: SharedString,
175    on_font_changed: impl Fn(SharedString, &mut Window, &mut App) + 'static,
176    window: &mut Window,
177    cx: &mut Context<FontPicker>,
178) -> FontPicker {
179    let delegate = FontPickerDelegate::new(current_font, on_font_changed, cx);
180
181    Picker::uniform_list(delegate, window, cx)
182        .show_scrollbar(true)
183        .initial_width(rems_from_px(210.))
184        .max_height(rems(18.))
185        .popover()
186}
187
Served at tenant.openagents/omega Member data and write actions are omitted.