1use std::{path::Path, sync::Arc};
2
3use anyhow::Result;
4use dap::{DebugRequestType, client::DebugAdapterClient};
5use gpui::{App, AppContext, Entity, Subscription, Task};
6use task::DebugTaskDefinition;
7
8use crate::Project;
9
10use super::session::Session;
11
12pub fn intercept_debug_sessions<T: Fn(&Arc<DebugAdapterClient>) + 'static>(
13 cx: &mut gpui::TestAppContext,
14 configure: T,
15) -> Subscription {
16 cx.update(|cx| {
17 cx.observe_new::<Session>(move |session, _, cx| {
18 let client = session.adapter_client().unwrap();
19 register_default_handlers(session, &client, cx);
20 configure(&client);
21 cx.background_spawn(async move {
22 client
23 .fake_event(dap::messages::Events::Initialized(Some(Default::default())))
24 .await
25 })
26 .detach();
27 })
28 })
29}
30
31pub fn start_debug_session_with<T: Fn(&Arc<DebugAdapterClient>) + 'static>(
32 project: &Entity<Project>,
33 cx: &mut gpui::TestAppContext,
34 config: DebugTaskDefinition,
35 configure: T,
36) -> Task<Result<Entity<Session>>> {
37 let subscription = intercept_debug_sessions(cx, configure);
38 let task = project.update(cx, |project, cx| project.start_debug_session(config, cx));
39 cx.spawn(async move |_| {
40 let result = task.await;
41 drop(subscription);
42 result
43 })
44}
45
46pub fn start_debug_session<T: Fn(&Arc<DebugAdapterClient>) + 'static>(
47 project: &Entity<Project>,
48 cx: &mut gpui::TestAppContext,
49 configure: T,
50) -> Task<Result<Entity<Session>>> {
51 start_debug_session_with(
52 project,
53 cx,
54 DebugTaskDefinition {
55 adapter: "fake-adapter".to_string(),
56 request: DebugRequestType::Launch(Default::default()),
57 label: "test".to_string(),
58 initialize_args: None,
59 tcp_connection: None,
60 locator: None,
61 stop_on_entry: None,
62 },
63 configure,
64 )
65}
66
67fn register_default_handlers(session: &Session, client: &Arc<DebugAdapterClient>, cx: &mut App) {
68 client.on_request::<dap::requests::Initialize, _>(move |_, _| Ok(Default::default()));
69 let paths = session
70 .as_local()
71 .unwrap()
72 .breakpoint_store
73 .read(cx)
74 .breakpoint_paths();
75
76 client.on_request::<dap::requests::SetBreakpoints, _>(move |_, args| {
77 let p = Arc::from(Path::new(&args.source.path.unwrap()));
78 if !paths.contains(&p) {
79 panic!("Sent breakpoints for path without any")
80 }
81
82 Ok(dap::SetBreakpointsResponse {
83 breakpoints: Vec::default(),
84 })
85 });
86
87 client.on_request::<dap::requests::Launch, _>(move |_, _| Ok(()));
88
89 client.on_request::<dap::requests::SetExceptionBreakpoints, _>(move |_, _| {
90 Ok(dap::SetExceptionBreakpointsResponse { breakpoints: None })
91 });
92
93 client.on_request::<dap::requests::Disconnect, _>(move |_, _| Ok(()));
94
95 client.on_request::<dap::requests::Threads, _>(move |_, _| {
96 Ok(dap::ThreadsResponse { threads: vec![] })
97 });
98}