1use std::{path::Path, sync::Arc};
2
3use anyhow::Result;
4use dap::{DebugRequest, 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: DebugRequest::Launch(Default::default()),
57 label: "test".to_string(),
58 initialize_args: None,
59 tcp_connection: None,
60 stop_on_entry: None,
61 },
62 configure,
63 )
64}
65
66fn register_default_handlers(session: &Session, client: &Arc<DebugAdapterClient>, cx: &mut App) {
67 client.on_request::<dap::requests::Initialize, _>(move |_, _| Ok(Default::default()));
68 let paths = session
69 .as_local()
70 .unwrap()
71 .breakpoint_store
72 .read(cx)
73 .breakpoint_paths();
74
75 client.on_request::<dap::requests::SetBreakpoints, _>(move |_, args| {
76 let p = Arc::from(Path::new(&args.source.path.unwrap()));
77 if !paths.contains(&p) {
78 panic!("Sent breakpoints for path without any")
79 }
80
81 Ok(dap::SetBreakpointsResponse {
82 breakpoints: Vec::default(),
83 })
84 });
85
86 client.on_request::<dap::requests::Launch, _>(move |_, _| Ok(()));
87
88 client.on_request::<dap::requests::SetExceptionBreakpoints, _>(move |_, _| {
89 Ok(dap::SetExceptionBreakpointsResponse { breakpoints: None })
90 });
91
92 client.on_request::<dap::requests::Disconnect, _>(move |_, _| Ok(()));
93
94 client.on_request::<dap::requests::Threads, _>(move |_, _| {
95 Ok(dap::ThreadsResponse { threads: vec![] })
96 });
97}