Skip to repository content

tenant.openagents/omega

No repository description is available.

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

icon_theme_picker.rs

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