Skip to repository content

tenant.openagents/omega

No repository description is available.

OpenAgents Git authority 2026-07-28T04:34:19.924Z 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

attach_modal.rs

321 lines · 10.1 KB · rust
1#![expect(clippy::result_large_err)]
2use crate::{
3    attach_modal::{Candidate, ModalIntent},
4    tests::start_debug_session_with,
5    *,
6};
7use attach_modal::AttachModal;
8use dap::{FakeAdapter, adapters::DebugTaskDefinition};
9use gpui::{BackgroundExecutor, TestAppContext, VisualTestContext};
10use menu::Confirm;
11use project::{FakeFs, Project};
12use serde_json::json;
13use task::{AttachRequest, SharedTaskContext};
14use tests::{init_test, init_test_workspace};
15use util::path;
16
17#[gpui::test]
18async fn test_direct_attach_to_process(executor: BackgroundExecutor, cx: &mut TestAppContext) {
19    init_test(cx);
20
21    let fs = FakeFs::new(executor.clone());
22
23    fs.insert_tree(
24        path!("/project"),
25        json!({
26            "main.rs": "First line\nSecond line\nThird line\nFourth line",
27        }),
28    )
29    .await;
30
31    let project = Project::test(fs, [path!("/project").as_ref()], cx).await;
32    let workspace = init_test_workspace(&project, cx).await;
33    let cx = &mut VisualTestContext::from_window(*workspace, cx);
34
35    let _session = start_debug_session_with(
36        &workspace,
37        cx,
38        DebugTaskDefinition {
39            adapter: "fake-adapter".into(),
40            label: "label".into(),
41            config: json!({
42               "request": "attach",
43              "process_id": 10,
44            }),
45            tcp_connection: None,
46        },
47        |client| {
48            client.on_request::<dap::requests::Attach, _>(move |_, args| {
49                let raw = &args.raw;
50                assert_eq!(raw["request"], "attach");
51                assert_eq!(raw["process_id"], 10);
52
53                Ok(())
54            });
55        },
56    )
57    .unwrap();
58
59    cx.run_until_parked();
60
61    // assert we didn't show the attach modal
62    workspace
63        .update(cx, |workspace, _window, cx| {
64            assert!(
65                workspace
66                    .workspace()
67                    .read(cx)
68                    .active_modal::<AttachModal>(cx)
69                    .is_none()
70            );
71        })
72        .unwrap();
73}
74
75#[gpui::test]
76async fn test_show_attach_modal_and_select_process(
77    executor: BackgroundExecutor,
78    cx: &mut TestAppContext,
79) {
80    init_test(cx);
81
82    let fs = FakeFs::new(executor.clone());
83
84    fs.insert_tree(
85        path!("/project"),
86        json!({
87            "main.rs": "First line\nSecond line\nThird line\nFourth line",
88        }),
89    )
90    .await;
91
92    let project = Project::test(fs, [path!("/project").as_ref()], cx).await;
93    let workspace = init_test_workspace(&project, cx).await;
94    let cx = &mut VisualTestContext::from_window(*workspace, cx);
95    // Set up handlers for sessions spawned via modal.
96    let _initialize_subscription =
97        project::debugger::test::intercept_debug_sessions(cx, |client| {
98            client.on_request::<dap::requests::Attach, _>(move |_, args| {
99                let raw = &args.raw;
100                assert_eq!(raw["request"], "attach");
101                assert_eq!(raw["process_id"], 1);
102
103                Ok(())
104            });
105        });
106    let attach_modal = workspace
107        .update(cx, |multi, window, cx| {
108            let workspace_handle = multi.workspace().downgrade();
109            multi.toggle_modal(window, cx, |window, cx| {
110                AttachModal::with_processes(
111                    workspace_handle,
112                    vec![
113                        Candidate {
114                            pid: 0,
115                            name: "fake-binary-1".into(),
116                            command: vec![],
117                        },
118                        Candidate {
119                            pid: 3,
120                            name: "real-binary-1".into(),
121                            command: vec![],
122                        },
123                        Candidate {
124                            pid: 1,
125                            name: "fake-binary-2".into(),
126                            command: vec![],
127                        },
128                    ]
129                    .into_iter()
130                    .collect(),
131                    true,
132                    ModalIntent::AttachToProcess(task::ZedDebugConfig {
133                        adapter: FakeAdapter::ADAPTER_NAME.into(),
134                        request: dap::DebugRequest::Attach(AttachRequest::default()),
135                        label: "attach example".into(),
136                        stop_on_entry: None,
137                    }),
138                    window,
139                    cx,
140                )
141            });
142
143            multi.active_modal::<AttachModal>(cx).unwrap()
144        })
145        .unwrap();
146
147    cx.run_until_parked();
148
149    // assert we got the expected processes
150    workspace
151        .update(cx, |_, window, cx| {
152            let names = attach_modal.update(cx, |modal, cx| attach_modal::process_names(modal, cx));
153            // Initially all processes are visible.
154            assert_eq!(3, names.len());
155            attach_modal.update(cx, |this, cx| {
156                this.picker.update(cx, |this, cx| {
157                    this.set_query("fakb", window, cx);
158                })
159            })
160        })
161        .unwrap();
162    cx.run_until_parked();
163    // assert we got the expected processes
164    workspace
165        .update(cx, |_, _, cx| {
166            let names = attach_modal.update(cx, |modal, cx| attach_modal::process_names(modal, cx));
167            // Initially all processes are visible.
168            assert_eq!(2, names.len());
169        })
170        .unwrap();
171    // select the only existing process
172    cx.dispatch_action(Confirm);
173
174    cx.run_until_parked();
175
176    // assert attach modal was dismissed
177    workspace
178        .update(cx, |workspace, _window, cx| {
179            assert!(workspace.active_modal::<AttachModal>(cx).is_none());
180        })
181        .unwrap();
182}
183
184#[gpui::test]
185async fn test_attach_with_pick_pid_variable(executor: BackgroundExecutor, cx: &mut TestAppContext) {
186    init_test(cx);
187
188    let fs = FakeFs::new(executor.clone());
189
190    fs.insert_tree(
191        path!("/project"),
192        json!({
193            "main.rs": "First line\nSecond line\nThird line\nFourth line",
194        }),
195    )
196    .await;
197
198    let project = Project::test(fs, [path!("/project").as_ref()], cx).await;
199    let workspace = init_test_workspace(&project, cx).await;
200    let cx = &mut VisualTestContext::from_window(*workspace, cx);
201
202    let _initialize_subscription =
203        project::debugger::test::intercept_debug_sessions(cx, |client| {
204            client.on_request::<dap::requests::Attach, _>(move |_, args| {
205                let raw = &args.raw;
206                assert_eq!(raw["request"], "attach");
207                assert_eq!(
208                    raw["process_id"], "42",
209                    "verify process id has been replaced"
210                );
211
212                Ok(())
213            });
214        });
215
216    let pick_pid_placeholder = task::VariableName::PickProcessId.template_value();
217    workspace
218        .update(cx, |multi, window, cx| {
219            multi.workspace().update(cx, |workspace, cx| {
220                workspace.start_debug_session(
221                    DebugTaskDefinition {
222                        adapter: FakeAdapter::ADAPTER_NAME.into(),
223                        label: "attach with picker".into(),
224                        config: json!({
225                            "request": "attach",
226                            "process_id": pick_pid_placeholder,
227                        }),
228                        tcp_connection: None,
229                    }
230                    .to_scenario(),
231                    SharedTaskContext::default(),
232                    None,
233                    None,
234                    window,
235                    cx,
236                );
237            })
238        })
239        .unwrap();
240
241    cx.run_until_parked();
242
243    let attach_modal = workspace
244        .update(cx, |workspace, _window, cx| {
245            workspace.active_modal::<AttachModal>(cx)
246        })
247        .unwrap();
248
249    assert!(
250        attach_modal.is_some(),
251        "Attach modal should open when config contains ZED_PICK_PID"
252    );
253
254    let attach_modal = attach_modal.unwrap();
255
256    workspace
257        .update(cx, |_, window, cx| {
258            attach_modal.update(cx, |modal, cx| {
259                attach_modal::set_candidates(
260                    modal,
261                    vec![
262                        Candidate {
263                            pid: 10,
264                            name: "process-1".into(),
265                            command: vec![],
266                        },
267                        Candidate {
268                            pid: 42,
269                            name: "target-process".into(),
270                            command: vec![],
271                        },
272                        Candidate {
273                            pid: 99,
274                            name: "process-3".into(),
275                            command: vec![],
276                        },
277                    ]
278                    .into_iter()
279                    .collect(),
280                    window,
281                    cx,
282                )
283            })
284        })
285        .unwrap();
286
287    cx.run_until_parked();
288
289    workspace
290        .update(cx, |_, window, cx| {
291            attach_modal.update(cx, |modal, cx| {
292                modal.picker.update(cx, |picker, cx| {
293                    picker.set_query("target", window, cx);
294                })
295            })
296        })
297        .unwrap();
298
299    cx.run_until_parked();
300
301    workspace
302        .update(cx, |_, _, cx| {
303            let names = attach_modal.update(cx, |modal, cx| attach_modal::process_names(modal, cx));
304            assert_eq!(names.len(), 1);
305            assert_eq!(names[0], " 42 target-process");
306        })
307        .unwrap();
308
309    cx.dispatch_action(Confirm);
310    cx.run_until_parked();
311
312    workspace
313        .update(cx, |workspace, _window, cx| {
314            assert!(
315                workspace.active_modal::<AttachModal>(cx).is_none(),
316                "Attach modal should be dismissed after selection"
317            );
318        })
319        .unwrap();
320}
321
Served at tenant.openagents/omega Member data and write actions are omitted.