Skip to repository content297 lines · 8.4 KB · rust
tenant.openagents/omega
No repository description is available.
OpenAgents Git authority 2026-07-28T01:34:12.607Z 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
wsl_picker.rs
1use std::{path::PathBuf, sync::Arc};
2
3use gpui::{AppContext, DismissEvent, Entity, EventEmitter, Focusable, Subscription, Task};
4use picker::Picker;
5use remote::{RemoteConnectionOptions, WslConnectionOptions};
6use ui::{
7 App, Context, HighlightedLabel, Icon, IconName, InteractiveElement, ListItem, ParentElement,
8 Render, Styled, StyledExt, Toggleable, Window, div, h_flex, rems, v_flex,
9};
10use util::ResultExt as _;
11use workspace::{ModalView, MultiWorkspace};
12
13use crate::open_remote_project;
14
15#[derive(Clone, Debug)]
16pub struct WslDistroSelected {
17 pub secondary: bool,
18 pub distro: String,
19}
20
21#[derive(Clone, Debug)]
22pub struct WslPickerDismissed;
23
24pub(crate) struct WslPickerDelegate {
25 selected_index: usize,
26 distro_list: Option<Vec<String>>,
27 matches: Vec<fuzzy_nucleo::StringMatch>,
28}
29
30impl WslPickerDelegate {
31 pub fn new() -> Self {
32 WslPickerDelegate {
33 selected_index: 0,
34 distro_list: None,
35 matches: Vec::new(),
36 }
37 }
38
39 pub fn selected_distro(&self) -> Option<String> {
40 self.matches
41 .get(self.selected_index)
42 .map(|m| m.string.to_string())
43 }
44}
45
46impl WslPickerDelegate {
47 fn fetch_distros() -> anyhow::Result<Vec<String>> {
48 use anyhow::Context;
49 use windows_registry::CURRENT_USER;
50
51 let lxss_key = CURRENT_USER
52 .open("Software\\Microsoft\\Windows\\CurrentVersion\\Lxss")
53 .context("failed to get lxss wsl key")?;
54
55 let distros = lxss_key
56 .keys()
57 .context("failed to get wsl distros")?
58 .filter_map(|key| {
59 lxss_key
60 .open(&key)
61 .context("failed to open subkey for distro")
62 .log_err()
63 })
64 .filter_map(|distro| distro.get_string("DistributionName").ok())
65 .collect::<Vec<_>>();
66
67 Ok(distros)
68 }
69}
70
71impl EventEmitter<WslDistroSelected> for Picker<WslPickerDelegate> {}
72
73impl EventEmitter<WslPickerDismissed> for Picker<WslPickerDelegate> {}
74
75impl picker::PickerDelegate for WslPickerDelegate {
76 type ListItem = ListItem;
77
78 fn name() -> &'static str {
79 "WSL-distor-picker"
80 }
81
82 fn match_count(&self) -> usize {
83 self.matches.len()
84 }
85
86 fn selected_index(&self) -> usize {
87 self.selected_index
88 }
89
90 fn set_selected_index(
91 &mut self,
92 ix: usize,
93 _window: &mut Window,
94 cx: &mut Context<Picker<Self>>,
95 ) {
96 self.selected_index = ix;
97 cx.notify();
98 }
99
100 fn placeholder_text(&self, _window: &mut Window, _cx: &mut App) -> Arc<str> {
101 Arc::from("Enter WSL distro name")
102 }
103
104 fn update_matches(
105 &mut self,
106 query: String,
107 _window: &mut Window,
108 _cx: &mut Context<Picker<Self>>,
109 ) -> Task<()> {
110 use fuzzy_nucleo::StringMatchCandidate;
111
112 let needs_fetch = self.distro_list.is_none();
113 if needs_fetch {
114 let distros = Self::fetch_distros().log_err();
115 self.distro_list = distros;
116 }
117
118 if let Some(distro_list) = &self.distro_list {
119 use ordered_float::OrderedFloat;
120
121 let candidates = distro_list
122 .iter()
123 .enumerate()
124 .map(|(id, distro)| StringMatchCandidate::new(id, distro))
125 .collect::<Vec<_>>();
126
127 let query = query.trim_start();
128 let case = fuzzy_nucleo::Case::smart_if_uppercase_in(query);
129 self.matches = fuzzy_nucleo::match_strings(
130 &candidates,
131 query,
132 case,
133 fuzzy_nucleo::LengthPenalty::On,
134 100,
135 );
136 self.matches.sort_unstable_by_key(|m| m.candidate_id);
137
138 self.selected_index = self
139 .matches
140 .iter()
141 .enumerate()
142 .rev()
143 .max_by_key(|(_, m)| OrderedFloat(m.score))
144 .map(|(index, _)| index)
145 .unwrap_or(0);
146 }
147
148 Task::ready(())
149 }
150
151 fn confirm(&mut self, secondary: bool, _window: &mut Window, cx: &mut Context<Picker<Self>>) {
152 if let Some(distro) = self.matches.get(self.selected_index) {
153 cx.emit(WslDistroSelected {
154 secondary,
155 distro: distro.string.to_string(),
156 });
157 }
158 }
159
160 fn dismissed(&mut self, _window: &mut Window, cx: &mut Context<Picker<Self>>) {
161 cx.emit(WslPickerDismissed);
162 }
163
164 fn render_match(
165 &self,
166 ix: usize,
167 selected: bool,
168 _: &mut Window,
169 _: &mut Context<Picker<Self>>,
170 ) -> Option<Self::ListItem> {
171 let matched = self.matches.get(ix)?;
172 Some(
173 ListItem::new(ix)
174 .toggle_state(selected)
175 .inset(true)
176 .spacing(ui::ListItemSpacing::Sparse)
177 .child(
178 h_flex()
179 .flex_grow_1()
180 .gap_3()
181 .child(Icon::new(IconName::Linux))
182 .child(v_flex().child(HighlightedLabel::new(
183 matched.string.clone(),
184 matched.positions.clone(),
185 ))),
186 ),
187 )
188 }
189}
190
191pub(crate) struct WslOpenModal {
192 paths: Vec<PathBuf>,
193 create_new_window: bool,
194 picker: Entity<Picker<WslPickerDelegate>>,
195 _subscriptions: [Subscription; 2],
196}
197
198impl WslOpenModal {
199 pub fn new(
200 paths: Vec<PathBuf>,
201 create_new_window: bool,
202 window: &mut Window,
203 cx: &mut Context<Self>,
204 ) -> Self {
205 let delegate = WslPickerDelegate::new();
206 let picker = cx.new(|cx| Picker::uniform_list(delegate, window, cx).embedded());
207
208 let selected = cx.subscribe_in(
209 &picker,
210 window,
211 |this, _, event: &WslDistroSelected, window, cx| {
212 this.confirm(&event.distro, event.secondary, window, cx);
213 },
214 );
215
216 let dismissed = cx.subscribe_in(
217 &picker,
218 window,
219 |this, _, _: &WslPickerDismissed, window, cx| {
220 this.cancel(&menu::Cancel, window, cx);
221 },
222 );
223
224 WslOpenModal {
225 paths,
226 create_new_window,
227 picker,
228 _subscriptions: [selected, dismissed],
229 }
230 }
231
232 fn confirm(
233 &mut self,
234 distro: &str,
235 secondary: bool,
236 window: &mut Window,
237 cx: &mut Context<Self>,
238 ) {
239 let app_state = workspace::AppState::global(cx);
240
241 let connection_options = RemoteConnectionOptions::Wsl(WslConnectionOptions {
242 distro_name: distro.to_string(),
243 user: None,
244 });
245
246 let replace_current_window = match self.create_new_window {
247 true => secondary,
248 false => !secondary,
249 };
250 let open_mode = if replace_current_window {
251 workspace::OpenMode::Activate
252 } else {
253 workspace::OpenMode::NewWindow
254 };
255
256 let paths = self.paths.clone();
257 let open_options = workspace::OpenOptions {
258 requesting_window: window.window_handle().downcast::<MultiWorkspace>(),
259 open_mode,
260 ..Default::default()
261 };
262
263 cx.emit(DismissEvent);
264 cx.spawn_in(window, async move |_, cx| {
265 open_remote_project(connection_options, paths, app_state, open_options, cx).await
266 })
267 .detach();
268 }
269
270 fn cancel(&mut self, _: &menu::Cancel, _: &mut Window, cx: &mut Context<Self>) {
271 cx.emit(DismissEvent);
272 }
273}
274
275impl ModalView for WslOpenModal {}
276
277impl Focusable for WslOpenModal {
278 fn focus_handle(&self, cx: &App) -> gpui::FocusHandle {
279 self.picker.focus_handle(cx)
280 }
281}
282
283impl EventEmitter<DismissEvent> for WslOpenModal {}
284
285impl Render for WslOpenModal {
286 fn render(&mut self, _: &mut Window, cx: &mut Context<Self>) -> impl ui::IntoElement {
287 div()
288 .on_mouse_down_out(cx.listener(|_, _, _, cx| cx.emit(DismissEvent)))
289 .on_action(cx.listener(Self::cancel))
290 .elevation_3(cx)
291 .w(rems(34.))
292 .flex_1()
293 .overflow_hidden()
294 .child(self.picker.clone())
295 }
296}
297