History

Tidy up DAP initialization (#28730)

To make DAP work over SSH we want to create the binary at the project level (so we can wrap it in an `ssh` invocation transparently). This means not pushing the adapter down into the session, and resolving more information ahead-of-time. Co-authored-by: Anthony Eid <hello@anthonyeid.me> Co-authored-by: Piotr <piotr@zed.dev> Release Notes: - N/A ---------

Conrad Irwin committed 1 year ago

Commit aef78dc1 parent 6f0951f32 files · +1276 −1695Browse files

Unified · Split

32 files
  1. crates/dap/src/adapters.rs +36 −27
  2. crates/dap/src/client.rs +38 −19
  3. crates/dap/src/transport.rs +45 −50
  4. crates/dap_adapters/src/codelldb.rs +42 −35
  5. crates/dap_adapters/src/dap_adapters.rs +15 −2
  6. crates/dap_adapters/src/gdb.rs +44 −38
  7. crates/dap_adapters/src/go.rs +30 −25
  8. crates/dap_adapters/src/javascript.rs +38 −32
  9. crates/dap_adapters/src/lldb.rs +39 −33
  10. crates/dap_adapters/src/php.rs +25 −18
  11. crates/dap_adapters/src/python.rs +36 −31
  12. crates/debugger_ui/src/attach_modal.rs +1 −4
  13. crates/debugger_ui/src/new_session_modal.rs +1 −1
  14. crates/debugger_ui/src/tests/attach_modal.rs +30 −10
  15. crates/debugger_ui/src/tests/console.rs +8 −18
  16. crates/debugger_ui/src/tests/debugger_panel.rs +256 −355
  17. crates/debugger_ui/src/tests/module_list.rs +31 −54
  18. crates/debugger_ui/src/tests/stack_frame_list.rs +71 −102
  19. crates/debugger_ui/src/tests/variable_list.rs +254 −342
  20. crates/project/src/debugger.rs +3 −0
  21. crates/project/src/debugger/dap_store.rs +36 −127
  22. crates/project/src/debugger/locator_store.rs +2 −2
  23. crates/project/src/debugger/locator_store/cargo.rs +3 −5
  24. crates/project/src/debugger/locator_store/locators.rs +2 −2
  25. crates/project/src/debugger/session.rs +49 −298
  26. crates/project/src/debugger/test.rs +98 −0
  27. crates/project/src/project.rs +32 −51
  28. crates/project/src/project_tests.rs +1 −1
  29. crates/remote_server/src/headless_project.rs +1 −3
  30. crates/task/src/lib.rs +4 −4
  31. crates/tasks_ui/src/modal.rs +3 −4
  32. crates/workspace/src/workspace.rs +2 −2
crates/dap/src/adapters.rs+36−27
@@ -3,13 +3,13 @@ use anyhow::{Context as _, Ok, Result, anyhow}; · 2 unmodified lines
33 use async_compression::futures::bufread::GzipDecoder;
44 use async_tar::Archive;
55 use async_trait::async_trait;
6+use dap_types::StartDebuggingRequestArguments;
67 use futures::io::BufReader;
78 use gpui::{AsyncApp, SharedString};
89 pub use http_client::{HttpClient, github::latest_github_release};
910 use language::LanguageToolchainStore;
1011 use node_runtime::NodeRuntime;
1112 use serde::{Deserialize, Serialize};
12−use serde_json::Value;
1313 use settings::WorktreeId;
1414 use smol::{self, fs::File, lock::Mutex};
1515 use std::{
@@ -22,7 +22,7 @@ use std::{ · 6 unmodified lines
2222 path::PathBuf,
2323 sync::Arc,
2424 };
25−use task::{DebugAdapterConfig, DebugTaskDefinition};
25+use task::DebugTaskDefinition;
2626 use util::ResultExt;
2727
2828 #[derive(Clone, Debug, PartialEq, Eq)]
@@ -93,13 +93,15 @@ pub struct TcpArguments { · 64 unmodified lines
9393 pub port: u16,
9494 pub timeout: Option<u64>,
9595 }
96−#[derive(Default, Debug, Clone)]
96+#[derive(Debug, Clone)]
9797 pub struct DebugAdapterBinary {
98+ pub adapter_name: DebugAdapterName,
9899 pub command: String,
99100 pub arguments: Option<Vec<OsString>>,
100101 pub envs: Option<HashMap<String, String>>,
101102 pub cwd: Option<PathBuf>,
102103 pub connection: Option<TcpArguments>,
104+ pub request_args: StartDebuggingRequestArguments,
103105 }
104106
105107 #[derive(Debug)]
@@ -220,7 +222,7 @@ pub trait DebugAdapter: 'static + Send + Sync { · 114 unmodified lines
220222 async fn get_binary(
221223 &self,
222224 delegate: &dyn DapDelegate,
223− config: &DebugAdapterConfig,
225+ config: &DebugTaskDefinition,
224226 user_installed_path: Option<PathBuf>,
225227 cx: &mut AsyncApp,
226228 ) -> Result<DebugAdapterBinary> {
@@ -284,13 +286,10 @@ pub trait DebugAdapter: 'static + Send + Sync { · 57 unmodified lines
284286 async fn get_installed_binary(
285287 &self,
286288 delegate: &dyn DapDelegate,
287− config: &DebugAdapterConfig,
289+ config: &DebugTaskDefinition,
288290 user_installed_path: Option<PathBuf>,
289291 cx: &mut AsyncApp,
290292 ) -> Result<DebugAdapterBinary>;
291−
292− /// Should return base configuration to make the debug adapter work
293− fn request_args(&self, config: &DebugTaskDefinition) -> Value;
294293 }
295294 #[cfg(any(test, feature = "test-support"))]
296295 pub struct FakeAdapter {}
@@ -302,6 +301,31 @@ impl FakeAdapter { · 5 unmodified lines
302301 pub fn new() -> Self {
303302 Self {}
304303 }
304+
305+ fn request_args(&self, config: &DebugTaskDefinition) -> StartDebuggingRequestArguments {
306+ use serde_json::json;
307+ use task::DebugRequestType;
308+
309+ let value = json!({
310+ "request": match config.request {
311+ DebugRequestType::Launch(_) => "launch",
312+ DebugRequestType::Attach(_) => "attach",
313+ },
314+ "process_id": if let DebugRequestType::Attach(attach_config) = &config.request {
315+ attach_config.process_id
316+ } else {
317+ None
318+ },
319+ });
320+ let request = match config.request {
321+ DebugRequestType::Launch(_) => dap_types::StartDebuggingRequestArgumentsRequest::Launch,
322+ DebugRequestType::Attach(_) => dap_types::StartDebuggingRequestArgumentsRequest::Attach,
323+ };
324+ StartDebuggingRequestArguments {
325+ configuration: value,
326+ request,
327+ }
328+ }
305329 }
306330
307331 #[cfg(any(test, feature = "test-support"))]
@@ -314,16 +338,18 @@ impl DebugAdapter for FakeAdapter { · 6 unmodified lines
314338 async fn get_binary(
315339 &self,
316340 _: &dyn DapDelegate,
317− _: &DebugAdapterConfig,
341+ config: &DebugTaskDefinition,
318342 _: Option<PathBuf>,
319343 _: &mut AsyncApp,
320344 ) -> Result<DebugAdapterBinary> {
321345 Ok(DebugAdapterBinary {
346+ adapter_name: Self::ADAPTER_NAME.into(),
322347 command: "command".into(),
323348 arguments: None,
324349 connection: None,
325350 envs: None,
326351 cwd: None,
352+ request_args: self.request_args(config),
327353 })
328354 }
329355
@@ -345,27 +371,10 @@ impl DebugAdapter for FakeAdapter { · 15 unmodified lines
345371 async fn get_installed_binary(
346372 &self,
347373 _: &dyn DapDelegate,
348− _: &DebugAdapterConfig,
374+ _: &DebugTaskDefinition,
349375 _: Option<PathBuf>,
350376 _: &mut AsyncApp,
351377 ) -> Result<DebugAdapterBinary> {
352378 unimplemented!("get installed binary");
353379 }
354−
355− fn request_args(&self, config: &DebugTaskDefinition) -> Value {
356− use serde_json::json;
357− use task::DebugRequestType;
358−
359− json!({
360− "request": match config.request {
361− DebugRequestType::Launch(_) => "launch",
362− DebugRequestType::Attach(_) => "attach",
363− },
364− "process_id": if let DebugRequestType::Attach(attach_config) = &config.request {
365− attach_config.process_id
366− } else {
367− None
368− },
369− })
370− }
371380 }
crates/dap/src/client.rs+38−19
@@ -39,7 +39,6 @@ impl SessionId { · 38 unmodified lines
3939 /// Represents a connection to the debug adapter process, either via stdout/stdin or a socket.
4040 pub struct DebugAdapterClient {
4141 id: SessionId,
42− name: DebugAdapterName,
4342 sequence_count: AtomicU64,
4443 binary: DebugAdapterBinary,
4544 executor: BackgroundExecutor,
@@ -51,7 +50,6 @@ pub type DapMessageHandler = Box<dyn FnMut(Message) + 'static + Send + Sync>; · 5 unmodified lines
5150 impl DebugAdapterClient {
5251 pub async fn start(
5352 id: SessionId,
54− name: DebugAdapterName,
5553 binary: DebugAdapterBinary,
5654 message_handler: DapMessageHandler,
5755 cx: AsyncApp,
@@ -60,7 +58,6 @@ impl DebugAdapterClient { · 2 unmodified lines
6058 TransportDelegate::start(&binary, cx.clone()).await?;
6159 let this = Self {
6260 id,
63− name,
6461 binary,
6562 transport_delegate,
6663 sequence_count: AtomicU64::new(1),
@@ -91,6 +88,7 @@ impl DebugAdapterClient { · 24 unmodified lines
9188 ) -> Result<Self> {
9289 let binary = match self.transport_delegate.transport() {
9390 crate::transport::Transport::Tcp(tcp_transport) => DebugAdapterBinary {
91+ adapter_name: binary.adapter_name,
9492 command: binary.command,
9593 arguments: binary.arguments,
9694 envs: binary.envs,
@@ -100,11 +98,12 @@ impl DebugAdapterClient { · 3 unmodified lines
10098 port: tcp_transport.port,
10199 timeout: Some(tcp_transport.timeout),
102100 }),
101+ request_args: binary.request_args,
103102 },
104103 _ => self.binary.clone(),
105104 };
106105
107− Self::start(session_id, self.name(), binary, message_handler, cx).await
106+ Self::start(session_id, binary, message_handler, cx).await
108107 }
109108
110109 async fn handle_receive_messages(
@@ -189,7 +188,17 @@ impl DebugAdapterClient { · 78 unmodified lines
189188
190189 let response = response??;
191190 match response.success {
192− true => Ok(serde_json::from_value(response.body.unwrap_or_default())?),
191+ true => {
192+ if let Some(json) = response.body {
193+ Ok(serde_json::from_value(json)?)
194+ // Note: dap types configure themselves to return `None` when an empty object is received,
195+ // which then fails here...
196+ } else if let Ok(result) = serde_json::from_value(serde_json::Value::Object(Default::default())) {
197+ Ok(result)
198+ } else {
199+ Ok(serde_json::from_value(Default::default())?)
200+ }
201+ }
193202 false => Err(anyhow!("Request failed: {}", response.message.unwrap_or_default())),
194203 }
195204 }
@@ -211,7 +220,7 @@ impl DebugAdapterClient { · 15 unmodified lines
211220 }
212221
213222 pub fn name(&self) -> DebugAdapterName {
214− self.name.clone()
223+ self.binary.adapter_name.clone()
215224 }
216225 pub fn binary(&self) -> &DebugAdapterBinary {
217226 &self.binary
@@ -238,14 +247,14 @@ impl DebugAdapterClient { · 20 unmodified lines
238247 }
239248
240249 #[cfg(any(test, feature = "test-support"))]
241− pub async fn on_request<R: dap_types::requests::Request, F>(&self, handler: F)
250+ pub fn on_request<R: dap_types::requests::Request, F>(&self, handler: F)
242251 where
243252 F: 'static
244253 + Send
245254 + FnMut(u64, R::Arguments) -> Result<R::Response, dap_types::ErrorResponse>,
246255 {
247256 let transport = self.transport_delegate.transport().as_fake();
248− transport.on_request::<R, F>(handler).await;
257+ transport.on_request::<R, F>(handler);
249258 }
250259
251260 #[cfg(any(test, feature = "test-support"))]
@@ -282,7 +291,7 @@ mod tests { · 30 unmodified lines
282291 use crate::{client::DebugAdapterClient, debugger_settings::DebuggerSettings};
283292 use dap_types::{
284293 Capabilities, InitializeRequestArguments, InitializeRequestArgumentsPathFormat,
285− RunInTerminalRequestArguments,
294+ RunInTerminalRequestArguments, StartDebuggingRequestArguments,
286295 messages::Events,
287296 requests::{Initialize, Request, RunInTerminal},
288297 };
@@ -312,13 +321,17 @@ mod tests { · 23 unmodified lines
312321
313322 let client = DebugAdapterClient::start(
314323 crate::client::SessionId(1),
315− DebugAdapterName("adapter".into()),
316324 DebugAdapterBinary {
325+ adapter_name: "adapter".into(),
317326 command: "command".into(),
318327 arguments: Default::default(),
319328 envs: Default::default(),
320329 connection: None,
321330 cwd: None,
331+ request_args: StartDebuggingRequestArguments {
332+ configuration: serde_json::Value::Null,
333+ request: dap_types::StartDebuggingRequestArgumentsRequest::Launch,
334+ },
322335 },
323336 Box::new(|_| panic!("Did not expect to hit this code path")),
324337 cx.to_async(),
@@ -326,14 +339,12 @@ mod tests { · 1 unmodified line
326339 .await
327340 .unwrap();
328341
329− client
330− .on_request::<Initialize, _>(move |_, _| {
331− Ok(dap_types::Capabilities {
332− supports_configuration_done_request: Some(true),
333− ..Default::default()
334− })
342+ client.on_request::<Initialize, _>(move |_, _| {
343+ Ok(dap_types::Capabilities {
344+ supports_configuration_done_request: Some(true),
345+ ..Default::default()
335346 })
336− .await;
347+ });
337348
338349 cx.run_until_parked();
339350
@@ -381,13 +392,17 @@ mod tests { · 41 unmodified lines
381392
382393 let client = DebugAdapterClient::start(
383394 crate::client::SessionId(1),
384− DebugAdapterName("adapter".into()),
385395 DebugAdapterBinary {
396+ adapter_name: "adapter".into(),
386397 command: "command".into(),
387398 arguments: Default::default(),
388399 envs: Default::default(),
389400 connection: None,
390401 cwd: None,
402+ request_args: StartDebuggingRequestArguments {
403+ configuration: serde_json::Value::Null,
404+ request: dap_types::StartDebuggingRequestArgumentsRequest::Launch,
405+ },
391406 },
392407 Box::new({
393408 let called_event_handler = called_event_handler.clone();
@@ -431,13 +446,17 @@ mod tests { · 37 unmodified lines
431446
432447 let client = DebugAdapterClient::start(
433448 crate::client::SessionId(1),
434− DebugAdapterName("test-adapter".into()),
435449 DebugAdapterBinary {
450+ adapter_name: "test-adapter".into(),
436451 command: "command".into(),
437452 arguments: Default::default(),
438453 envs: Default::default(),
439454 connection: None,
440455 cwd: None,
456+ request_args: dap_types::StartDebuggingRequestArguments {
457+ configuration: serde_json::Value::Null,
458+ request: dap_types::StartDebuggingRequestArgumentsRequest::Launch,
459+ },
441460 },
442461 Box::new({
443462 let called_event_handler = called_event_handler.clone();
crates/dap/src/transport.rs+45−50
@@ -699,14 +699,8 @@ impl StdioTransport { · 698 unmodified lines
699699 }
700700
701701 #[cfg(any(test, feature = "test-support"))]
702−type RequestHandler = Box<
703− dyn Send
704− + FnMut(
705− u64,
706− serde_json::Value,
707− Arc<Mutex<async_pipe::PipeWriter>>,
708− ) -> std::pin::Pin<Box<dyn std::future::Future<Output = ()> + Send>>,
709−>;
702+type RequestHandler =
703+ Box<dyn Send + FnMut(u64, serde_json::Value) -> dap_types::messages::Response>;
710704
711705 #[cfg(any(test, feature = "test-support"))]
712706 type ResponseHandler = Box<dyn Send + Fn(Response)>;
@@ -714,45 +708,41 @@ type ResponseHandler = Box<dyn Send + Fn(Response)>; · 1 unmodified line
714708 #[cfg(any(test, feature = "test-support"))]
715709 pub struct FakeTransport {
716710 // for sending fake response back from adapter side
717− request_handlers: Arc<Mutex<HashMap<&'static str, RequestHandler>>>,
711+ request_handlers: Arc<parking_lot::Mutex<HashMap<&'static str, RequestHandler>>>,
718712 // for reverse request responses
719− response_handlers: Arc<Mutex<HashMap<&'static str, ResponseHandler>>>,
713+ response_handlers: Arc<parking_lot::Mutex<HashMap<&'static str, ResponseHandler>>>,
720714 }
721715
722716 #[cfg(any(test, feature = "test-support"))]
723717 impl FakeTransport {
724− pub async fn on_request<R: dap_types::requests::Request, F>(&self, mut handler: F)
718+ pub fn on_request<R: dap_types::requests::Request, F>(&self, mut handler: F)
725719 where
726720 F: 'static + Send + FnMut(u64, R::Arguments) -> Result<R::Response, ErrorResponse>,
727721 {
728− self.request_handlers.lock().await.insert(
722+ self.request_handlers.lock().insert(
729723 R::COMMAND,
730− Box::new(
731− move |seq, args, writer: Arc<Mutex<async_pipe::PipeWriter>>| {
732− let response = handler(seq, serde_json::from_value(args).unwrap());
733−
734− let message = serde_json::to_string(&Message::Response(Response {
724+ Box::new(move |seq, args| {
725+ let result = handler(seq, serde_json::from_value(args).unwrap());
726+ let response = match result {
727+ Ok(response) => Response {
735728 seq: seq + 1,
736729 request_seq: seq,
737− success: response.as_ref().is_ok(),
730+ success: true,
738731 command: R::COMMAND.into(),
739− body: util::maybe!({ serde_json::to_value(response.ok()?).ok() }),
732+ body: Some(serde_json::to_value(response).unwrap()),
740733 message: None,
741− }))
742− .unwrap();
743−
744− let writer = writer.clone();
745−
746− Box::pin(async move {
747− let mut writer = writer.lock().await;
748− writer
749− .write_all(TransportDelegate::build_rpc_message(message).as_bytes())
750− .await
751− .unwrap();
752− writer.flush().await.unwrap();
753− })
754− },
755− ),
734+ },
735+ Err(response) => Response {
736+ seq: seq + 1,
737+ request_seq: seq,
738+ success: false,
739+ command: R::COMMAND.into(),
740+ body: Some(serde_json::to_value(response).unwrap()),
741+ message: None,
742+ },
743+ };
744+ response
745+ }),
756746 );
757747 }
758748
@@ -762,14 +752,13 @@ impl FakeTransport { · 3 unmodified lines
762752 {
763753 self.response_handlers
764754 .lock()
765− .await
766755 .insert(R::COMMAND, Box::new(handler));
767756 }
768757
769758 async fn start(cx: AsyncApp) -> Result<(TransportPipe, Self)> {
770759 let this = Self {
771− request_handlers: Arc::new(Mutex::new(HashMap::default())),
772− response_handlers: Arc::new(Mutex::new(HashMap::default())),
760+ request_handlers: Arc::new(parking_lot::Mutex::new(HashMap::default())),
761+ response_handlers: Arc::new(parking_lot::Mutex::new(HashMap::default())),
773762 };
774763 use dap_types::requests::{Request, RunInTerminal, StartDebugging};
775764 use serde_json::json;
@@ -816,23 +805,31 @@ impl FakeTransport { · 40 unmodified lines
816805 .unwrap();
817806 writer.flush().await.unwrap();
818807 } else {
819− if let Some(handle) = request_handlers
808+ let response = if let Some(handle) = request_handlers
820809 .lock()
821− .await
822810 .get_mut(request.command.as_str())
823811 {
824812 handle(
825813 request.seq,
826814 request.arguments.unwrap_or(json!({})),
827− stdout_writer.clone(),
828815 )
829− .await;
830816 } else {
831− log::error!(
832− "No request handler for {}",
833− request.command
834− );
835− }
817+ panic!("No request handler for {}", request.command);
818+ };
819+ let message =
820+ serde_json::to_string(&Message::Response(response))
821+ .unwrap();
822+
823+ let mut writer = stdout_writer.lock().await;
824+
825+ writer
826+ .write_all(
827+ TransportDelegate::build_rpc_message(message)
828+ .as_bytes(),
829+ )
830+ .await
831+ .unwrap();
832+ writer.flush().await.unwrap();
836833 }
837834 }
838835 Message::Event(event) => {
@@ -850,10 +847,8 @@ impl FakeTransport { · 11 unmodified lines
850847 writer.flush().await.unwrap();
851848 }
852849 Message::Response(response) => {
853− if let Some(handle) = response_handlers
854− .lock()
855− .await
856− .get(response.command.as_str())
850+ if let Some(handle) =
851+ response_handlers.lock().get(response.command.as_str())
857852 {
858853 handle(response);
859854 } else {
crates/dap_adapters/src/codelldb.rs+42−35
@@ -4,7 +4,7 @@ use anyhow::{Result, bail}; · 3 unmodified lines
44 use async_trait::async_trait;
55 use dap::adapters::latest_github_release;
66 use gpui::AsyncApp;
7−use task::{DebugAdapterConfig, DebugRequestType, DebugTaskDefinition};
7+use task::{DebugRequestType, DebugTaskDefinition};
88
99 use crate::*;
1010
@@ -15,6 +15,42 @@ pub(crate) struct CodeLldbDebugAdapter { · 4 unmodified lines
1515
1616 impl CodeLldbDebugAdapter {
1717 const ADAPTER_NAME: &'static str = "CodeLLDB";
18+
19+ fn request_args(&self, config: &DebugTaskDefinition) -> dap::StartDebuggingRequestArguments {
20+ let mut configuration = json!({
21+ "request": match config.request {
22+ DebugRequestType::Launch(_) => "launch",
23+ DebugRequestType::Attach(_) => "attach",
24+ },
25+ });
26+ let map = configuration.as_object_mut().unwrap();
27+ // CodeLLDB uses `name` for a terminal label.
28+ map.insert("name".into(), Value::String(config.label.clone()));
29+ let request = config.request.to_dap();
30+ match &config.request {
31+ DebugRequestType::Attach(attach) => {
32+ map.insert("pid".into(), attach.process_id.into());
33+ }
34+ DebugRequestType::Launch(launch) => {
35+ map.insert("program".into(), launch.program.clone().into());
36+
37+ if !launch.args.is_empty() {
38+ map.insert("args".into(), launch.args.clone().into());
39+ }
40+
41+ if let Some(stop_on_entry) = config.stop_on_entry {
42+ map.insert("stopOnEntry".into(), stop_on_entry.into());
43+ }
44+ if let Some(cwd) = launch.cwd.as_ref() {
45+ map.insert("cwd".into(), cwd.to_string_lossy().into_owned().into());
46+ }
47+ }
48+ }
49+ dap::StartDebuggingRequestArguments {
50+ request,
51+ configuration,
52+ }
53+ }
1854 }
1955
2056 #[async_trait(?Send)]
@@ -86,7 +122,7 @@ impl DebugAdapter for CodeLldbDebugAdapter { · 65 unmodified lines
86122 async fn get_installed_binary(
87123 &self,
88124 _: &dyn DapDelegate,
89− _: &DebugAdapterConfig,
125+ config: &DebugTaskDefinition,
90126 _: Option<PathBuf>,
91127 _: &mut AsyncApp,
92128 ) -> Result<DebugAdapterBinary> {
@@ -111,39 +147,10 @@ impl DebugAdapter for CodeLldbDebugAdapter { · 18 unmodified lines
111147 .to_string()
112148 .into(),
113149 ]),
114− ..Default::default()
150+ request_args: self.request_args(config),
151+ adapter_name: "test".into(),
152+ envs: None,
153+ connection: None,
115154 })
116155 }
117−
118− fn request_args(&self, config: &DebugTaskDefinition) -> Value {
119− let mut args = json!({
120− "request": match config.request {
121− DebugRequestType::Launch(_) => "launch",
122− DebugRequestType::Attach(_) => "attach",
123− },
124− });
125− let map = args.as_object_mut().unwrap();
126− // CodeLLDB uses `name` for a terminal label.
127− map.insert("name".into(), Value::String(config.label.clone()));
128− match &config.request {
129− DebugRequestType::Attach(attach) => {
130− map.insert("pid".into(), attach.process_id.into());
131− }
132− DebugRequestType::Launch(launch) => {
133− map.insert("program".into(), launch.program.clone().into());
134−
135− if !launch.args.is_empty() {
136− map.insert("args".into(), launch.args.clone().into());
137− }
138−
139− if let Some(stop_on_entry) = config.stop_on_entry {
140− map.insert("stopOnEntry".into(), stop_on_entry.into());
141− }
142− if let Some(cwd) = launch.cwd.as_ref() {
143− map.insert("cwd".into(), cwd.to_string_lossy().into_owned().into());
144− }
145− }
146− }
147− args
148− }
149156 }
crates/dap_adapters/src/dap_adapters.rs+15−2
@@ -12,7 +12,7 @@ use anyhow::{Result, anyhow}; · 11 unmodified lines
1212 use async_trait::async_trait;
1313 use codelldb::CodeLldbDebugAdapter;
1414 use dap::{
15− DapRegistry,
15+ DapRegistry, DebugRequestType,
1616 adapters::{
1717 self, AdapterVersion, DapDelegate, DebugAdapter, DebugAdapterBinary, DebugAdapterName,
1818 GithubRepo,
@@ -25,7 +25,7 @@ use lldb::LldbDebugAdapter; · 6 unmodified lines
2525 use php::PhpDebugAdapter;
2626 use python::PythonDebugAdapter;
2727 use serde_json::{Value, json};
28−use task::{DebugAdapterConfig, TCPHost};
28+use task::TCPHost;
2929
3030 pub fn init(registry: Arc<DapRegistry>) {
3131 registry.add_adapter(Arc::from(CodeLldbDebugAdapter::default()));
@@ -51,3 +51,16 @@ pub(crate) async fn configure_tcp_connection( · 19 unmodified lines
5151
5252 Ok((host, port, timeout))
5353 }
54+
55+trait ToDap {
56+ fn to_dap(&self) -> dap::StartDebuggingRequestArgumentsRequest;
57+}
58+
59+impl ToDap for DebugRequestType {
60+ fn to_dap(&self) -> dap::StartDebuggingRequestArgumentsRequest {
61+ match self {
62+ Self::Launch(_) => dap::StartDebuggingRequestArgumentsRequest::Launch,
63+ Self::Attach(_) => dap::StartDebuggingRequestArgumentsRequest::Attach,
64+ }
65+ }
66+}
crates/dap_adapters/src/gdb.rs+44−38
@@ -2,8 +2,9 @@ use std::ffi::OsStr; · 1 unmodified line
22
33 use anyhow::{Result, bail};
44 use async_trait::async_trait;
5+use dap::StartDebuggingRequestArguments;
56 use gpui::AsyncApp;
6−use task::{DebugAdapterConfig, DebugRequestType, DebugTaskDefinition};
7+use task::{DebugRequestType, DebugTaskDefinition};
78
89 use crate::*;
910
@@ -12,6 +13,44 @@ pub(crate) struct GdbDebugAdapter; · 2 unmodified lines
1213
1314 impl GdbDebugAdapter {
1415 const ADAPTER_NAME: &'static str = "GDB";
16+
17+ fn request_args(&self, config: &DebugTaskDefinition) -> StartDebuggingRequestArguments {
18+ let mut args = json!({
19+ "request": match config.request {
20+ DebugRequestType::Launch(_) => "launch",
21+ DebugRequestType::Attach(_) => "attach",
22+ },
23+ });
24+
25+ let map = args.as_object_mut().unwrap();
26+ match &config.request {
27+ DebugRequestType::Attach(attach) => {
28+ map.insert("pid".into(), attach.process_id.into());
29+ }
30+
31+ DebugRequestType::Launch(launch) => {
32+ map.insert("program".into(), launch.program.clone().into());
33+
34+ if !launch.args.is_empty() {
35+ map.insert("args".into(), launch.args.clone().into());
36+ }
37+
38+ if let Some(stop_on_entry) = config.stop_on_entry {
39+ map.insert(
40+ "stopAtBeginningOfMainSubprogram".into(),
41+ stop_on_entry.into(),
42+ );
43+ }
44+ if let Some(cwd) = launch.cwd.as_ref() {
45+ map.insert("cwd".into(), cwd.to_string_lossy().into_owned().into());
46+ }
47+ }
48+ }
49+ StartDebuggingRequestArguments {
50+ configuration: args,
51+ request: config.request.to_dap(),
52+ }
53+ }
1554 }
1655
1756 #[async_trait(?Send)]
@@ -23,7 +62,7 @@ impl DebugAdapter for GdbDebugAdapter { · 5 unmodified lines
2362 async fn get_binary(
2463 &self,
2564 delegate: &dyn DapDelegate,
26− _: &DebugAdapterConfig,
65+ config: &DebugTaskDefinition,
2766 user_installed_path: Option<std::path::PathBuf>,
2867 _: &mut AsyncApp,
2968 ) -> Result<DebugAdapterBinary> {
@@ -43,11 +82,13 @@ impl DebugAdapter for GdbDebugAdapter { · 13 unmodified lines
4382 let gdb_path = user_setting_path.unwrap_or(gdb_path?);
4483
4584 Ok(DebugAdapterBinary {
85+ adapter_name: Self::ADAPTER_NAME.into(),
4686 command: gdb_path,
4787 arguments: Some(vec!["-i=dap".into()]),
4888 envs: None,
4989 cwd: None,
5090 connection: None,
91+ request_args: self.request_args(config),
5192 })
5293 }
5394
@@ -66,45 +107,10 @@ impl DebugAdapter for GdbDebugAdapter { · 12 unmodified lines
66107 async fn get_installed_binary(
67108 &self,
68109 _: &dyn DapDelegate,
69− _: &DebugAdapterConfig,
110+ _: &DebugTaskDefinition,
70111 _: Option<std::path::PathBuf>,
71112 _: &mut AsyncApp,
72113 ) -> Result<DebugAdapterBinary> {
73114 unimplemented!("GDB cannot be installed by Zed (yet)")
74115 }
75−
76− fn request_args(&self, config: &DebugTaskDefinition) -> Value {
77− let mut args = json!({
78− "request": match config.request {
79− DebugRequestType::Launch(_) => "launch",
80− DebugRequestType::Attach(_) => "attach",
81− },
82− });
83−
84− let map = args.as_object_mut().unwrap();
85− match &config.request {
86− DebugRequestType::Attach(attach) => {
87− map.insert("pid".into(), attach.process_id.into());
88− }
89−
90− DebugRequestType::Launch(launch) => {
91− map.insert("program".into(), launch.program.clone().into());
92−
93− if !launch.args.is_empty() {
94− map.insert("args".into(), launch.args.clone().into());
95− }
96−
97− if let Some(stop_on_entry) = config.stop_on_entry {
98− map.insert(
99− "stopAtBeginningOfMainSubprogram".into(),
100− stop_on_entry.into(),
101− );
102− }
103− if let Some(cwd) = launch.cwd.as_ref() {
104− map.insert("cwd".into(), cwd.to_string_lossy().into_owned().into());
105− }
106− }
107− }
108− args
109− }
110116 }
crates/dap_adapters/src/go.rs+30−25
@@ -1,3 +1,4 @@
1+use dap::StartDebuggingRequestArguments;
12 use gpui::AsyncApp;
23 use std::{ffi::OsStr, path::PathBuf};
34 use task::DebugTaskDefinition;
@@ -9,6 +10,31 @@ pub(crate) struct GoDebugAdapter; · 5 unmodified lines
910
1011 impl GoDebugAdapter {
1112 const ADAPTER_NAME: &'static str = "Delve";
13+ fn request_args(&self, config: &DebugTaskDefinition) -> StartDebuggingRequestArguments {
14+ let mut args = match &config.request {
15+ dap::DebugRequestType::Attach(attach_config) => {
16+ json!({
17+ "processId": attach_config.process_id,
18+ })
19+ }
20+ dap::DebugRequestType::Launch(launch_config) => json!({
21+ "program": launch_config.program,
22+ "cwd": launch_config.cwd,
23+ "args": launch_config.args
24+ }),
25+ };
26+
27+ let map = args.as_object_mut().unwrap();
28+
29+ if let Some(stop_on_entry) = config.stop_on_entry {
30+ map.insert("stopOnEntry".into(), stop_on_entry.into());
31+ }
32+
33+ StartDebuggingRequestArguments {
34+ configuration: args,
35+ request: config.request.to_dap(),
36+ }
37+ }
1238 }
1339
1440 #[async_trait(?Send)]
@@ -20,7 +46,7 @@ impl DebugAdapter for GoDebugAdapter { · 5 unmodified lines
2046 async fn get_binary(
2147 &self,
2248 delegate: &dyn DapDelegate,
23− config: &DebugAdapterConfig,
49+ config: &DebugTaskDefinition,
2450 user_installed_path: Option<PathBuf>,
2551 cx: &mut AsyncApp,
2652 ) -> Result<DebugAdapterBinary> {
@@ -53,7 +79,7 @@ impl DebugAdapter for GoDebugAdapter { · 26 unmodified lines
5379 async fn get_installed_binary(
5480 &self,
5581 delegate: &dyn DapDelegate,
56− config: &DebugAdapterConfig,
82+ config: &DebugTaskDefinition,
5783 _: Option<PathBuf>,
5884 _: &mut AsyncApp,
5985 ) -> Result<DebugAdapterBinary> {
@@ -66,6 +92,7 @@ impl DebugAdapter for GoDebugAdapter { · 6 unmodified lines
6692 let (host, port, timeout) = crate::configure_tcp_connection(tcp_connection).await?;
6793
6894 Ok(DebugAdapterBinary {
95+ adapter_name: self.name(),
6996 command: delve_path,
7097 arguments: Some(vec![
7198 "dap".into(),
@@ -79,29 +106,7 @@ impl DebugAdapter for GoDebugAdapter { · 7 unmodified lines
79106 port,
80107 timeout,
81108 }),
109+ request_args: self.request_args(config),
82110 })
83111 }
84−
85− fn request_args(&self, config: &DebugTaskDefinition) -> Value {
86− let mut args = match &config.request {
87− dap::DebugRequestType::Attach(attach_config) => {
88− json!({
89− "processId": attach_config.process_id,
90− })
91− }
92− dap::DebugRequestType::Launch(launch_config) => json!({
93− "program": launch_config.program,
94− "cwd": launch_config.cwd,
95− "args": launch_config.args
96− }),
97− };
98−
99− let map = args.as_object_mut().unwrap();
100−
101− if let Some(stop_on_entry) = config.stop_on_entry {
102− map.insert("stopOnEntry".into(), stop_on_entry.into());
103− }
104−
105− args
106− }
107112 }
crates/dap_adapters/src/javascript.rs+38−32
@@ -1,4 +1,5 @@
11 use adapters::latest_github_release;
2+use dap::StartDebuggingRequestArguments;
23 use gpui::AsyncApp;
34 use std::path::PathBuf;
45 use task::{DebugRequestType, DebugTaskDefinition};
@@ -12,6 +13,40 @@ impl JsDebugAdapter { · 7 unmodified lines
1213 const ADAPTER_NAME: &'static str = "JavaScript";
1314 const ADAPTER_NPM_NAME: &'static str = "vscode-js-debug";
1415 const ADAPTER_PATH: &'static str = "js-debug/src/dapDebugServer.js";
16+
17+ fn request_args(&self, config: &DebugTaskDefinition) -> StartDebuggingRequestArguments {
18+ let mut args = json!({
19+ "type": "pwa-node",
20+ "request": match config.request {
21+ DebugRequestType::Launch(_) => "launch",
22+ DebugRequestType::Attach(_) => "attach",
23+ },
24+ });
25+ let map = args.as_object_mut().unwrap();
26+ match &config.request {
27+ DebugRequestType::Attach(attach) => {
28+ map.insert("processId".into(), attach.process_id.into());
29+ }
30+ DebugRequestType::Launch(launch) => {
31+ map.insert("program".into(), launch.program.clone().into());
32+
33+ if !launch.args.is_empty() {
34+ map.insert("args".into(), launch.args.clone().into());
35+ }
36+
37+ if let Some(stop_on_entry) = config.stop_on_entry {
38+ map.insert("stopOnEntry".into(), stop_on_entry.into());
39+ }
40+ if let Some(cwd) = launch.cwd.as_ref() {
41+ map.insert("cwd".into(), cwd.to_string_lossy().into_owned().into());
42+ }
43+ }
44+ }
45+ StartDebuggingRequestArguments {
46+ configuration: args,
47+ request: config.request.to_dap(),
48+ }
49+ }
1550 }
1651
1752 #[async_trait(?Send)]
@@ -49,7 +84,7 @@ impl DebugAdapter for JsDebugAdapter { · 31 unmodified lines
4984 async fn get_installed_binary(
5085 &self,
5186 delegate: &dyn DapDelegate,
52− config: &DebugAdapterConfig,
87+ config: &DebugTaskDefinition,
5388 user_installed_path: Option<PathBuf>,
5489 _: &mut AsyncApp,
5590 ) -> Result<DebugAdapterBinary> {
@@ -71,6 +106,7 @@ impl DebugAdapter for JsDebugAdapter { · 15 unmodified lines
71106 let (host, port, timeout) = crate::configure_tcp_connection(tcp_connection).await?;
72107
73108 Ok(DebugAdapterBinary {
109+ adapter_name: self.name(),
74110 command: delegate
75111 .node_runtime()
76112 .binary_path()
@@ -89,6 +125,7 @@ impl DebugAdapter for JsDebugAdapter { · 12 unmodified lines
89125 port,
90126 timeout,
91127 }),
128+ request_args: self.request_args(config),
92129 })
93130 }
94131
@@ -107,35 +144,4 @@ impl DebugAdapter for JsDebugAdapter { · 12 unmodified lines
107144
108145 return Ok(());
109146 }
110−
111− fn request_args(&self, config: &DebugTaskDefinition) -> Value {
112− let mut args = json!({
113− "type": "pwa-node",
114− "request": match config.request {
115− DebugRequestType::Launch(_) => "launch",
116− DebugRequestType::Attach(_) => "attach",
117− },
118− });
119− let map = args.as_object_mut().unwrap();
120− match &config.request {
121− DebugRequestType::Attach(attach) => {
122− map.insert("processId".into(), attach.process_id.into());
123− }
124− DebugRequestType::Launch(launch) => {
125− map.insert("program".into(), launch.program.clone().into());
126−
127− if !launch.args.is_empty() {
128− map.insert("args".into(), launch.args.clone().into());
129− }
130−
131− if let Some(stop_on_entry) = config.stop_on_entry {
132− map.insert("stopOnEntry".into(), stop_on_entry.into());
133− }
134− if let Some(cwd) = launch.cwd.as_ref() {
135− map.insert("cwd".into(), cwd.to_string_lossy().into_owned().into());
136− }
137− }
138− }
139− args
140− }
141147 }
crates/dap_adapters/src/lldb.rs+39−33
@@ -3,7 +3,7 @@ use std::{ffi::OsStr, path::PathBuf}; · 2 unmodified lines
33 use anyhow::Result;
44 use async_trait::async_trait;
55 use gpui::AsyncApp;
6−use task::{DebugAdapterConfig, DebugRequestType, DebugTaskDefinition};
6+use task::{DebugRequestType, DebugTaskDefinition};
77
88 use crate::*;
99
@@ -12,6 +12,40 @@ pub(crate) struct LldbDebugAdapter; · 2 unmodified lines
1212
1313 impl LldbDebugAdapter {
1414 const ADAPTER_NAME: &'static str = "LLDB";
15+
16+ fn request_args(&self, config: &DebugTaskDefinition) -> dap::StartDebuggingRequestArguments {
17+ let request = config.request.to_dap();
18+ let mut args = json!({
19+ "request": match config.request {
20+ DebugRequestType::Launch(_) => "launch",
21+ DebugRequestType::Attach(_) => "attach",
22+ },
23+ });
24+ let map = args.as_object_mut().unwrap();
25+ match &config.request {
26+ DebugRequestType::Attach(attach) => {
27+ map.insert("pid".into(), attach.process_id.into());
28+ }
29+ DebugRequestType::Launch(launch) => {
30+ map.insert("program".into(), launch.program.clone().into());
31+
32+ if !launch.args.is_empty() {
33+ map.insert("args".into(), launch.args.clone().into());
34+ }
35+
36+ if let Some(stop_on_entry) = config.stop_on_entry {
37+ map.insert("stopOnEntry".into(), stop_on_entry.into());
38+ }
39+ if let Some(cwd) = launch.cwd.as_ref() {
40+ map.insert("cwd".into(), cwd.to_string_lossy().into_owned().into());
41+ }
42+ }
43+ }
44+ dap::StartDebuggingRequestArguments {
45+ request,
46+ configuration: args,
47+ }
48+ }
1549 }
1650
1751 #[async_trait(?Send)]
@@ -23,7 +57,7 @@ impl DebugAdapter for LldbDebugAdapter { · 5 unmodified lines
2357 async fn get_binary(
2458 &self,
2559 delegate: &dyn DapDelegate,
26− _: &DebugAdapterConfig,
60+ config: &DebugTaskDefinition,
2761 user_installed_path: Option<PathBuf>,
2862 _: &mut AsyncApp,
2963 ) -> Result<DebugAdapterBinary> {
@@ -37,11 +71,13 @@ impl DebugAdapter for LldbDebugAdapter { · 7 unmodified lines
3771 };
3872
3973 Ok(DebugAdapterBinary {
74+ adapter_name: Self::ADAPTER_NAME.into(),
4075 command: lldb_dap_path,
4176 arguments: None,
4277 envs: None,
4378 cwd: None,
4479 connection: None,
80+ request_args: self.request_args(config),
4581 })
4682 }
4783
@@ -60,40 +96,10 @@ impl DebugAdapter for LldbDebugAdapter { · 12 unmodified lines
6096 async fn get_installed_binary(
6197 &self,
6298 _: &dyn DapDelegate,
63− _: &DebugAdapterConfig,
99+ _: &DebugTaskDefinition,
64100 _: Option<PathBuf>,
65101 _: &mut AsyncApp,
66102 ) -> Result<DebugAdapterBinary> {
67103 unimplemented!("LLDB debug adapter cannot be installed by Zed (yet)")
68104 }
69−
70− fn request_args(&self, config: &DebugTaskDefinition) -> Value {
71− let mut args = json!({
72− "request": match config.request {
73− DebugRequestType::Launch(_) => "launch",
74− DebugRequestType::Attach(_) => "attach",
75− },
76− });
77− let map = args.as_object_mut().unwrap();
78− match &config.request {
79− DebugRequestType::Attach(attach) => {
80− map.insert("pid".into(), attach.process_id.into());
81− }
82− DebugRequestType::Launch(launch) => {
83− map.insert("program".into(), launch.program.clone().into());
84−
85− if !launch.args.is_empty() {
86− map.insert("args".into(), launch.args.clone().into());
87− }
88−
89− if let Some(stop_on_entry) = config.stop_on_entry {
90− map.insert("stopOnEntry".into(), stop_on_entry.into());
91− }
92− if let Some(cwd) = launch.cwd.as_ref() {
93− map.insert("cwd".into(), cwd.to_string_lossy().into_owned().into());
94− }
95− }
96− }
97− args
98− }
99105 }
crates/dap_adapters/src/php.rs+25−18
@@ -13,6 +13,28 @@ impl PhpDebugAdapter { · 12 unmodified lines
1313 const ADAPTER_NAME: &'static str = "PHP";
1414 const ADAPTER_PACKAGE_NAME: &'static str = "vscode-php-debug";
1515 const ADAPTER_PATH: &'static str = "extension/out/phpDebug.js";
16+
17+ fn request_args(
18+ &self,
19+ config: &DebugTaskDefinition,
20+ ) -> Result<dap::StartDebuggingRequestArguments> {
21+ match &config.request {
22+ dap::DebugRequestType::Attach(_) => {
23+ anyhow::bail!("php adapter does not support attaching")
24+ }
25+ dap::DebugRequestType::Launch(launch_config) => {
26+ Ok(dap::StartDebuggingRequestArguments {
27+ configuration: json!({
28+ "program": launch_config.program,
29+ "cwd": launch_config.cwd,
30+ "args": launch_config.args,
31+ "stopOnEntry": config.stop_on_entry.unwrap_or_default(),
32+ }),
33+ request: config.request.to_dap(),
34+ })
35+ }
36+ }
37+ }
1638 }
1739
1840 #[async_trait(?Send)]
@@ -50,7 +72,7 @@ impl DebugAdapter for PhpDebugAdapter { · 31 unmodified lines
5072 async fn get_installed_binary(
5173 &self,
5274 delegate: &dyn DapDelegate,
53− config: &DebugAdapterConfig,
75+ config: &DebugTaskDefinition,
5476 user_installed_path: Option<PathBuf>,
5577 _: &mut AsyncApp,
5678 ) -> Result<DebugAdapterBinary> {
@@ -72,6 +94,7 @@ impl DebugAdapter for PhpDebugAdapter { · 15 unmodified lines
7294 let (host, port, timeout) = crate::configure_tcp_connection(tcp_connection).await?;
7395
7496 Ok(DebugAdapterBinary {
97+ adapter_name: self.name(),
7598 command: delegate
7699 .node_runtime()
77100 .binary_path()
@@ -89,6 +112,7 @@ impl DebugAdapter for PhpDebugAdapter { · 11 unmodified lines
89112 }),
90113 cwd: None,
91114 envs: None,
115+ request_args: self.request_args(config)?,
92116 })
93117 }
94118
@@ -107,21 +131,4 @@ impl DebugAdapter for PhpDebugAdapter { · 12 unmodified lines
107131
108132 Ok(())
109133 }
110−
111− fn request_args(&self, config: &DebugTaskDefinition) -> Value {
112− match &config.request {
113− dap::DebugRequestType::Attach(_) => {
114− // php adapter does not support attaching
115− json!({})
116− }
117− dap::DebugRequestType::Launch(launch_config) => {
118− json!({
119− "program": launch_config.program,
120− "cwd": launch_config.cwd,
121− "args": launch_config.args,
122− "stopOnEntry": config.stop_on_entry.unwrap_or_default(),
123− })
124− }
125− }
126− }
127134 }
crates/dap_adapters/src/python.rs+36−31
@@ -1,5 +1,5 @@
11 use crate::*;
2−use dap::DebugRequestType;
2+use dap::{DebugRequestType, StartDebuggingRequestArguments};
33 use gpui::AsyncApp;
44 use std::{ffi::OsStr, path::PathBuf};
55 use task::DebugTaskDefinition;
@@ -12,6 +12,38 @@ impl PythonDebugAdapter { · 6 unmodified lines
1212 const ADAPTER_PACKAGE_NAME: &'static str = "debugpy";
1313 const ADAPTER_PATH: &'static str = "src/debugpy/adapter";
1414 const LANGUAGE_NAME: &'static str = "Python";
15+
16+ fn request_args(&self, config: &DebugTaskDefinition) -> StartDebuggingRequestArguments {
17+ let mut args = json!({
18+ "request": match config.request {
19+ DebugRequestType::Launch(_) => "launch",
20+ DebugRequestType::Attach(_) => "attach",
21+ },
22+ "subProcess": true,
23+ "redirectOutput": true,
24+ });
25+ let map = args.as_object_mut().unwrap();
26+ match &config.request {
27+ DebugRequestType::Attach(attach) => {
28+ map.insert("processId".into(), attach.process_id.into());
29+ }
30+ DebugRequestType::Launch(launch) => {
31+ map.insert("program".into(), launch.program.clone().into());
32+ map.insert("args".into(), launch.args.clone().into());
33+
34+ if let Some(stop_on_entry) = config.stop_on_entry {
35+ map.insert("stopOnEntry".into(), stop_on_entry.into());
36+ }
37+ if let Some(cwd) = launch.cwd.as_ref() {
38+ map.insert("cwd".into(), cwd.to_string_lossy().into_owned().into());
39+ }
40+ }
41+ }
42+ StartDebuggingRequestArguments {
43+ configuration: args,
44+ request: config.request.to_dap(),
45+ }
46+ }
1547 }
1648
1749 #[async_trait(?Send)]
@@ -64,7 +96,7 @@ impl DebugAdapter for PythonDebugAdapter { · 46 unmodified lines
6496 async fn get_installed_binary(
6597 &self,
6698 delegate: &dyn DapDelegate,
67− config: &DebugAdapterConfig,
99+ config: &DebugTaskDefinition,
68100 user_installed_path: Option<PathBuf>,
69101 cx: &mut AsyncApp,
70102 ) -> Result<DebugAdapterBinary> {
@@ -109,6 +141,7 @@ impl DebugAdapter for PythonDebugAdapter { · 38 unmodified lines
109141 };
110142
111143 Ok(DebugAdapterBinary {
144+ adapter_name: self.name(),
112145 command: python_path.ok_or(anyhow!("failed to find binary path for python"))?,
113146 arguments: Some(vec![
114147 debugpy_dir.join(Self::ADAPTER_PATH).into(),
@@ -122,35 +155,7 @@ impl DebugAdapter for PythonDebugAdapter { · 7 unmodified lines
122155 }),
123156 cwd: None,
124157 envs: None,
158+ request_args: self.request_args(config),
125159 })
126160 }
127−
128− fn request_args(&self, config: &DebugTaskDefinition) -> Value {
129− let mut args = json!({
130− "request": match config.request {
131− DebugRequestType::Launch(_) => "launch",
132− DebugRequestType::Attach(_) => "attach",
133− },
134− "subProcess": true,
135− "redirectOutput": true,
136− });
137− let map = args.as_object_mut().unwrap();
138− match &config.request {
139− DebugRequestType::Attach(attach) => {
140− map.insert("processId".into(), attach.process_id.into());
141− }
142− DebugRequestType::Launch(launch) => {
143− map.insert("program".into(), launch.program.clone().into());
144− map.insert("args".into(), launch.args.clone().into());
145−
146− if let Some(stop_on_entry) = config.stop_on_entry {
147− map.insert("stopOnEntry".into(), stop_on_entry.into());
148− }
149− if let Some(cwd) = launch.cwd.as_ref() {
150− map.insert("cwd".into(), cwd.to_string_lossy().into_owned().into());
151− }
152− }
153− }
154− args
155− }
156161 }
crates/debugger_ui/src/attach_modal.rs+1−4
@@ -228,10 +228,7 @@ impl PickerDelegate for AttachModalDelegate { · 227 unmodified lines
228228 let config = self.debug_config.clone();
229229 self.project
230230 .update(cx, |project, cx| {
231− #[cfg(any(test, feature = "test-support"))]
232− let ret = project.fake_debug_session(config.request, None, false, cx);
233− #[cfg(not(any(test, feature = "test-support")))]
234− let ret = project.start_debug_session(config.into(), cx);
231+ let ret = project.start_debug_session(config, cx);
235232 ret
236233 })
237234 .detach_and_log_err(cx);
crates/debugger_ui/src/new_session_modal.rs+1−1
@@ -146,7 +146,7 @@ impl NewSessionModal { · 145 unmodified lines
146146 {
147147 this.start_debug_session(debug_config, cx)
148148 } else {
149− this.start_debug_session(config.into(), cx)
149+ this.start_debug_session(config, cx)
150150 }
151151 })?;
152152 let spawn_result = task.await;
crates/debugger_ui/src/tests/attach_modal.rs+30−10
@@ -26,18 +26,30 @@ async fn test_direct_attach_to_process(executor: BackgroundExecutor, cx: &mut Te · 25 unmodified lines
2626 let workspace = init_test_workspace(&project, cx).await;
2727 let cx = &mut VisualTestContext::from_window(*workspace, cx);
2828
29− let task = project.update(cx, |project, cx| {
30− project.fake_debug_session(
31− dap::DebugRequestType::Attach(AttachConfig {
29+ let session = debugger::test::start_debug_session_with(
30+ &project,
31+ cx,
32+ DebugTaskDefinition {
33+ adapter: "fake-adapter".to_string(),
34+ request: dap::DebugRequestType::Attach(AttachConfig {
3235 process_id: Some(10),
3336 }),
34− None,
35− false,
36− cx,
37− )
38− });
39−
40− let session = task.await.unwrap();
37+ label: "label".to_string(),
38+ initialize_args: None,
39+ tcp_connection: None,
40+ locator: None,
41+ stop_on_entry: None,
42+ },
43+ |client| {
44+ client.on_request::<dap::requests::Attach, _>(move |_, args| {
45+ assert_eq!(json!({"request": "attach", "process_id": 10}), args.raw);
46+
47+ Ok(())
48+ });
49+ },
50+ )
51+ .await
52+ .unwrap();
4153
4254 cx.run_until_parked();
4355
@@ -77,7 +89,15 @@ async fn test_show_attach_modal_and_select_process( · 33 unmodified lines
7789 let project = Project::test(fs, ["/project".as_ref()], cx).await;
7890 let workspace = init_test_workspace(&project, cx).await;
7991 let cx = &mut VisualTestContext::from_window(*workspace, cx);
92+ // Set up handlers for sessions spawned via modal.
93+ let _initialize_subscription =
94+ project::debugger::test::intercept_debug_sessions(cx, |client| {
95+ client.on_request::<dap::requests::Attach, _>(move |_, args| {
96+ assert_eq!(json!({"request": "attach", "process_id": 1}), args.raw);
8097
98+ Ok(())
99+ });
100+ });
81101 let attach_modal = workspace
82102 .update(cx, |workspace, window, cx| {
83103 workspace.toggle_modal(window, cx, |window, cx| {
crates/debugger_ui/src/tests/console.rs+8−18
@@ -3,7 +3,6 @@ use dap::requests::StackTrace; · 2 unmodified lines
33 use gpui::{BackgroundExecutor, TestAppContext, VisualTestContext};
44 use project::{FakeFs, Project};
55 use serde_json::json;
6−use task::LaunchConfig;
76 use tests::{init_test, init_test_workspace};
87
98 #[gpui::test]
@@ -29,26 +28,17 @@ async fn test_handle_output_event(executor: BackgroundExecutor, cx: &mut TestApp · 19 unmodified lines
2928 })
3029 .unwrap();
3130
32− let task = project.update(cx, |project, cx| {
33− project.fake_debug_session(
34− dap::DebugRequestType::Launch(LaunchConfig::default()),
35− None,
36− false,
37− cx,
38− )
39− });
40−
41− let session = task.await.unwrap();
31+ let session = debugger::test::start_debug_session(&project, cx, |_| {})
32+ .await
33+ .unwrap();
4234 let client = session.update(cx, |session, _| session.adapter_client().unwrap());
4335
44− client
45− .on_request::<StackTrace, _>(move |_, _| {
46− Ok(dap::StackTraceResponse {
47− stack_frames: Vec::default(),
48− total_frames: None,
49− })
36+ client.on_request::<StackTrace, _>(move |_, _| {
37+ Ok(dap::StackTraceResponse {
38+ stack_frames: Vec::default(),
39+ total_frames: None,
5040 })
51− .await;
41+ });
5242
5343 client
5444 .fake_event(dap::messages::Events::Output(dap::OutputEvent {
crates/debugger_ui/src/tests/debugger_panel.rs+256−355
@@ -1,7 +1,7 @@
11 use crate::*;
22 use dap::{
3− ErrorResponse, RunInTerminalRequestArguments, SourceBreakpoint, StartDebuggingRequestArguments,
4− StartDebuggingRequestArgumentsRequest,
3+ ErrorResponse, Message, RunInTerminalRequestArguments, SourceBreakpoint,
4+ StartDebuggingRequestArguments, StartDebuggingRequestArgumentsRequest,
55 client::SessionId,
66 requests::{
77 Continue, Disconnect, Launch, Next, RunInTerminal, SetBreakpoints, StackTrace,
@@ -25,7 +25,6 @@ use std::{ · 17 unmodified lines
2525 atomic::{AtomicBool, Ordering},
2626 },
2727 };
28−use task::LaunchConfig;
2928 use terminal_view::{TerminalView, terminal_panel::TerminalPanel};
3029 use tests::{active_debug_session_panel, init_test, init_test_workspace};
3130 use util::path;
@@ -49,37 +48,26 @@ async fn test_basic_show_debug_panel(executor: BackgroundExecutor, cx: &mut Test · 17 unmodified lines
4948 let workspace = init_test_workspace(&project, cx).await;
5049 let cx = &mut VisualTestContext::from_window(*workspace, cx);
5150
52− let task = project.update(cx, |project, cx| {
53− project.fake_debug_session(
54− dap::DebugRequestType::Launch(LaunchConfig::default()),
55− None,
56− false,
57− cx,
58− )
59− });
60−
61− let session = task.await.unwrap();
51+ let session = debugger::test::start_debug_session(&project, cx, |_| {})
52+ .await
53+ .unwrap();
6254 let client = session.update(cx, |session, _| session.adapter_client().unwrap());
6355
64− client
65− .on_request::<Threads, _>(move |_, _| {
66− Ok(dap::ThreadsResponse {
67− threads: vec![dap::Thread {
68− id: 1,
69− name: "Thread 1".into(),
70− }],
71− })
56+ client.on_request::<Threads, _>(move |_, _| {
57+ Ok(dap::ThreadsResponse {
58+ threads: vec![dap::Thread {
59+ id: 1,
60+ name: "Thread 1".into(),
61+ }],
7262 })
73− .await;
63+ });
7464
75− client
76− .on_request::<StackTrace, _>(move |_, _| {
77− Ok(dap::StackTraceResponse {
78− stack_frames: Vec::default(),
79− total_frames: None,
80− })
65+ client.on_request::<StackTrace, _>(move |_, _| {
66+ Ok(dap::StackTraceResponse {
67+ stack_frames: Vec::default(),
68+ total_frames: None,
8169 })
82− .await;
70+ });
8371
8472 cx.run_until_parked();
8573
@@ -199,37 +187,26 @@ async fn test_we_can_only_have_one_panel_per_debug_session( · 113 unmodified lines
199187 let workspace = init_test_workspace(&project, cx).await;
200188 let cx = &mut VisualTestContext::from_window(*workspace, cx);
201189
202− let task = project.update(cx, |project, cx| {
203− project.fake_debug_session(
204− dap::DebugRequestType::Launch(LaunchConfig::default()),
205− None,
206− false,
207− cx,
208− )
209− });
210−
211− let session = task.await.unwrap();
190+ let session = debugger::test::start_debug_session(&project, cx, |_| {})
191+ .await
192+ .unwrap();
212193 let client = session.update(cx, |session, _| session.adapter_client().unwrap());
213194
214− client
215− .on_request::<Threads, _>(move |_, _| {
216− Ok(dap::ThreadsResponse {
217− threads: vec![dap::Thread {
218− id: 1,
219− name: "Thread 1".into(),
220− }],
221− })
195+ client.on_request::<Threads, _>(move |_, _| {
196+ Ok(dap::ThreadsResponse {
197+ threads: vec![dap::Thread {
198+ id: 1,
199+ name: "Thread 1".into(),
200+ }],
222201 })
223− .await;
202+ });
224203
225− client
226− .on_request::<StackTrace, _>(move |_, _| {
227− Ok(dap::StackTraceResponse {
228− stack_frames: Vec::default(),
229− total_frames: None,
230− })
204+ client.on_request::<StackTrace, _>(move |_, _| {
205+ Ok(dap::StackTraceResponse {
206+ stack_frames: Vec::default(),
207+ total_frames: None,
231208 })
232− .await;
209+ });
233210
234211 cx.run_until_parked();
235212
@@ -377,16 +354,9 @@ async fn test_handle_successful_run_in_terminal_reverse_request( · 141 unmodified lines
377354 let workspace = init_test_workspace(&project, cx).await;
378355 let cx = &mut VisualTestContext::from_window(*workspace, cx);
379356
380− let task = project.update(cx, |project, cx| {
381− project.fake_debug_session(
382− dap::DebugRequestType::Launch(LaunchConfig::default()),
383− None,
384− false,
385− cx,
386− )
387− });
388−
389− let session = task.await.unwrap();
357+ let session = debugger::test::start_debug_session(&project, cx, |_| {})
358+ .await
359+ .unwrap();
390360 let client = session.update(cx, |session, _| session.adapter_client().unwrap());
391361
392362 client
@@ -474,16 +444,9 @@ async fn test_handle_error_run_in_terminal_reverse_request( · 81 unmodified lines
474444 let workspace = init_test_workspace(&project, cx).await;
475445 let cx = &mut VisualTestContext::from_window(*workspace, cx);
476446
477− let task = project.update(cx, |project, cx| {
478− project.fake_debug_session(
479− dap::DebugRequestType::Launch(LaunchConfig::default()),
480− None,
481− false,
482− cx,
483− )
484− });
485−
486− let session = task.await.unwrap();
447+ let session = debugger::test::start_debug_session(&project, cx, |_| {})
448+ .await
449+ .unwrap();
487450 let client = session.update(cx, |session, _| session.adapter_client().unwrap());
488451
489452 client
@@ -559,28 +522,19 @@ async fn test_handle_start_debugging_reverse_request( · 69 unmodified lines
559522 let workspace = init_test_workspace(&project, cx).await;
560523 let cx = &mut VisualTestContext::from_window(*workspace, cx);
561524
562− let task = project.update(cx, |project, cx| {
563− project.fake_debug_session(
564− dap::DebugRequestType::Launch(LaunchConfig::default()),
565− None,
566− false,
567− cx,
568− )
569− });
570−
571− let session = task.await.unwrap();
525+ let session = debugger::test::start_debug_session(&project, cx, |_| {})
526+ .await
527+ .unwrap();
572528 let client = session.update(cx, |session, _| session.adapter_client().unwrap());
573529
574− client
575− .on_request::<dap::requests::Threads, _>(move |_, _| {
576− Ok(dap::ThreadsResponse {
577− threads: vec![dap::Thread {
578− id: 1,
579− name: "Thread 1".into(),
580− }],
581− })
530+ client.on_request::<dap::requests::Threads, _>(move |_, _| {
531+ Ok(dap::ThreadsResponse {
532+ threads: vec![dap::Thread {
533+ id: 1,
534+ name: "Thread 1".into(),
535+ }],
582536 })
583− .await;
537+ });
584538
585539 client
586540 .on_response::<StartDebugging, _>({
@@ -593,7 +547,9 @@ async fn test_handle_start_debugging_reverse_request( · 6 unmodified lines
593547 }
594548 })
595549 .await;
596−
550+ // Set up handlers for sessions spawned with reverse request too.
551+ let _reverse_request_subscription =
552+ project::debugger::test::intercept_debug_sessions(cx, |_| {});
597553 client
598554 .fake_reverse_request::<StartDebugging>(StartDebuggingRequestArguments {
599555 configuration: json!({}),
@@ -612,20 +568,16 @@ async fn test_handle_start_debugging_reverse_request( · 12 unmodified lines
612568 });
613569 let child_client = child_session.update(cx, |session, _| session.adapter_client().unwrap());
614570
615− child_client
616− .on_request::<dap::requests::Threads, _>(move |_, _| {
617− Ok(dap::ThreadsResponse {
618− threads: vec![dap::Thread {
619− id: 1,
620− name: "Thread 1".into(),
621− }],
622− })
571+ child_client.on_request::<dap::requests::Threads, _>(move |_, _| {
572+ Ok(dap::ThreadsResponse {
573+ threads: vec![dap::Thread {
574+ id: 1,
575+ name: "Thread 1".into(),
576+ }],
623577 })
624− .await;
578+ });
625579
626− child_client
627− .on_request::<Disconnect, _>(move |_, _| Ok(()))
628− .await;
580+ child_client.on_request::<Disconnect, _>(move |_, _| Ok(()));
629581
630582 child_client
631583 .fake_event(dap::messages::Events::Stopped(dap::StoppedEvent {
@@ -677,31 +629,24 @@ async fn test_shutdown_children_when_parent_session_shutdown( · 45 unmodified lines
677629 let workspace = init_test_workspace(&project, cx).await;
678630 let cx = &mut VisualTestContext::from_window(*workspace, cx);
679631
680− let task = project.update(cx, |project, cx| {
681− project.fake_debug_session(
682− dap::DebugRequestType::Launch(LaunchConfig::default()),
683− None,
684− false,
685− cx,
686− )
687− });
688−
689− let parent_session = task.await.unwrap();
632+ let parent_session = debugger::test::start_debug_session(&project, cx, |_| {})
633+ .await
634+ .unwrap();
690635 let client = parent_session.update(cx, |session, _| session.adapter_client().unwrap());
691636
692− client
693− .on_request::<dap::requests::Threads, _>(move |_, _| {
694− Ok(dap::ThreadsResponse {
695− threads: vec![dap::Thread {
696− id: 1,
697− name: "Thread 1".into(),
698− }],
699− })
637+ client.on_request::<dap::requests::Threads, _>(move |_, _| {
638+ Ok(dap::ThreadsResponse {
639+ threads: vec![dap::Thread {
640+ id: 1,
641+ name: "Thread 1".into(),
642+ }],
700643 })
701− .await;
644+ });
702645
703646 client.on_response::<StartDebugging, _>(move |_| {}).await;
704−
647+ // Set up handlers for sessions spawned with reverse request too.
648+ let _reverse_request_subscription =
649+ project::debugger::test::intercept_debug_sessions(cx, |_| {});
705650 // start first child session
706651 client
707652 .fake_reverse_request::<StartDebugging>(StartDebuggingRequestArguments {
@@ -729,9 +674,7 @@ async fn test_shutdown_children_when_parent_session_shutdown( · 21 unmodified lines
729674 let first_child_client =
730675 first_child_session.update(cx, |session, _| session.adapter_client().unwrap());
731676
732− first_child_client
733− .on_request::<Disconnect, _>(move |_, _| Ok(()))
734− .await;
677+ first_child_client.on_request::<Disconnect, _>(move |_, _| Ok(()));
735678
736679 // configure second child session
737680 let second_child_session = dap_store.read_with(cx, |dap_store, _| {
@@ -740,9 +683,7 @@ async fn test_shutdown_children_when_parent_session_shutdown( · 2 unmodified lines
740683 let second_child_client =
741684 second_child_session.update(cx, |session, _| session.adapter_client().unwrap());
742685
743− second_child_client
744− .on_request::<Disconnect, _>(move |_, _| Ok(()))
745− .await;
686+ second_child_client.on_request::<Disconnect, _>(move |_, _| Ok(()));
746687
747688 cx.run_until_parked();
748689
@@ -796,20 +737,15 @@ async fn test_shutdown_parent_session_if_all_children_are_shutdown( · 47 unmodified lines
796737 let workspace = init_test_workspace(&project, cx).await;
797738 let cx = &mut VisualTestContext::from_window(*workspace, cx);
798739
799− let task = project.update(cx, |project, cx| {
800− project.fake_debug_session(
801− dap::DebugRequestType::Launch(LaunchConfig::default()),
802− None,
803− false,
804− cx,
805− )
806− });
807−
808− let parent_session = task.await.unwrap();
740+ let parent_session = debugger::test::start_debug_session(&project, cx, |_| {})
741+ .await
742+ .unwrap();
809743 let client = parent_session.update(cx, |session, _| session.adapter_client().unwrap());
810744
811745 client.on_response::<StartDebugging, _>(move |_| {}).await;
812−
746+ // Set up handlers for sessions spawned with reverse request too.
747+ let _reverse_request_subscription =
748+ project::debugger::test::intercept_debug_sessions(cx, |_| {});
813749 // start first child session
814750 client
815751 .fake_reverse_request::<StartDebugging>(StartDebuggingRequestArguments {
@@ -837,9 +773,7 @@ async fn test_shutdown_parent_session_if_all_children_are_shutdown( · 21 unmodified lines
837773 let first_child_client =
838774 first_child_session.update(cx, |session, _| session.adapter_client().unwrap());
839775
840− first_child_client
841− .on_request::<Disconnect, _>(move |_, _| Ok(()))
842− .await;
776+ first_child_client.on_request::<Disconnect, _>(move |_, _| Ok(()));
843777
844778 // configure second child session
845779 let second_child_session = dap_store.read_with(cx, |dap_store, _| {
@@ -848,9 +782,7 @@ async fn test_shutdown_parent_session_if_all_children_are_shutdown( · 2 unmodified lines
848782 let second_child_client =
849783 second_child_session.update(cx, |session, _| session.adapter_client().unwrap());
850784
851− second_child_client
852− .on_request::<Disconnect, _>(move |_, _| Ok(()))
853− .await;
785+ second_child_client.on_request::<Disconnect, _>(move |_, _| Ok(()));
854786
855787 cx.run_until_parked();
856788
@@ -926,123 +858,107 @@ async fn test_debug_panel_item_thread_status_reset_on_failure( · 69 unmodified lines
926858 let workspace = init_test_workspace(&project, cx).await;
927859 let cx = &mut VisualTestContext::from_window(*workspace, cx);
928860
929− let task = project.update(cx, |project, cx| {
930− project.fake_debug_session(
931− dap::DebugRequestType::Launch(LaunchConfig::default()),
932− Some(dap::Capabilities {
861+ let session = debugger::test::start_debug_session(&project, cx, |client| {
862+ client.on_request::<dap::requests::Initialize, _>(move |_, _| {
863+ Ok(dap::Capabilities {
933864 supports_step_back: Some(true),
934865 ..Default::default()
935− }),
936− false,
937− cx,
938− )
939− });
866+ })
867+ });
868+ })
869+ .await
870+ .unwrap();
940871
941− let session = task.await.unwrap();
942872 let client = session.update(cx, |session, _| session.adapter_client().unwrap());
943873 const THREAD_ID_NUM: u64 = 1;
944874
945− client
946− .on_request::<dap::requests::Threads, _>(move |_, _| {
947− Ok(dap::ThreadsResponse {
948− threads: vec![dap::Thread {
949− id: THREAD_ID_NUM,
950− name: "Thread 1".into(),
951− }],
952− })
875+ client.on_request::<dap::requests::Threads, _>(move |_, _| {
876+ Ok(dap::ThreadsResponse {
877+ threads: vec![dap::Thread {
878+ id: THREAD_ID_NUM,
879+ name: "Thread 1".into(),
880+ }],
953881 })
954− .await;
882+ });
955883
956− client.on_request::<Launch, _>(move |_, _| Ok(())).await;
884+ client.on_request::<Launch, _>(move |_, _| Ok(()));
957885
958− client
959− .on_request::<StackTrace, _>(move |_, _| {
960− Ok(dap::StackTraceResponse {
961− stack_frames: Vec::default(),
962− total_frames: None,
963− })
886+ client.on_request::<StackTrace, _>(move |_, _| {
887+ Ok(dap::StackTraceResponse {
888+ stack_frames: Vec::default(),
889+ total_frames: None,
964890 })
965− .await;
891+ });
966892
967− client
968− .on_request::<Next, _>(move |_, _| {
969− Err(ErrorResponse {
970− error: Some(dap::Message {
971− id: 1,
972− format: "error".into(),
973− variables: None,
974− send_telemetry: None,
975− show_user: None,
976− url: None,
977− url_label: None,
978− }),
979− })
893+ client.on_request::<Next, _>(move |_, _| {
894+ Err(ErrorResponse {
895+ error: Some(dap::Message {
896+ id: 1,
897+ format: "error".into(),
898+ variables: None,
899+ send_telemetry: None,
900+ show_user: None,
901+ url: None,
902+ url_label: None,
903+ }),
980904 })
981− .await;
905+ });
982906
983− client
984− .on_request::<StepOut, _>(move |_, _| {
985− Err(ErrorResponse {
986− error: Some(dap::Message {
987− id: 1,
988− format: "error".into(),
989− variables: None,
990− send_telemetry: None,
991− show_user: None,
992− url: None,
993− url_label: None,
994− }),
995− })
907+ client.on_request::<StepOut, _>(move |_, _| {
908+ Err(ErrorResponse {
909+ error: Some(dap::Message {
910+ id: 1,
911+ format: "error".into(),
912+ variables: None,
913+ send_telemetry: None,
914+ show_user: None,
915+ url: None,
916+ url_label: None,
917+ }),
996918 })
997− .await;
919+ });
998920
999− client
1000− .on_request::<StepIn, _>(move |_, _| {
1001− Err(ErrorResponse {
1002− error: Some(dap::Message {
1003− id: 1,
1004− format: "error".into(),
1005− variables: None,
1006− send_telemetry: None,
1007− show_user: None,
1008− url: None,
1009− url_label: None,
1010− }),
1011− })
921+ client.on_request::<StepIn, _>(move |_, _| {
922+ Err(ErrorResponse {
923+ error: Some(dap::Message {
924+ id: 1,
925+ format: "error".into(),
926+ variables: None,
927+ send_telemetry: None,
928+ show_user: None,
929+ url: None,
930+ url_label: None,
931+ }),
1012932 })
1013− .await;
933+ });
1014934
1015− client
1016− .on_request::<StepBack, _>(move |_, _| {
1017− Err(ErrorResponse {
1018− error: Some(dap::Message {
1019− id: 1,
1020− format: "error".into(),
1021− variables: None,
1022− send_telemetry: None,
1023− show_user: None,
1024− url: None,
1025− url_label: None,
1026− }),
1027− })
935+ client.on_request::<StepBack, _>(move |_, _| {
936+ Err(ErrorResponse {
937+ error: Some(dap::Message {
938+ id: 1,
939+ format: "error".into(),
940+ variables: None,
941+ send_telemetry: None,
942+ show_user: None,
943+ url: None,
944+ url_label: None,
945+ }),
1028946 })
1029− .await;
947+ });
1030948
1031− client
1032− .on_request::<Continue, _>(move |_, _| {
1033− Err(ErrorResponse {
1034− error: Some(dap::Message {
1035− id: 1,
1036− format: "error".into(),
1037− variables: None,
1038− send_telemetry: None,
1039− show_user: None,
1040− url: None,
1041− url_label: None,
1042− }),
1043− })
949+ client.on_request::<Continue, _>(move |_, _| {
950+ Err(ErrorResponse {
951+ error: Some(dap::Message {
952+ id: 1,
953+ format: "error".into(),
954+ variables: None,
955+ send_telemetry: None,
956+ show_user: None,
957+ url: None,
958+ url_label: None,
959+ }),
1044960 })
1045− .await;
961+ });
1046962
1047963 client
1048964 .fake_event(dap::messages::Events::Stopped(dap::StoppedEvent {
@@ -1157,16 +1073,9 @@ async fn test_send_breakpoints_when_editor_has_been_saved( · 108 unmodified lines
11571073 .update(cx, |_, _, cx| worktree.read(cx).id())
11581074 .unwrap();
11591075
1160− let task = project.update(cx, |project, cx| {
1161− project.fake_debug_session(
1162− dap::DebugRequestType::Launch(LaunchConfig::default()),
1163− None,
1164− false,
1165− cx,
1166− )
1167− });
1168−
1169− let session = task.await.unwrap();
1076+ let session = debugger::test::start_debug_session(&project, cx, |_| {})
1077+ .await
1078+ .unwrap();
11701079 let client = session.update(cx, |session, _| session.adapter_client().unwrap());
11711080
11721081 let buffer = project
@@ -1186,16 +1095,14 @@ async fn test_send_breakpoints_when_editor_has_been_saved( · 13 unmodified lines
11861095 )
11871096 });
11881097
1189− client.on_request::<Launch, _>(move |_, _| Ok(())).await;
1098+ client.on_request::<Launch, _>(move |_, _| Ok(()));
11901099
1191− client
1192− .on_request::<StackTrace, _>(move |_, _| {
1193− Ok(dap::StackTraceResponse {
1194− stack_frames: Vec::default(),
1195− total_frames: None,
1196− })
1100+ client.on_request::<StackTrace, _>(move |_, _| {
1101+ Ok(dap::StackTraceResponse {
1102+ stack_frames: Vec::default(),
1103+ total_frames: None,
11971104 })
1198− .await;
1105+ });
11991106
12001107 client
12011108 .fake_event(dap::messages::Events::Stopped(dap::StoppedEvent {
@@ -1210,32 +1117,30 @@ async fn test_send_breakpoints_when_editor_has_been_saved( · 8 unmodified lines
12101117 .await;
12111118
12121119 let called_set_breakpoints = Arc::new(AtomicBool::new(false));
1213− client
1214− .on_request::<SetBreakpoints, _>({
1215− let called_set_breakpoints = called_set_breakpoints.clone();
1216− move |_, args| {
1217− assert_eq!(path!("/project/main.rs"), args.source.path.unwrap());
1218− assert_eq!(
1219− vec![SourceBreakpoint {
1220− line: 2,
1221− column: None,
1222− condition: None,
1223− hit_condition: None,
1224− log_message: None,
1225− mode: None
1226− }],
1227− args.breakpoints.unwrap()
1228− );
1229− assert!(!args.source_modified.unwrap());
1120+ client.on_request::<SetBreakpoints, _>({
1121+ let called_set_breakpoints = called_set_breakpoints.clone();
1122+ move |_, args| {
1123+ assert_eq!(path!("/project/main.rs"), args.source.path.unwrap());
1124+ assert_eq!(
1125+ vec![SourceBreakpoint {
1126+ line: 2,
1127+ column: None,
1128+ condition: None,
1129+ hit_condition: None,
1130+ log_message: None,
1131+ mode: None
1132+ }],
1133+ args.breakpoints.unwrap()
1134+ );
1135+ assert!(!args.source_modified.unwrap());
12301136
1231− called_set_breakpoints.store(true, Ordering::SeqCst);
1137+ called_set_breakpoints.store(true, Ordering::SeqCst);
12321138
1233− Ok(dap::SetBreakpointsResponse {
1234− breakpoints: Vec::default(),
1235− })
1236− }
1237− })
1238− .await;
1139+ Ok(dap::SetBreakpointsResponse {
1140+ breakpoints: Vec::default(),
1141+ })
1142+ }
1143+ });
12391144
12401145 editor.update_in(cx, |editor, window, cx| {
12411146 editor.move_down(&actions::MoveDown, window, cx);
@@ -1250,32 +1155,30 @@ async fn test_send_breakpoints_when_editor_has_been_saved( · 8 unmodified lines
12501155 );
12511156
12521157 let called_set_breakpoints = Arc::new(AtomicBool::new(false));
1253− client
1254− .on_request::<SetBreakpoints, _>({
1255− let called_set_breakpoints = called_set_breakpoints.clone();
1256− move |_, args| {
1257− assert_eq!(path!("/project/main.rs"), args.source.path.unwrap());
1258− assert_eq!(
1259− vec![SourceBreakpoint {
1260− line: 3,
1261− column: None,
1262− condition: None,
1263− hit_condition: None,
1264− log_message: None,
1265− mode: None
1266− }],
1267− args.breakpoints.unwrap()
1268− );
1269− assert!(args.source_modified.unwrap());
1158+ client.on_request::<SetBreakpoints, _>({
1159+ let called_set_breakpoints = called_set_breakpoints.clone();
1160+ move |_, args| {
1161+ assert_eq!(path!("/project/main.rs"), args.source.path.unwrap());
1162+ assert_eq!(
1163+ vec![SourceBreakpoint {
1164+ line: 3,
1165+ column: None,
1166+ condition: None,
1167+ hit_condition: None,
1168+ log_message: None,
1169+ mode: None
1170+ }],
1171+ args.breakpoints.unwrap()
1172+ );
1173+ assert!(args.source_modified.unwrap());
12701174
1271− called_set_breakpoints.store(true, Ordering::SeqCst);
1175+ called_set_breakpoints.store(true, Ordering::SeqCst);
12721176
1273− Ok(dap::SetBreakpointsResponse {
1274− breakpoints: Vec::default(),
1275− })
1276− }
1277− })
1278− .await;
1177+ Ok(dap::SetBreakpointsResponse {
1178+ breakpoints: Vec::default(),
1179+ })
1180+ }
1181+ });
12791182
12801183 editor.update_in(cx, |editor, window, cx| {
12811184 editor.move_up(&actions::MoveUp, window, cx);
@@ -1387,49 +1290,40 @@ async fn test_unsetting_breakpoints_on_clear_breakpoint_action( · 105 unmodified lines
13871290 editor.toggle_breakpoint(&actions::ToggleBreakpoint, window, cx);
13881291 });
13891292
1390− let task = project.update(cx, |project, cx| {
1391− project.fake_debug_session(
1392− dap::DebugRequestType::Launch(LaunchConfig::default()),
1393− None,
1394− false,
1395− cx,
1396− )
1397− });
1398−
1399− let session = task.await.unwrap();
1293+ let session = debugger::test::start_debug_session(&project, cx, |_| {})
1294+ .await
1295+ .unwrap();
14001296 let client = session.update(cx, |session, _| session.adapter_client().unwrap());
14011297
14021298 let called_set_breakpoints = Arc::new(AtomicBool::new(false));
14031299
1404− client
1405− .on_request::<SetBreakpoints, _>({
1406− let called_set_breakpoints = called_set_breakpoints.clone();
1407− move |_, args| {
1408− assert!(
1409− args.breakpoints.is_none_or(|bps| bps.is_empty()),
1410− "Send empty breakpoint sets to clear them from DAP servers"
1411− );
1300+ client.on_request::<SetBreakpoints, _>({
1301+ let called_set_breakpoints = called_set_breakpoints.clone();
1302+ move |_, args| {
1303+ assert!(
1304+ args.breakpoints.is_none_or(|bps| bps.is_empty()),
1305+ "Send empty breakpoint sets to clear them from DAP servers"
1306+ );
14121307
1413− match args
1414− .source
1415− .path
1416− .expect("We should always send a breakpoint's path")
1417− .as_str()
1418− {
1419− "/project/main.rs" | "/project/second.rs" => {}
1420− _ => {
1421− panic!("Unset breakpoints for path that doesn't have any")
1422− }
1308+ match args
1309+ .source
1310+ .path
1311+ .expect("We should always send a breakpoint's path")
1312+ .as_str()
1313+ {
1314+ "/project/main.rs" | "/project/second.rs" => {}
1315+ _ => {
1316+ panic!("Unset breakpoints for path that doesn't have any")
14231317 }
1318+ }
14241319
1425− called_set_breakpoints.store(true, Ordering::SeqCst);
1320+ called_set_breakpoints.store(true, Ordering::SeqCst);
14261321
1427− Ok(dap::SetBreakpointsResponse {
1428− breakpoints: Vec::default(),
1429− })
1430− }
1431− })
1432− .await;
1322+ Ok(dap::SetBreakpointsResponse {
1323+ breakpoints: Vec::default(),
1324+ })
1325+ }
1326+ });
14331327
14341328 cx.dispatch_action(crate::ClearAllBreakpoints);
14351329 cx.run_until_parked();
@@ -1464,13 +1358,20 @@ async fn test_debug_session_is_shutdown_when_attach_and_launch_request_fails( · 28 unmodified lines
14641358 let workspace = init_test_workspace(&project, cx).await;
14651359 let cx = &mut VisualTestContext::from_window(*workspace, cx);
14661360
1467− let task = project.update(cx, |project, cx| {
1468− project.fake_debug_session(
1469− dap::DebugRequestType::Launch(LaunchConfig::default()),
1470− None,
1471− true,
1472− cx,
1473− )
1361+ let task = project::debugger::test::start_debug_session(&project, cx, |client| {
1362+ client.on_request::<dap::requests::Initialize, _>(|_, _| {
1363+ Err(ErrorResponse {
1364+ error: Some(Message {
1365+ format: "failed to launch".to_string(),
1366+ id: 1,
1367+ variables: None,
1368+ send_telemetry: None,
1369+ show_user: None,
1370+ url: None,
1371+ url_label: None,
1372+ }),
1373+ })
1374+ });
14741375 });
14751376
14761377 assert!(
crates/debugger_ui/src/tests/module_list.rs+31−54
@@ -4,15 +4,17 @@ use crate::{ · 3 unmodified lines
44 };
55 use dap::{
66 StoppedEvent,
7− requests::{Modules, StackTrace, Threads},
7+ requests::{Initialize, Modules},
88 };
99 use gpui::{BackgroundExecutor, TestAppContext, VisualTestContext};
10−use project::{FakeFs, Project};
10+use project::{
11+ FakeFs, Project,
12+ debugger::{self},
13+};
1114 use std::sync::{
1215 Arc,
1316 atomic::{AtomicBool, AtomicI32, Ordering},
1417 };
15−use task::LaunchConfig;
1618
1719 #[gpui::test]
1820 async fn test_module_list(executor: BackgroundExecutor, cx: &mut TestAppContext) {
@@ -29,31 +31,19 @@ async fn test_module_list(executor: BackgroundExecutor, cx: &mut TestAppContext) · 10 unmodified lines
2931 .unwrap();
3032 let cx = &mut VisualTestContext::from_window(*workspace, cx);
3133
32− let task = project.update(cx, |project, cx| {
33− project.fake_debug_session(
34− dap::DebugRequestType::Launch(LaunchConfig::default()),
35− Some(dap::Capabilities {
34+ let session = debugger::test::start_debug_session(&project, cx, |client| {
35+ client.on_request::<Initialize, _>(move |_, _| {
36+ Ok(dap::Capabilities {
3637 supports_modules_request: Some(true),
3738 ..Default::default()
38− }),
39− false,
40− cx,
41− )
42− });
39+ })
40+ });
41+ })
42+ .await
43+ .unwrap();
4344
44− let session = task.await.unwrap();
4545 let client = session.update(cx, |session, _| session.adapter_client().unwrap());
4646
47− client
48− .on_request::<StackTrace, _>(move |_, args| {
49− assert!(args.thread_id == 1);
50− Ok(dap::StackTraceResponse {
51− stack_frames: Vec::default(),
52− total_frames: None,
53− })
54− })
55− .await;
56−
5747 let called_modules = Arc::new(AtomicBool::new(false));
5848 let modules = vec![
5949 dap::Module {
@@ -82,38 +72,25 @@ async fn test_module_list(executor: BackgroundExecutor, cx: &mut TestAppContext) · 22 unmodified lines
8272 },
8373 ];
8474
85− client
86− .on_request::<Threads, _>(move |_, _| {
87− Ok(dap::ThreadsResponse {
88− threads: vec![dap::Thread {
89− id: 1,
90− name: "Thread 1".into(),
91− }],
75+ client.on_request::<Modules, _>({
76+ let called_modules = called_modules.clone();
77+ let modules_request_count = AtomicI32::new(0);
78+ let modules = modules.clone();
79+ move |_, _| {
80+ modules_request_count.fetch_add(1, Ordering::SeqCst);
81+ assert_eq!(
82+ 1,
83+ modules_request_count.load(Ordering::SeqCst),
84+ "This request should only be called once from the host"
85+ );
86+ called_modules.store(true, Ordering::SeqCst);
87+
88+ Ok(dap::ModulesResponse {
89+ modules: modules.clone(),
90+ total_modules: Some(2u64),
9291 })
93− })
94− .await;
95−
96− client
97− .on_request::<Modules, _>({
98− let called_modules = called_modules.clone();
99− let modules_request_count = AtomicI32::new(0);
100− let modules = modules.clone();
101− move |_, _| {
102− modules_request_count.fetch_add(1, Ordering::SeqCst);
103− assert_eq!(
104− 1,
105− modules_request_count.load(Ordering::SeqCst),
106− "This request should only be called once from the host"
107− );
108− called_modules.store(true, Ordering::SeqCst);
109−
110− Ok(dap::ModulesResponse {
111− modules: modules.clone(),
112− total_modules: Some(2u64),
113− })
114− }
115− })
116− .await;
92+ }
93+ });
11794
11895 client
11996 .fake_event(dap::messages::Events::Stopped(StoppedEvent {
crates/debugger_ui/src/tests/stack_frame_list.rs+71−102
@@ -5,14 +5,13 @@ use crate::{ · 4 unmodified lines
55 };
66 use dap::{
77 StackFrame,
8− requests::{StackTrace, Threads},
8+ requests::{Scopes, StackTrace, Threads},
99 };
1010 use editor::{Editor, ToPoint as _};
1111 use gpui::{BackgroundExecutor, TestAppContext, VisualTestContext};
12−use project::{FakeFs, Project};
12+use project::{FakeFs, Project, debugger};
1313 use serde_json::json;
1414 use std::sync::Arc;
15−use task::LaunchConfig;
1615 use unindent::Unindent as _;
1716 use util::path;
1817
@@ -51,29 +50,20 @@ async fn test_fetch_initial_stack_frames_and_go_to_stack_frame( · 32 unmodified lines
5150 let project = Project::test(fs, [path!("/project").as_ref()], cx).await;
5251 let workspace = init_test_workspace(&project, cx).await;
5352 let cx = &mut VisualTestContext::from_window(*workspace, cx);
54−
55− let task = project.update(cx, |project, cx| {
56− project.fake_debug_session(
57− dap::DebugRequestType::Launch(LaunchConfig::default()),
58− None,
59− false,
60− cx,
61− )
62− });
63−
64− let session = task.await.unwrap();
53+ let session = debugger::test::start_debug_session(&project, cx, |_| {})
54+ .await
55+ .unwrap();
6556 let client = session.update(cx, |session, _| session.adapter_client().unwrap());
66−
67− client
68− .on_request::<Threads, _>(move |_, _| {
69− Ok(dap::ThreadsResponse {
70− threads: vec![dap::Thread {
71− id: 1,
72− name: "Thread 1".into(),
73− }],
74− })
57+ client.on_request::<Scopes, _>(move |_, _| Ok(dap::ScopesResponse { scopes: vec![] }));
58+
59+ client.on_request::<Threads, _>(move |_, _| {
60+ Ok(dap::ThreadsResponse {
61+ threads: vec![dap::Thread {
62+ id: 1,
63+ name: "Thread 1".into(),
64+ }],
7565 })
76− .await;
66+ });
7767
7868 let stack_frames = vec![
7969 StackFrame {
@@ -122,19 +112,17 @@ async fn test_fetch_initial_stack_frames_and_go_to_stack_frame( · 42 unmodified lines
122112 },
123113 ];
124114
125− client
126− .on_request::<StackTrace, _>({
127− let stack_frames = Arc::new(stack_frames.clone());
128− move |_, args| {
129− assert_eq!(1, args.thread_id);
130−
131− Ok(dap::StackTraceResponse {
132− stack_frames: (*stack_frames).clone(),
133− total_frames: None,
134− })
135− }
136− })
137− .await;
115+ client.on_request::<StackTrace, _>({
116+ let stack_frames = Arc::new(stack_frames.clone());
117+ move |_, args| {
118+ assert_eq!(1, args.thread_id);
119+
120+ Ok(dap::StackTraceResponse {
121+ stack_frames: (*stack_frames).clone(),
122+ total_frames: None,
123+ })
124+ }
125+ });
138126
139127 client
140128 .fake_event(dap::messages::Events::Stopped(dap::StoppedEvent {
@@ -241,29 +229,21 @@ async fn test_select_stack_frame(executor: BackgroundExecutor, cx: &mut TestAppC · 100 unmodified lines
241229 });
242230
243231 let cx = &mut VisualTestContext::from_window(*workspace, cx);
244−
245− let task = project.update(cx, |project, cx| {
246− project.fake_debug_session(
247− dap::DebugRequestType::Launch(LaunchConfig::default()),
248− None,
249− false,
250− cx,
251− )
252− });
253−
254− let session = task.await.unwrap();
232+ let session = debugger::test::start_debug_session(&project, cx, |_| {})
233+ .await
234+ .unwrap();
255235 let client = session.update(cx, |session, _| session.adapter_client().unwrap());
256236
257− client
258− .on_request::<Threads, _>(move |_, _| {
259− Ok(dap::ThreadsResponse {
260− threads: vec![dap::Thread {
261− id: 1,
262− name: "Thread 1".into(),
263− }],
264− })
237+ client.on_request::<Threads, _>(move |_, _| {
238+ Ok(dap::ThreadsResponse {
239+ threads: vec![dap::Thread {
240+ id: 1,
241+ name: "Thread 1".into(),
242+ }],
265243 })
266− .await;
244+ });
245+
246+ client.on_request::<Scopes, _>(move |_, _| Ok(dap::ScopesResponse { scopes: vec![] }));
267247
268248 let stack_frames = vec![
269249 StackFrame {
@@ -312,19 +292,17 @@ async fn test_select_stack_frame(executor: BackgroundExecutor, cx: &mut TestAppC · 42 unmodified lines
312292 },
313293 ];
314294
315− client
316− .on_request::<StackTrace, _>({
317− let stack_frames = Arc::new(stack_frames.clone());
318− move |_, args| {
319− assert_eq!(1, args.thread_id);
320−
321− Ok(dap::StackTraceResponse {
322− stack_frames: (*stack_frames).clone(),
323− total_frames: None,
324− })
325− }
326− })
327− .await;
295+ client.on_request::<StackTrace, _>({
296+ let stack_frames = Arc::new(stack_frames.clone());
297+ move |_, args| {
298+ assert_eq!(1, args.thread_id);
299+
300+ Ok(dap::StackTraceResponse {
301+ stack_frames: (*stack_frames).clone(),
302+ total_frames: None,
303+ })
304+ }
305+ });
328306
329307 client
330308 .fake_event(dap::messages::Events::Stopped(dap::StoppedEvent {
@@ -517,28 +495,21 @@ async fn test_collapsed_entries(executor: BackgroundExecutor, cx: &mut TestAppCo · 186 unmodified lines
517495 let workspace = init_test_workspace(&project, cx).await;
518496 let cx = &mut VisualTestContext::from_window(*workspace, cx);
519497
520− let task = project.update(cx, |project, cx| {
521− project.fake_debug_session(
522− dap::DebugRequestType::Launch(LaunchConfig::default()),
523− None,
524− false,
525− cx,
526− )
527− });
528−
529− let session = task.await.unwrap();
498+ let session = debugger::test::start_debug_session(&project, cx, |_| {})
499+ .await
500+ .unwrap();
530501 let client = session.update(cx, |session, _| session.adapter_client().unwrap());
531502
532− client
533− .on_request::<Threads, _>(move |_, _| {
534− Ok(dap::ThreadsResponse {
535− threads: vec![dap::Thread {
536− id: 1,
537− name: "Thread 1".into(),
538− }],
539− })
503+ client.on_request::<Threads, _>(move |_, _| {
504+ Ok(dap::ThreadsResponse {
505+ threads: vec![dap::Thread {
506+ id: 1,
507+ name: "Thread 1".into(),
508+ }],
540509 })
541− .await;
510+ });
511+
512+ client.on_request::<Scopes, _>(move |_, _| Ok(dap::ScopesResponse { scopes: vec![] }));
542513
543514 let stack_frames = vec![
544515 StackFrame {
@@ -697,19 +668,17 @@ async fn test_collapsed_entries(executor: BackgroundExecutor, cx: &mut TestAppCo · 152 unmodified lines
697668 },
698669 ];
699670
700− client
701− .on_request::<StackTrace, _>({
702− let stack_frames = Arc::new(stack_frames.clone());
703− move |_, args| {
704− assert_eq!(1, args.thread_id);
705−
706− Ok(dap::StackTraceResponse {
707− stack_frames: (*stack_frames).clone(),
708− total_frames: None,
709− })
710− }
711− })
712− .await;
671+ client.on_request::<StackTrace, _>({
672+ let stack_frames = Arc::new(stack_frames.clone());
673+ move |_, args| {
674+ assert_eq!(1, args.thread_id);
675+
676+ Ok(dap::StackTraceResponse {
677+ stack_frames: (*stack_frames).clone(),
678+ total_frames: None,
679+ })
680+ }
681+ });
713682
714683 client
715684 .fake_event(dap::messages::Events::Stopped(dap::StoppedEvent {
crates/debugger_ui/src/tests/variable_list.rs+254−342
@@ -15,9 +15,8 @@ use dap::{ · 14 unmodified lines
1515 };
1616 use gpui::{BackgroundExecutor, TestAppContext, VisualTestContext};
1717 use menu::{SelectFirst, SelectNext, SelectPrevious};
18−use project::{FakeFs, Project};
18+use project::{FakeFs, Project, debugger};
1919 use serde_json::json;
20−use task::LaunchConfig;
2120 use unindent::Unindent as _;
2221 use util::path;
2322
@@ -55,29 +54,19 @@ async fn test_basic_fetch_initial_scope_and_variables( · 31 unmodified lines
5554 })
5655 .unwrap();
5756 let cx = &mut VisualTestContext::from_window(*workspace, cx);
58−
59− let task = project.update(cx, |project, cx| {
60− project.fake_debug_session(
61− dap::DebugRequestType::Launch(LaunchConfig::default()),
62− None,
63− false,
64− cx,
65− )
66− });
67−
68− let session = task.await.unwrap();
57+ let session = debugger::test::start_debug_session(&project, cx, |_| {})
58+ .await
59+ .unwrap();
6960 let client = session.update(cx, |session, _| session.adapter_client().unwrap());
7061
71− client
72− .on_request::<dap::requests::Threads, _>(move |_, _| {
73− Ok(dap::ThreadsResponse {
74− threads: vec![dap::Thread {
75− id: 1,
76− name: "Thread 1".into(),
77− }],
78− })
62+ client.on_request::<dap::requests::Threads, _>(move |_, _| {
63+ Ok(dap::ThreadsResponse {
64+ threads: vec![dap::Thread {
65+ id: 1,
66+ name: "Thread 1".into(),
67+ }],
7968 })
80− .await;
69+ });
8170
8271 let stack_frames = vec![StackFrame {
8372 id: 1,
@@ -102,19 +91,17 @@ async fn test_basic_fetch_initial_scope_and_variables( · 18 unmodified lines
10291 presentation_hint: None,
10392 }];
10493
105− client
106− .on_request::<StackTrace, _>({
107− let stack_frames = Arc::new(stack_frames.clone());
108− move |_, args| {
109− assert_eq!(1, args.thread_id);
110−
111− Ok(dap::StackTraceResponse {
112− stack_frames: (*stack_frames).clone(),
113− total_frames: None,
114− })
115− }
116− })
117− .await;
94+ client.on_request::<StackTrace, _>({
95+ let stack_frames = Arc::new(stack_frames.clone());
96+ move |_, args| {
97+ assert_eq!(1, args.thread_id);
98+
99+ Ok(dap::StackTraceResponse {
100+ stack_frames: (*stack_frames).clone(),
101+ total_frames: None,
102+ })
103+ }
104+ });
118105
119106 let scopes = vec![Scope {
120107 name: "Scope 1".into(),
@@ -130,18 +117,16 @@ async fn test_basic_fetch_initial_scope_and_variables( · 9 unmodified lines
130117 end_column: None,
131118 }];
132119
133− client
134− .on_request::<Scopes, _>({
135− let scopes = Arc::new(scopes.clone());
136− move |_, args| {
137− assert_eq!(1, args.frame_id);
120+ client.on_request::<Scopes, _>({
121+ let scopes = Arc::new(scopes.clone());
122+ move |_, args| {
123+ assert_eq!(1, args.frame_id);
138124
139− Ok(dap::ScopesResponse {
140− scopes: (*scopes).clone(),
141− })
142− }
143− })
144− .await;
125+ Ok(dap::ScopesResponse {
126+ scopes: (*scopes).clone(),
127+ })
128+ }
129+ });
145130
146131 let variables = vec![
147132 Variable {
@@ -172,18 +157,16 @@ async fn test_basic_fetch_initial_scope_and_variables( · 24 unmodified lines
172157 },
173158 ];
174159
175− client
176− .on_request::<Variables, _>({
177− let variables = Arc::new(variables.clone());
178− move |_, args| {
179− assert_eq!(2, args.variables_reference);
160+ client.on_request::<Variables, _>({
161+ let variables = Arc::new(variables.clone());
162+ move |_, args| {
163+ assert_eq!(2, args.variables_reference);
180164
181− Ok(dap::VariablesResponse {
182− variables: (*variables).clone(),
183− })
184− }
185− })
186− .await;
165+ Ok(dap::VariablesResponse {
166+ variables: (*variables).clone(),
167+ })
168+ }
169+ });
187170
188171 client
189172 .fake_event(dap::messages::Events::Stopped(dap::StoppedEvent {
@@ -283,39 +266,28 @@ async fn test_fetch_variables_for_multiple_scopes( · 93 unmodified lines
283266 .unwrap();
284267 let cx = &mut VisualTestContext::from_window(*workspace, cx);
285268
286− let task = project.update(cx, |project, cx| {
287− project.fake_debug_session(
288− dap::DebugRequestType::Launch(LaunchConfig::default()),
289− None,
290− false,
291− cx,
292− )
293− });
294−
295− let session = task.await.unwrap();
269+ let session = debugger::test::start_debug_session(&project, cx, |_| {})
270+ .await
271+ .unwrap();
296272 let client = session.update(cx, |session, _| session.adapter_client().unwrap());
297273
298− client
299− .on_request::<dap::requests::Threads, _>(move |_, _| {
300− Ok(dap::ThreadsResponse {
301− threads: vec![dap::Thread {
302− id: 1,
303− name: "Thread 1".into(),
304− }],
305− })
274+ client.on_request::<dap::requests::Threads, _>(move |_, _| {
275+ Ok(dap::ThreadsResponse {
276+ threads: vec![dap::Thread {
277+ id: 1,
278+ name: "Thread 1".into(),
279+ }],
306280 })
307− .await;
281+ });
308282
309− client
310− .on_request::<Initialize, _>(move |_, _| {
311− Ok(dap::Capabilities {
312− supports_step_back: Some(false),
313− ..Default::default()
314− })
283+ client.on_request::<Initialize, _>(move |_, _| {
284+ Ok(dap::Capabilities {
285+ supports_step_back: Some(false),
286+ ..Default::default()
315287 })
316− .await;
288+ });
317289
318− client.on_request::<Launch, _>(move |_, _| Ok(())).await;
290+ client.on_request::<Launch, _>(move |_, _| Ok(()));
319291
320292 let stack_frames = vec![StackFrame {
321293 id: 1,
@@ -340,19 +312,17 @@ async fn test_fetch_variables_for_multiple_scopes( · 18 unmodified lines
340312 presentation_hint: None,
341313 }];
342314
343− client
344− .on_request::<StackTrace, _>({
345− let stack_frames = Arc::new(stack_frames.clone());
346− move |_, args| {
347− assert_eq!(1, args.thread_id);
348−
349− Ok(dap::StackTraceResponse {
350− stack_frames: (*stack_frames).clone(),
351− total_frames: None,
352− })
353− }
354− })
355− .await;
315+ client.on_request::<StackTrace, _>({
316+ let stack_frames = Arc::new(stack_frames.clone());
317+ move |_, args| {
318+ assert_eq!(1, args.thread_id);
319+
320+ Ok(dap::StackTraceResponse {
321+ stack_frames: (*stack_frames).clone(),
322+ total_frames: None,
323+ })
324+ }
325+ });
356326
357327 let scopes = vec![
358328 Scope {
@@ -383,18 +353,16 @@ async fn test_fetch_variables_for_multiple_scopes( · 24 unmodified lines
383353 },
384354 ];
385355
386− client
387− .on_request::<Scopes, _>({
388− let scopes = Arc::new(scopes.clone());
389− move |_, args| {
390− assert_eq!(1, args.frame_id);
356+ client.on_request::<Scopes, _>({
357+ let scopes = Arc::new(scopes.clone());
358+ move |_, args| {
359+ assert_eq!(1, args.frame_id);
391360
392− Ok(dap::ScopesResponse {
393− scopes: (*scopes).clone(),
394− })
395− }
396− })
397− .await;
361+ Ok(dap::ScopesResponse {
362+ scopes: (*scopes).clone(),
363+ })
364+ }
365+ });
398366
399367 let mut variables = HashMap::default();
400368 variables.insert(
@@ -445,16 +413,14 @@ async fn test_fetch_variables_for_multiple_scopes( · 44 unmodified lines
445413 }],
446414 );
447415
448− client
449− .on_request::<Variables, _>({
450− let variables = Arc::new(variables.clone());
451− move |_, args| {
452− Ok(dap::VariablesResponse {
453− variables: variables.get(&args.variables_reference).unwrap().clone(),
454− })
455− }
456− })
457− .await;
416+ client.on_request::<Variables, _>({
417+ let variables = Arc::new(variables.clone());
418+ move |_, args| {
419+ Ok(dap::VariablesResponse {
420+ variables: variables.get(&args.variables_reference).unwrap().clone(),
421+ })
422+ }
423+ });
458424
459425 client
460426 .fake_event(dap::messages::Events::Stopped(dap::StoppedEvent {
@@ -562,40 +528,28 @@ async fn test_keyboard_navigation(executor: BackgroundExecutor, cx: &mut TestApp · 101 unmodified lines
562528 })
563529 .unwrap();
564530 let cx = &mut VisualTestContext::from_window(*workspace, cx);
565−
566− let task = project.update(cx, |project, cx| {
567− project.fake_debug_session(
568− dap::DebugRequestType::Launch(LaunchConfig::default()),
569− None,
570− false,
571− cx,
572− )
573− });
574−
575− let session = task.await.unwrap();
531+ let session = debugger::test::start_debug_session(&project, cx, |_| {})
532+ .await
533+ .unwrap();
576534 let client = session.update(cx, |session, _| session.adapter_client().unwrap());
577535
578− client
579− .on_request::<dap::requests::Threads, _>(move |_, _| {
580− Ok(dap::ThreadsResponse {
581− threads: vec![dap::Thread {
582− id: 1,
583− name: "Thread 1".into(),
584− }],
585− })
536+ client.on_request::<dap::requests::Threads, _>(move |_, _| {
537+ Ok(dap::ThreadsResponse {
538+ threads: vec![dap::Thread {
539+ id: 1,
540+ name: "Thread 1".into(),
541+ }],
586542 })
587− .await;
543+ });
588544
589− client
590− .on_request::<Initialize, _>(move |_, _| {
591− Ok(dap::Capabilities {
592− supports_step_back: Some(false),
593− ..Default::default()
594− })
545+ client.on_request::<Initialize, _>(move |_, _| {
546+ Ok(dap::Capabilities {
547+ supports_step_back: Some(false),
548+ ..Default::default()
595549 })
596− .await;
550+ });
597551
598− client.on_request::<Launch, _>(move |_, _| Ok(())).await;
552+ client.on_request::<Launch, _>(move |_, _| Ok(()));
599553
600554 let stack_frames = vec![StackFrame {
601555 id: 1,
@@ -620,19 +574,17 @@ async fn test_keyboard_navigation(executor: BackgroundExecutor, cx: &mut TestApp · 18 unmodified lines
620574 presentation_hint: None,
621575 }];
622576
623− client
624− .on_request::<StackTrace, _>({
625− let stack_frames = Arc::new(stack_frames.clone());
626− move |_, args| {
627− assert_eq!(1, args.thread_id);
628−
629− Ok(dap::StackTraceResponse {
630− stack_frames: (*stack_frames).clone(),
631− total_frames: None,
632− })
633− }
634− })
635− .await;
577+ client.on_request::<StackTrace, _>({
578+ let stack_frames = Arc::new(stack_frames.clone());
579+ move |_, args| {
580+ assert_eq!(1, args.thread_id);
581+
582+ Ok(dap::StackTraceResponse {
583+ stack_frames: (*stack_frames).clone(),
584+ total_frames: None,
585+ })
586+ }
587+ });
636588
637589 let scopes = vec![
638590 Scope {
@@ -663,18 +615,16 @@ async fn test_keyboard_navigation(executor: BackgroundExecutor, cx: &mut TestApp · 24 unmodified lines
663615 },
664616 ];
665617
666− client
667− .on_request::<Scopes, _>({
668− let scopes = Arc::new(scopes.clone());
669− move |_, args| {
670− assert_eq!(1, args.frame_id);
618+ client.on_request::<Scopes, _>({
619+ let scopes = Arc::new(scopes.clone());
620+ move |_, args| {
621+ assert_eq!(1, args.frame_id);
671622
672− Ok(dap::ScopesResponse {
673− scopes: (*scopes).clone(),
674− })
675− }
676− })
677− .await;
623+ Ok(dap::ScopesResponse {
624+ scopes: (*scopes).clone(),
625+ })
626+ }
627+ });
678628
679629 let scope1_variables = vec![
680630 Variable {
@@ -748,25 +698,23 @@ async fn test_keyboard_navigation(executor: BackgroundExecutor, cx: &mut TestApp · 67 unmodified lines
748698 value_location_reference: None,
749699 }];
750700
751− client
752− .on_request::<Variables, _>({
753− let scope1_variables = Arc::new(scope1_variables.clone());
754− let nested_variables = Arc::new(nested_variables.clone());
755− let scope2_variables = Arc::new(scope2_variables.clone());
756− move |_, args| match args.variables_reference {
757− 4 => Ok(dap::VariablesResponse {
758− variables: (*scope2_variables).clone(),
759− }),
760− 3 => Ok(dap::VariablesResponse {
761− variables: (*nested_variables).clone(),
762− }),
763− 2 => Ok(dap::VariablesResponse {
764− variables: (*scope1_variables).clone(),
765− }),
766− id => unreachable!("unexpected variables reference {id}"),
767− }
768− })
769− .await;
701+ client.on_request::<Variables, _>({
702+ let scope1_variables = Arc::new(scope1_variables.clone());
703+ let nested_variables = Arc::new(nested_variables.clone());
704+ let scope2_variables = Arc::new(scope2_variables.clone());
705+ move |_, args| match args.variables_reference {
706+ 4 => Ok(dap::VariablesResponse {
707+ variables: (*scope2_variables).clone(),
708+ }),
709+ 3 => Ok(dap::VariablesResponse {
710+ variables: (*nested_variables).clone(),
711+ }),
712+ 2 => Ok(dap::VariablesResponse {
713+ variables: (*scope1_variables).clone(),
714+ }),
715+ id => unreachable!("unexpected variables reference {id}"),
716+ }
717+ });
770718
771719 client
772720 .fake_event(dap::messages::Events::Stopped(dap::StoppedEvent {
@@ -1365,39 +1313,28 @@ async fn test_variable_list_only_sends_requests_when_rendering( · 592 unmodified lines
13651313 let workspace = init_test_workspace(&project, cx).await;
13661314 let cx = &mut VisualTestContext::from_window(*workspace, cx);
13671315
1368− let task = project.update(cx, |project, cx| {
1369− project.fake_debug_session(
1370− dap::DebugRequestType::Launch(LaunchConfig::default()),
1371− None,
1372− false,
1373− cx,
1374− )
1375− });
1376−
1377− let session = task.await.unwrap();
1316+ let session = debugger::test::start_debug_session(&project, cx, |_| {})
1317+ .await
1318+ .unwrap();
13781319 let client = session.update(cx, |session, _| session.adapter_client().unwrap());
13791320
1380− client
1381− .on_request::<dap::requests::Threads, _>(move |_, _| {
1382− Ok(dap::ThreadsResponse {
1383− threads: vec![dap::Thread {
1384− id: 1,
1385− name: "Thread 1".into(),
1386− }],
1387− })
1321+ client.on_request::<dap::requests::Threads, _>(move |_, _| {
1322+ Ok(dap::ThreadsResponse {
1323+ threads: vec![dap::Thread {
1324+ id: 1,
1325+ name: "Thread 1".into(),
1326+ }],
13881327 })
1389− .await;
1328+ });
13901329
1391− client
1392− .on_request::<Initialize, _>(move |_, _| {
1393− Ok(dap::Capabilities {
1394− supports_step_back: Some(false),
1395− ..Default::default()
1396− })
1330+ client.on_request::<Initialize, _>(move |_, _| {
1331+ Ok(dap::Capabilities {
1332+ supports_step_back: Some(false),
1333+ ..Default::default()
13971334 })
1398− .await;
1335+ });
13991336
1400− client.on_request::<Launch, _>(move |_, _| Ok(())).await;
1337+ client.on_request::<Launch, _>(move |_, _| Ok(()));
14011338
14021339 let stack_frames = vec![
14031340 StackFrame {
@@ -1446,19 +1383,17 @@ async fn test_variable_list_only_sends_requests_when_rendering( · 42 unmodified lines
14461383 },
14471384 ];
14481385
1449− client
1450− .on_request::<StackTrace, _>({
1451− let stack_frames = Arc::new(stack_frames.clone());
1452− move |_, args| {
1453− assert_eq!(1, args.thread_id);
1454−
1455− Ok(dap::StackTraceResponse {
1456− stack_frames: (*stack_frames).clone(),
1457− total_frames: None,
1458− })
1459− }
1460− })
1461− .await;
1386+ client.on_request::<StackTrace, _>({
1387+ let stack_frames = Arc::new(stack_frames.clone());
1388+ move |_, args| {
1389+ assert_eq!(1, args.thread_id);
1390+
1391+ Ok(dap::StackTraceResponse {
1392+ stack_frames: (*stack_frames).clone(),
1393+ total_frames: None,
1394+ })
1395+ }
1396+ });
14621397
14631398 let frame_1_scopes = vec![Scope {
14641399 name: "Frame 1 Scope 1".into(),
@@ -1476,25 +1411,23 @@ async fn test_variable_list_only_sends_requests_when_rendering( · 11 unmodified lines
14761411
14771412 let made_scopes_request = Arc::new(AtomicBool::new(false));
14781413
1479− client
1480− .on_request::<Scopes, _>({
1481− let frame_1_scopes = Arc::new(frame_1_scopes.clone());
1482− let made_scopes_request = made_scopes_request.clone();
1483− move |_, args| {
1484− assert_eq!(1, args.frame_id);
1485− assert!(
1486− !made_scopes_request.load(Ordering::SeqCst),
1487− "We should be caching the scope request"
1488− );
1414+ client.on_request::<Scopes, _>({
1415+ let frame_1_scopes = Arc::new(frame_1_scopes.clone());
1416+ let made_scopes_request = made_scopes_request.clone();
1417+ move |_, args| {
1418+ assert_eq!(1, args.frame_id);
1419+ assert!(
1420+ !made_scopes_request.load(Ordering::SeqCst),
1421+ "We should be caching the scope request"
1422+ );
14891423
1490− made_scopes_request.store(true, Ordering::SeqCst);
1424+ made_scopes_request.store(true, Ordering::SeqCst);
14911425
1492− Ok(dap::ScopesResponse {
1493− scopes: (*frame_1_scopes).clone(),
1494− })
1495− }
1496− })
1497− .await;
1426+ Ok(dap::ScopesResponse {
1427+ scopes: (*frame_1_scopes).clone(),
1428+ })
1429+ }
1430+ });
14981431
14991432 let frame_1_variables = vec![
15001433 Variable {
@@ -1525,18 +1458,16 @@ async fn test_variable_list_only_sends_requests_when_rendering( · 24 unmodified lines
15251458 },
15261459 ];
15271460
1528− client
1529− .on_request::<Variables, _>({
1530− let frame_1_variables = Arc::new(frame_1_variables.clone());
1531− move |_, args| {
1532− assert_eq!(2, args.variables_reference);
1461+ client.on_request::<Variables, _>({
1462+ let frame_1_variables = Arc::new(frame_1_variables.clone());
1463+ move |_, args| {
1464+ assert_eq!(2, args.variables_reference);
15331465
1534− Ok(dap::VariablesResponse {
1535− variables: (*frame_1_variables).clone(),
1536− })
1537− }
1538− })
1539− .await;
1466+ Ok(dap::VariablesResponse {
1467+ variables: (*frame_1_variables).clone(),
1468+ })
1469+ }
1470+ });
15401471
15411472 cx.run_until_parked();
15421473
@@ -1629,39 +1560,28 @@ async fn test_it_fetches_scopes_variables_when_you_select_a_stack_frame( · 86 unmodified lines
16291560 .unwrap();
16301561 let cx = &mut VisualTestContext::from_window(*workspace, cx);
16311562
1632− let task = project.update(cx, |project, cx| {
1633− project.fake_debug_session(
1634− dap::DebugRequestType::Launch(LaunchConfig::default()),
1635− None,
1636− false,
1637− cx,
1638− )
1639− });
1640−
1641− let session = task.await.unwrap();
1563+ let session = debugger::test::start_debug_session(&project, cx, |_| {})
1564+ .await
1565+ .unwrap();
16421566 let client = session.update(cx, |session, _| session.adapter_client().unwrap());
16431567
1644− client
1645− .on_request::<dap::requests::Threads, _>(move |_, _| {
1646− Ok(dap::ThreadsResponse {
1647− threads: vec![dap::Thread {
1648− id: 1,
1649− name: "Thread 1".into(),
1650− }],
1651− })
1568+ client.on_request::<dap::requests::Threads, _>(move |_, _| {
1569+ Ok(dap::ThreadsResponse {
1570+ threads: vec![dap::Thread {
1571+ id: 1,
1572+ name: "Thread 1".into(),
1573+ }],
16521574 })
1653− .await;
1575+ });
16541576
1655− client
1656− .on_request::<Initialize, _>(move |_, _| {
1657− Ok(dap::Capabilities {
1658− supports_step_back: Some(false),
1659− ..Default::default()
1660− })
1577+ client.on_request::<Initialize, _>(move |_, _| {
1578+ Ok(dap::Capabilities {
1579+ supports_step_back: Some(false),
1580+ ..Default::default()
16611581 })
1662− .await;
1582+ });
16631583
1664− client.on_request::<Launch, _>(move |_, _| Ok(())).await;
1584+ client.on_request::<Launch, _>(move |_, _| Ok(()));
16651585
16661586 let stack_frames = vec![
16671587 StackFrame {
@@ -1710,19 +1630,17 @@ async fn test_it_fetches_scopes_variables_when_you_select_a_stack_frame( · 42 unmodified lines
17101630 },
17111631 ];
17121632
1713− client
1714− .on_request::<StackTrace, _>({
1715− let stack_frames = Arc::new(stack_frames.clone());
1716− move |_, args| {
1717− assert_eq!(1, args.thread_id);
1718−
1719− Ok(dap::StackTraceResponse {
1720− stack_frames: (*stack_frames).clone(),
1721− total_frames: None,
1722− })
1723− }
1724− })
1725− .await;
1633+ client.on_request::<StackTrace, _>({
1634+ let stack_frames = Arc::new(stack_frames.clone());
1635+ move |_, args| {
1636+ assert_eq!(1, args.thread_id);
1637+
1638+ Ok(dap::StackTraceResponse {
1639+ stack_frames: (*stack_frames).clone(),
1640+ total_frames: None,
1641+ })
1642+ }
1643+ });
17261644
17271645 let frame_1_scopes = vec![Scope {
17281646 name: "Frame 1 Scope 1".into(),
@@ -1757,30 +1675,28 @@ async fn test_it_fetches_scopes_variables_when_you_select_a_stack_frame( · 28 unmodified lines
17571675 let called_second_stack_frame = Arc::new(AtomicBool::new(false));
17581676 let called_first_stack_frame = Arc::new(AtomicBool::new(false));
17591677
1760− client
1761− .on_request::<Scopes, _>({
1762− let frame_1_scopes = Arc::new(frame_1_scopes.clone());
1763− let frame_2_scopes = Arc::new(frame_2_scopes.clone());
1764− let called_first_stack_frame = called_first_stack_frame.clone();
1765− let called_second_stack_frame = called_second_stack_frame.clone();
1766− move |_, args| match args.frame_id {
1767− 1 => {
1768− called_first_stack_frame.store(true, Ordering::SeqCst);
1769− Ok(dap::ScopesResponse {
1770− scopes: (*frame_1_scopes).clone(),
1771− })
1772− }
1773− 2 => {
1774− called_second_stack_frame.store(true, Ordering::SeqCst);
1775−
1776− Ok(dap::ScopesResponse {
1777− scopes: (*frame_2_scopes).clone(),
1778− })
1779− }
1780− _ => panic!("Made a scopes request with an invalid frame id"),
1678+ client.on_request::<Scopes, _>({
1679+ let frame_1_scopes = Arc::new(frame_1_scopes.clone());
1680+ let frame_2_scopes = Arc::new(frame_2_scopes.clone());
1681+ let called_first_stack_frame = called_first_stack_frame.clone();
1682+ let called_second_stack_frame = called_second_stack_frame.clone();
1683+ move |_, args| match args.frame_id {
1684+ 1 => {
1685+ called_first_stack_frame.store(true, Ordering::SeqCst);
1686+ Ok(dap::ScopesResponse {
1687+ scopes: (*frame_1_scopes).clone(),
1688+ })
17811689 }
1782− })
1783− .await;
1690+ 2 => {
1691+ called_second_stack_frame.store(true, Ordering::SeqCst);
1692+
1693+ Ok(dap::ScopesResponse {
1694+ scopes: (*frame_2_scopes).clone(),
1695+ })
1696+ }
1697+ _ => panic!("Made a scopes request with an invalid frame id"),
1698+ }
1699+ });
17841700
17851701 let frame_1_variables = vec![
17861702 Variable {
@@ -1840,18 +1756,16 @@ async fn test_it_fetches_scopes_variables_when_you_select_a_stack_frame( · 53 unmodified lines
18401756 },
18411757 ];
18421758
1843− client
1844− .on_request::<Variables, _>({
1845− let frame_1_variables = Arc::new(frame_1_variables.clone());
1846− move |_, args| {
1847− assert_eq!(2, args.variables_reference);
1759+ client.on_request::<Variables, _>({
1760+ let frame_1_variables = Arc::new(frame_1_variables.clone());
1761+ move |_, args| {
1762+ assert_eq!(2, args.variables_reference);
18481763
1849− Ok(dap::VariablesResponse {
1850− variables: (*frame_1_variables).clone(),
1851− })
1852− }
1853− })
1854− .await;
1764+ Ok(dap::VariablesResponse {
1765+ variables: (*frame_1_variables).clone(),
1766+ })
1767+ }
1768+ });
18551769
18561770 client
18571771 .fake_event(dap::messages::Events::Stopped(dap::StoppedEvent {
@@ -1907,18 +1821,16 @@ async fn test_it_fetches_scopes_variables_when_you_select_a_stack_frame( · 49 unmodified lines
19071821 assert_eq!(frame_1_variables, variables);
19081822 });
19091823
1910− client
1911− .on_request::<Variables, _>({
1912− let frame_2_variables = Arc::new(frame_2_variables.clone());
1913− move |_, args| {
1914− assert_eq!(3, args.variables_reference);
1824+ client.on_request::<Variables, _>({
1825+ let frame_2_variables = Arc::new(frame_2_variables.clone());
1826+ move |_, args| {
1827+ assert_eq!(3, args.variables_reference);
19151828
1916− Ok(dap::VariablesResponse {
1917− variables: (*frame_2_variables).clone(),
1918− })
1919− }
1920− })
1921− .await;
1829+ Ok(dap::VariablesResponse {
1830+ variables: (*frame_2_variables).clone(),
1831+ })
1832+ }
1833+ });
19221834
19231835 running_state
19241836 .update_in(cx, |running_state, window, cx| {
crates/project/src/debugger.rs+3−0
@@ -16,3 +16,6 @@ pub mod dap_command; · 15 unmodified lines
1616 pub mod dap_store;
1717 mod locator_store;
1818 pub mod session;
19+
20+#[cfg(any(feature = "test-support", test))]
21+pub mod test;
crates/project/src/debugger/dap_store.rs+36−127
@@ -3,15 +3,15 @@ use super::{ · 2 unmodified lines
33 locator_store::LocatorStore,
44 session::{self, Session, SessionStateEvent},
55 };
6−use crate::{ProjectEnvironment, debugger, worktree_store::WorktreeStore};
6+use crate::{ProjectEnvironment, debugger};
77 use anyhow::{Result, anyhow};
88 use async_trait::async_trait;
99 use collections::HashMap;
1010 use dap::{
11− Capabilities, CompletionItem, CompletionsArguments, DapRegistry, ErrorResponse,
12− EvaluateArguments, EvaluateArgumentsContext, EvaluateResponse, RunInTerminalRequestArguments,
13− Source, StartDebuggingRequestArguments,
14− adapters::{DapStatus, DebugAdapterName},
11+ Capabilities, CompletionItem, CompletionsArguments, ErrorResponse, EvaluateArguments,
12+ EvaluateArgumentsContext, EvaluateResponse, RunInTerminalRequestArguments, Source,
13+ StartDebuggingRequestArguments,
14+ adapters::{DapStatus, DebugAdapterBinary, DebugAdapterName},
1515 client::SessionId,
1616 messages::Message,
1717 requests::{Completions, Evaluate, Request as _, RunInTerminal, StartDebugging},
@@ -42,7 +42,7 @@ use std::{ · 24 unmodified lines
4242 sync::{Arc, atomic::Ordering::SeqCst},
4343 };
4444 use std::{collections::VecDeque, sync::atomic::AtomicU32};
45−use task::{DebugAdapterConfig, DebugRequestDisposition};
45+use task::DebugTaskDefinition;
4646 use util::ResultExt as _;
4747 use worktree::Worktree;
4848
@@ -78,10 +78,8 @@ pub struct LocalDapStore { · 29 unmodified lines
7878 node_runtime: NodeRuntime,
7979 next_session_id: AtomicU32,
8080 http_client: Arc<dyn HttpClient>,
81− worktree_store: Entity<WorktreeStore>,
8281 environment: Entity<ProjectEnvironment>,
8382 language_registry: Arc<LanguageRegistry>,
84− debug_adapters: Arc<DapRegistry>,
8583 toolchain_store: Arc<dyn LanguageToolchainStore>,
8684 locator_store: Arc<LocatorStore>,
8785 start_debugging_tx: futures::channel::mpsc::UnboundedSender<(SessionId, Message)>,
@@ -132,11 +130,9 @@ impl DapStore { · 44 unmodified lines
132130 node_runtime: NodeRuntime,
133131 fs: Arc<dyn Fs>,
134132 language_registry: Arc<LanguageRegistry>,
135− debug_adapters: Arc<DapRegistry>,
136133 environment: Entity<ProjectEnvironment>,
137134 toolchain_store: Arc<dyn LanguageToolchainStore>,
138135 breakpoint_store: Entity<BreakpointStore>,
139− worktree_store: Entity<WorktreeStore>,
140136 cx: &mut Context<Self>,
141137 ) -> Self {
142138 cx.on_app_quit(Self::shutdown_sessions).detach();
@@ -170,10 +166,8 @@ impl DapStore { · 27 unmodified lines
170166 environment,
171167 http_client,
172168 node_runtime,
173− worktree_store,
174169 toolchain_store,
175170 language_registry,
176− debug_adapters,
177171 start_debugging_tx,
178172 _start_debugging_task,
179173 locator_store: Arc::from(LocatorStore::new()),
@@ -320,18 +314,12 @@ impl DapStore { · 140 unmodified lines
320314 Ok(())
321315 }
322316
323− pub fn new_session(
324− &mut self,
325− mut config: DebugAdapterConfig,
326− worktree: &Entity<Worktree>,
327− parent_session: Option<Entity<Session>>,
328− cx: &mut Context<Self>,
329− ) -> (SessionId, Task<Result<Entity<Session>>>) {
317+ pub fn delegate(&self, worktree: &Entity<Worktree>, cx: &mut App) -> DapAdapterDelegate {
330318 let Some(local_store) = self.as_local() else {
331319 unimplemented!("Starting session on remote side");
332320 };
333321
334− let delegate = DapAdapterDelegate::new(
322+ DapAdapterDelegate::new(
335323 local_store.fs.clone(),
336324 worktree.read(cx).id(),
337325 local_store.node_runtime.clone(),
@@ -341,7 +329,20 @@ impl DapStore { · 3 unmodified lines
341329 local_store.environment.update(cx, |env, cx| {
342330 env.get_worktree_environment(worktree.clone(), cx)
343331 }),
344− );
332+ )
333+ }
334+
335+ pub fn new_session(
336+ &mut self,
337+ binary: DebugAdapterBinary,
338+ mut config: DebugTaskDefinition,
339+ parent_session: Option<Entity<Session>>,
340+ cx: &mut Context<Self>,
341+ ) -> (SessionId, Task<Result<Entity<Session>>>) {
342+ let Some(local_store) = self.as_local() else {
343+ unimplemented!("Starting session on remote side");
344+ };
345+
345346 let session_id = local_store.next_session_id();
346347
347348 if let Some(session) = &parent_session {
@@ -352,7 +353,6 @@ impl DapStore { · 4 unmodified lines
352353
353354 let (initialized_tx, initialized_rx) = oneshot::channel();
354355 let locator_store = local_store.locator_store.clone();
355− let debug_adapters = local_store.debug_adapters.clone();
356356
357357 let start_debugging_tx = local_store.start_debugging_tx.clone();
358358
@@ -373,86 +373,31 @@ impl DapStore { · 14 unmodified lines
373373 this.breakpoint_store.clone(),
374374 session_id,
375375 parent_session,
376− delegate,
376+ binary,
377377 config,
378378 start_debugging_tx.clone(),
379379 initialized_tx,
380− debug_adapters,
381380 cx,
382381 )
383382 })?;
384383
385− this.update(cx, |_, cx| {
386− create_new_session(session_id, initialized_rx, start_client_task, cx)
387− })?
388− .await
384+ let ret = this
385+ .update(cx, |_, cx| {
386+ create_new_session(session_id, initialized_rx, start_client_task, cx)
387+ })?
388+ .await;
389+ ret
389390 });
390391
391392 (session_id, task)
392393 }
393394
394− #[cfg(any(test, feature = "test-support"))]
395− pub fn new_fake_session(
396− &mut self,
397− config: DebugAdapterConfig,
398− worktree: &Entity<Worktree>,
399− parent_session: Option<Entity<Session>>,
400− caps: Capabilities,
401− fails: bool,
402− cx: &mut Context<Self>,
403− ) -> (SessionId, Task<Result<Entity<Session>>>) {
404− let Some(local_store) = self.as_local() else {
405− unimplemented!("Starting session on remote side");
406− };
407−
408− let delegate = DapAdapterDelegate::new(
409− local_store.fs.clone(),
410− worktree.read(cx).id(),
411− local_store.node_runtime.clone(),
412− local_store.http_client.clone(),
413− local_store.language_registry.clone(),
414− local_store.toolchain_store.clone(),
415− local_store.environment.update(cx, |env, cx| {
416− env.get_worktree_environment(worktree.clone(), cx)
417− }),
418− );
419− let session_id = local_store.next_session_id();
420−
421− if let Some(session) = &parent_session {
422− session.update(cx, |session, _| {
423− session.add_child_session_id(session_id);
424− });
425− }
426−
427− let (initialized_tx, initialized_rx) = oneshot::channel();
428−
429− let start_client_task = Session::fake(
430− self.breakpoint_store.clone(),
431− session_id,
432− parent_session,
433− delegate,
434− config,
435− local_store.start_debugging_tx.clone(),
436− initialized_tx,
437− caps,
438− fails,
439− cx,
440− );
441−
442− let task = create_new_session(session_id, initialized_rx, start_client_task, cx);
443− (session_id, task)
444− }
445−
446395 fn handle_start_debugging_request(
447396 &mut self,
448397 session_id: SessionId,
449398 request: dap::messages::Request,
450399 cx: &mut Context<Self>,
451400 ) -> Task<Result<()>> {
452− let Some(local_store) = self.as_local() else {
453− unreachable!("Cannot response for non-local session");
454− };
455−
456401 let Some(parent_session) = self.session_by_id(session_id) else {
457402 return Task::ready(Err(anyhow!("Session not found")));
458403 };
@@ -461,41 +406,12 @@ impl DapStore { · 2 unmodified lines
461406 request.arguments.unwrap_or_default(),
462407 )
463408 .expect("To parse StartDebuggingRequestArguments");
464− let worktree = local_store
465− .worktree_store
466− .update(cx, |this, _| this.worktrees().next())
467− .expect("worktree-less project");
409+ let mut binary = parent_session.read(cx).binary().clone();
410+ let config = parent_session.read(cx).configuration().unwrap().clone();
411+ binary.request_args = args;
468412
469− let Some(config) = parent_session.read(cx).configuration() else {
470− unreachable!("there must be a config for local sessions");
471− };
472−
473− let debug_config = DebugAdapterConfig {
474− label: config.label,
475− adapter: config.adapter,
476− request: DebugRequestDisposition::ReverseRequest(args),
477− initialize_args: config.initialize_args.clone(),
478− tcp_connection: config.tcp_connection.clone(),
479− locator: None,
480− stop_on_entry: config.stop_on_entry,
481− };
482−
483− #[cfg(any(test, feature = "test-support"))]
484− let new_session_task = {
485− let caps = parent_session.read(cx).capabilities.clone();
486− self.new_fake_session(
487− debug_config,
488− &worktree,
489− Some(parent_session.clone()),
490− caps,
491− false,
492− cx,
493− )
494− .1
495− };
496− #[cfg(not(any(test, feature = "test-support")))]
497413 let new_session_task = self
498− .new_session(debug_config, &worktree, Some(parent_session.clone()), cx)
414+ .new_session(binary, config, Some(parent_session.clone()), cx)
499415 .1;
500416
501417 let request_seq = request.seq;
@@ -607,13 +523,7 @@ impl DapStore { · 105 unmodified lines
607523 .map(Arc::from)
608524 .or_else(|| {
609525 self.session_by_id(session_id)
610− .and_then(|session| {
611− session
612− .read(cx)
613− .configuration()
614− .and_then(|config| config.request.cwd())
615− })
616− .map(Arc::from)
526+ .and_then(|session| session.read(cx).binary().cwd.as_deref().map(Arc::from))
617527 });
618528 cx.emit(DapStoreEvent::RunInTerminal {
619529 session_id,
@@ -852,7 +762,7 @@ fn create_new_session( · 232 unmodified lines
852762 cx.emit(DapStoreEvent::DebugClientStarted(session_id));
853763 cx.notify();
854764 })?;
855− let seq_result = {
765+ let seq_result = async || {
856766 session
857767 .update(cx, |session, cx| session.request_initialize(cx))?
858768 .await?;
@@ -863,12 +773,11 @@ fn create_new_session( · 4 unmodified lines
863773 })?
864774 .await
865775 };
866− match seq_result {
776+ match seq_result().await {
867777 Ok(_) => {}
868778 Err(error) => {
869779 this.update(cx, |this, cx| {
870780 cx.emit(DapStoreEvent::Notification(error.to_string()));
871−
872781 this.shutdown_session(session_id, cx)
873782 })?
874783 .await
crates/project/src/debugger/locator_store.rs+2−2
@@ -1,9 +1,9 @@
11 use anyhow::{Result, anyhow};
22 use cargo::CargoLocator;
33 use collections::HashMap;
4−use dap::DebugAdapterConfig;
54 use gpui::SharedString;
65 use locators::DapLocator;
6+use task::DebugTaskDefinition;
77
88 mod cargo;
99 mod locators;
@@ -23,7 +23,7 @@ impl LocatorStore { · 13 unmodified lines
2323
2424 pub(super) async fn resolve_debug_config(
2525 &self,
26− debug_config: &mut DebugAdapterConfig,
26+ debug_config: &mut DebugTaskDefinition,
2727 ) -> Result<()> {
2828 let Some(locator_name) = &debug_config.locator else {
2929 log::debug!("Attempted to resolve debug config without a locator field");
crates/project/src/debugger/locator_store/cargo.rs+3−5
@@ -1,12 +1,12 @@
11 use super::DapLocator;
22 use anyhow::{Result, anyhow};
33 use async_trait::async_trait;
4−use dap::DebugAdapterConfig;
54 use serde_json::{Value, json};
65 use smol::{
76 io::AsyncReadExt,
87 process::{Command, Stdio},
98 };
9+use task::DebugTaskDefinition;
1010 use util::maybe;
1111
1212 pub(super) struct CargoLocator;
@@ -38,11 +38,9 @@ async fn find_best_executable(executables: &[String], test_name: &str) -> Option · 25 unmodified lines
3838 }
3939 #[async_trait]
4040 impl DapLocator for CargoLocator {
41− async fn run_locator(&self, debug_config: &mut DebugAdapterConfig) -> Result<()> {
41+ async fn run_locator(&self, debug_config: &mut DebugTaskDefinition) -> Result<()> {
4242 let Some(launch_config) = (match &mut debug_config.request {
43− task::DebugRequestDisposition::UserConfigured(task::DebugRequestType::Launch(
44− launch_config,
45− )) => Some(launch_config),
43+ task::DebugRequestType::Launch(launch_config) => Some(launch_config),
4644 _ => None,
4745 }) else {
4846 return Err(anyhow!("Couldn't get launch config in locator"));
crates/project/src/debugger/locator_store/locators.rs+2−2
@@ -1,8 +1,8 @@
11 use anyhow::Result;
22 use async_trait::async_trait;
3−use dap::DebugAdapterConfig;
3+use task::DebugTaskDefinition;
44
55 #[async_trait]
66 pub(super) trait DapLocator: Send + Sync {
7− async fn run_locator(&self, debug_config: &mut DebugAdapterConfig) -> Result<()>;
7+ async fn run_locator(&self, debug_config: &mut DebugTaskDefinition) -> Result<()>;
88 }
crates/project/src/debugger/session.rs+49−298
@@ -1,5 +1,3 @@
1−use crate::project_settings::ProjectSettings;
2−
31 use super::breakpoint_store::{
42 BreakpointStore, BreakpointStoreEvent, BreakpointUpdatedReason, SourceBreakpoint,
53 };
@@ -11,22 +9,17 @@ use super::dap_command::{ · 5 unmodified lines
119 StepBackCommand, StepCommand, StepInCommand, StepOutCommand, TerminateCommand,
1210 TerminateThreadsCommand, ThreadsCommand, VariablesCommand,
1311 };
14−use super::dap_store::DapAdapterDelegate;
1512 use anyhow::{Context as _, Result, anyhow};
1613 use collections::{HashMap, HashSet, IndexMap, IndexSet};
17−use dap::adapters::{DebugAdapter, DebugAdapterBinary};
14+use dap::adapters::DebugAdapterBinary;
1815 use dap::messages::Response;
1916 use dap::{
2017 Capabilities, ContinueArguments, EvaluateArgumentsContext, Module, Source, StackFrameId,
2118 SteppingGranularity, StoppedEvent, VariableReference,
22− adapters::{DapDelegate, DapStatus},
2319 client::{DebugAdapterClient, SessionId},
2420 messages::{Events, Message},
2521 };
26−use dap::{
27− DapRegistry, DebugRequestType, ExceptionBreakpointsFilter, ExceptionFilterOptions,
28− OutputEventCategory,
29−};
22+use dap::{ExceptionBreakpointsFilter, ExceptionFilterOptions, OutputEventCategory};
3023 use futures::channel::oneshot;
3124 use futures::{FutureExt, future::Shared};
3225 use gpui::{
@@ -35,11 +28,9 @@ use gpui::{ · 2 unmodified lines
3528 };
3629 use rpc::AnyProtoClient;
3730 use serde_json::{Value, json};
38−use settings::Settings;
3931 use smol::stream::StreamExt;
4032 use std::any::TypeId;
4133 use std::collections::BTreeMap;
42−use std::path::PathBuf;
4334 use std::u64;
4435 use std::{
4536 any::Any,
@@ -48,7 +39,7 @@ use std::{ · 2 unmodified lines
4839 path::Path,
4940 sync::Arc,
5041 };
51−use task::{DebugAdapterConfig, DebugTaskDefinition};
42+use task::DebugTaskDefinition;
5243 use text::{PointUtf16, ToPointUtf16};
5344 use util::{ResultExt, merge_json_value_into};
5445
@@ -168,9 +159,9 @@ enum Mode { · 113 unmodified lines
168159 #[derive(Clone)]
169160 pub struct LocalMode {
170161 client: Arc<DebugAdapterClient>,
171− config: DebugAdapterConfig,
172− adapter: Arc<dyn DebugAdapter>,
173− breakpoint_store: Entity<BreakpointStore>,
162+ definition: DebugTaskDefinition,
163+ binary: DebugAdapterBinary,
164+ pub(crate) breakpoint_store: Entity<BreakpointStore>,
174165 tmp_breakpoint: Option<SourceBreakpoint>,
175166 }
176167
@@ -191,185 +182,37 @@ fn client_source(abs_path: &Path) -> dap::Source { · 14 unmodified lines
191182
192183 impl LocalMode {
193184 fn new(
194− debug_adapters: Arc<DapRegistry>,
195185 session_id: SessionId,
196186 parent_session: Option<Entity<Session>>,
197187 breakpoint_store: Entity<BreakpointStore>,
198− config: DebugAdapterConfig,
199− delegate: DapAdapterDelegate,
188+ config: DebugTaskDefinition,
189+ binary: DebugAdapterBinary,
200190 messages_tx: futures::channel::mpsc::UnboundedSender<Message>,
201191 cx: AsyncApp,
202192 ) -> Task<Result<Self>> {
203193 Self::new_inner(
204− debug_adapters,
205194 session_id,
206195 parent_session,
207196 breakpoint_store,
208197 config,
209− delegate,
198+ binary,
210199 messages_tx,
211200 async |_, _| {},
212201 cx,
213202 )
214203 }
215− #[cfg(any(test, feature = "test-support"))]
216− fn new_fake(
217− session_id: SessionId,
218− parent_session: Option<Entity<Session>>,
219− breakpoint_store: Entity<BreakpointStore>,
220− config: DebugAdapterConfig,
221− delegate: DapAdapterDelegate,
222− messages_tx: futures::channel::mpsc::UnboundedSender<Message>,
223− caps: Capabilities,
224− fail: bool,
225− cx: AsyncApp,
226− ) -> Task<Result<Self>> {
227− use task::DebugRequestDisposition;
228−
229− let request = match config.request.clone() {
230− DebugRequestDisposition::UserConfigured(request) => request,
231− DebugRequestDisposition::ReverseRequest(reverse_request_args) => {
232− match reverse_request_args.request {
233− dap::StartDebuggingRequestArgumentsRequest::Launch => {
234− DebugRequestType::Launch(task::LaunchConfig {
235− program: "".to_owned(),
236− cwd: None,
237− args: Default::default(),
238− })
239− }
240− dap::StartDebuggingRequestArgumentsRequest::Attach => {
241− DebugRequestType::Attach(task::AttachConfig {
242− process_id: Some(0),
243− })
244− }
245− }
246− }
247− };
248−
249− let callback = async move |session: &mut LocalMode, cx: AsyncApp| {
250− session
251− .client
252− .on_request::<dap::requests::Initialize, _>(move |_, _| Ok(caps.clone()))
253− .await;
254−
255− let paths = cx
256− .update(|cx| session.breakpoint_store.read(cx).breakpoint_paths())
257− .expect("Breakpoint store should exist in all tests that start debuggers");
258−
259− session
260− .client
261− .on_request::<dap::requests::SetBreakpoints, _>(move |_, args| {
262− let p = Arc::from(Path::new(&args.source.path.unwrap()));
263− if !paths.contains(&p) {
264− panic!("Sent breakpoints for path without any")
265− }
266204
267− Ok(dap::SetBreakpointsResponse {
268− breakpoints: Vec::default(),
269− })
270− })
271− .await;
272−
273− match request {
274− dap::DebugRequestType::Launch(_) => {
275− if fail {
276− session
277− .client
278− .on_request::<dap::requests::Launch, _>(move |_, _| {
279− Err(dap::ErrorResponse {
280− error: Some(dap::Message {
281− id: 1,
282− format: "error".into(),
283− variables: None,
284− send_telemetry: None,
285− show_user: None,
286− url: None,
287− url_label: None,
288− }),
289− })
290− })
291− .await;
292− } else {
293− session
294− .client
295− .on_request::<dap::requests::Launch, _>(move |_, _| Ok(()))
296− .await;
297− }
298− }
299− dap::DebugRequestType::Attach(attach_config) => {
300− if fail {
301− session
302− .client
303− .on_request::<dap::requests::Attach, _>(move |_, _| {
304− Err(dap::ErrorResponse {
305− error: Some(dap::Message {
306− id: 1,
307− format: "error".into(),
308− variables: None,
309− send_telemetry: None,
310− show_user: None,
311− url: None,
312− url_label: None,
313− }),
314− })
315− })
316− .await;
317− } else {
318− session
319− .client
320− .on_request::<dap::requests::Attach, _>(move |_, args| {
321− assert_eq!(
322− json!({"request": "attach", "process_id": attach_config.process_id.unwrap()}),
323− args.raw
324− );
325−
326− Ok(())
327− })
328− .await;
329− }
330− }
331− }
332−
333− session
334− .client
335− .on_request::<dap::requests::SetExceptionBreakpoints, _>(move |_, _| {
336− Ok(dap::SetExceptionBreakpointsResponse { breakpoints: None })
337− })
338− .await;
339−
340− session
341− .client
342− .on_request::<dap::requests::Disconnect, _>(move |_, _| Ok(()))
343− .await;
344− session.client.fake_event(Events::Initialized(None)).await;
345− };
346− Self::new_inner(
347− DapRegistry::fake().into(),
348− session_id,
349− parent_session,
350− breakpoint_store,
351− config,
352− delegate,
353− messages_tx,
354− callback,
355− cx,
356− )
357− }
358205 fn new_inner(
359− registry: Arc<DapRegistry>,
360206 session_id: SessionId,
361207 parent_session: Option<Entity<Session>>,
362208 breakpoint_store: Entity<BreakpointStore>,
363− config: DebugAdapterConfig,
364− delegate: DapAdapterDelegate,
209+ config: DebugTaskDefinition,
210+ binary: DebugAdapterBinary,
365211 messages_tx: futures::channel::mpsc::UnboundedSender<Message>,
366212 on_initialized: impl AsyncFnOnce(&mut LocalMode, AsyncApp) + 'static,
367213 cx: AsyncApp,
368214 ) -> Task<Result<Self>> {
369215 cx.spawn(async move |cx| {
370− let (adapter, binary) =
371− Self::get_adapter_binary(&registry, &config, &delegate, cx).await?;
372−
373216 let message_handler = Box::new(move |message| {
374217 messages_tx.unbounded_send(message).ok();
375218 });
@@ -380,13 +223,12 @@ impl LocalMode { · 4 unmodified lines
380223 .flatten()
381224 {
382225 client
383− .reconnect(session_id, binary, message_handler, cx.clone())
226+ .reconnect(session_id, binary.clone(), message_handler, cx.clone())
384227 .await?
385228 } else {
386229 DebugAdapterClient::start(
387230 session_id,
388− adapter.name(),
389− binary,
231+ binary.clone(),
390232 message_handler,
391233 cx.clone(),
392234 )
@@ -397,10 +239,10 @@ impl LocalMode { · 4 unmodified lines
397239
398240 let mut session = Self {
399241 client,
400− adapter,
401242 breakpoint_store,
402243 tmp_breakpoint: None,
403− config: config.clone(),
244+ definition: config,
245+ binary,
404246 };
405247
406248 on_initialized(&mut session, cx.clone()).await;
@@ -533,55 +375,12 @@ impl LocalMode { · 126 unmodified lines
533375 })
534376 }
535377
536− async fn get_adapter_binary(
537− registry: &Arc<DapRegistry>,
538− config: &DebugAdapterConfig,
539− delegate: &DapAdapterDelegate,
540− cx: &mut AsyncApp,
541− ) -> Result<(Arc<dyn DebugAdapter>, DebugAdapterBinary)> {
542− let adapter = registry
543− .adapter(&config.adapter)
544− .ok_or_else(|| anyhow!("Debug adapter with name `{}` was not found", config.adapter))?;
545−
546− let binary = cx.update(|cx| {
547− ProjectSettings::get_global(cx)
548− .dap
549− .get(&adapter.name())
550− .and_then(|s| s.binary.as_ref().map(PathBuf::from))
551− })?;
552−
553− let binary = match adapter.get_binary(delegate, &config, binary, cx).await {
554− Err(error) => {
555− delegate.update_status(
556− adapter.name(),
557− DapStatus::Failed {
558− error: error.to_string(),
559− },
560− );
561−
562− return Err(error);
563− }
564− Ok(mut binary) => {
565− delegate.update_status(adapter.name(), DapStatus::None);
566−
567− let shell_env = delegate.shell_env().await;
568− let mut envs = binary.envs.unwrap_or_default();
569− envs.extend(shell_env);
570− binary.envs = Some(envs);
571−
572− binary
573− }
574− };
575−
576− Ok((adapter, binary))
577− }
578−
579378 pub fn label(&self) -> String {
580− self.config.label.clone()
379+ self.definition.label.clone()
581380 }
582381
583382 fn request_initialization(&self, cx: &App) -> Task<Result<Capabilities>> {
584− let adapter_id = self.adapter.name().to_string();
383+ let adapter_id = self.binary.adapter_name.to_string();
585384
586385 self.request(Initialize { adapter_id }, cx.background_executor().clone())
587386 }
@@ -592,36 +391,26 @@ impl LocalMode { · 4 unmodified lines
592391 initialized_rx: oneshot::Receiver<()>,
593392 cx: &App,
594393 ) -> Task<Result<()>> {
595− let (mut raw, is_launch) = match &self.config.request {
596− task::DebugRequestDisposition::UserConfigured(_) => {
597− let Ok(raw) = DebugTaskDefinition::try_from(self.config.clone()) else {
598− debug_assert!(false, "This part of code should be unreachable in practice");
599− return Task::ready(Err(anyhow!(
600− "Expected debug config conversion to succeed"
601− )));
602− };
603− let is_launch = matches!(raw.request, DebugRequestType::Launch(_));
604− let raw = self.adapter.request_args(&raw);
605− (raw, is_launch)
606− }
607− task::DebugRequestDisposition::ReverseRequest(start_debugging_request_arguments) => (
608− start_debugging_request_arguments.configuration.clone(),
609− matches!(
610− start_debugging_request_arguments.request,
611− dap::StartDebuggingRequestArgumentsRequest::Launch
612− ),
613− ),
614− };
394+ let mut raw = self.binary.request_args.clone();
615395
616396 merge_json_value_into(
617− self.config.initialize_args.clone().unwrap_or(json!({})),
618− &mut raw,
397+ self.definition.initialize_args.clone().unwrap_or(json!({})),
398+ &mut raw.configuration,
619399 );
620400 // Of relevance: https://github.com/microsoft/vscode/issues/4902#issuecomment-368583522
621− let launch = if is_launch {
622− self.request(Launch { raw }, cx.background_executor().clone())
623− } else {
624− self.request(Attach { raw }, cx.background_executor().clone())
401+ let launch = match raw.request {
402+ dap::StartDebuggingRequestArgumentsRequest::Launch => self.request(
403+ Launch {
404+ raw: raw.configuration,
405+ },
406+ cx.background_executor().clone(),
407+ ),
408+ dap::StartDebuggingRequestArgumentsRequest::Attach => self.request(
409+ Attach {
410+ raw: raw.configuration,
411+ },
412+ cx.background_executor().clone(),
413+ ),
625414 };
626415
627416 let configuration_done_supported = ConfigurationDone::is_supported(capabilities);
@@ -656,12 +445,13 @@ impl LocalMode { · 28 unmodified lines
656445 })?
657446 .await
658447 .ok();
659− if configuration_done_supported {
448+ let ret = if configuration_done_supported {
660449 this.request(ConfigurationDone {}, cx.background_executor().clone())
661450 } else {
662451 Task::ready(Ok(()))
663452 }
664− .await
453+ .await;
454+ ret
665455 }
666456 });
667457
@@ -909,68 +699,22 @@ impl Session { · 241 unmodified lines
909699 breakpoint_store: Entity<BreakpointStore>,
910700 session_id: SessionId,
911701 parent_session: Option<Entity<Session>>,
912− delegate: DapAdapterDelegate,
913− config: DebugAdapterConfig,
702+ binary: DebugAdapterBinary,
703+ config: DebugTaskDefinition,
914704 start_debugging_requests_tx: futures::channel::mpsc::UnboundedSender<(SessionId, Message)>,
915705 initialized_tx: oneshot::Sender<()>,
916− debug_adapters: Arc<DapRegistry>,
917706 cx: &mut App,
918707 ) -> Task<Result<Entity<Self>>> {
919708 let (message_tx, message_rx) = futures::channel::mpsc::unbounded();
920709
921710 cx.spawn(async move |cx| {
922711 let mode = LocalMode::new(
923− debug_adapters,
924− session_id,
925− parent_session.clone(),
926− breakpoint_store.clone(),
927− config.clone(),
928− delegate,
929− message_tx,
930− cx.clone(),
931− )
932− .await?;
933−
934− cx.new(|cx| {
935− create_local_session(
936− breakpoint_store,
937− session_id,
938− parent_session,
939− start_debugging_requests_tx,
940− initialized_tx,
941− message_rx,
942− mode,
943− cx,
944− )
945− })
946− })
947− }
948−
949− #[cfg(any(test, feature = "test-support"))]
950− pub(crate) fn fake(
951− breakpoint_store: Entity<BreakpointStore>,
952− session_id: SessionId,
953− parent_session: Option<Entity<Session>>,
954− delegate: DapAdapterDelegate,
955− config: DebugAdapterConfig,
956− start_debugging_requests_tx: futures::channel::mpsc::UnboundedSender<(SessionId, Message)>,
957− initialized_tx: oneshot::Sender<()>,
958− caps: Capabilities,
959− fails: bool,
960− cx: &mut App,
961− ) -> Task<Result<Entity<Session>>> {
962− let (message_tx, message_rx) = futures::channel::mpsc::unbounded();
963−
964− cx.spawn(async move |cx| {
965− let mode = LocalMode::new_fake(
966712 session_id,
967713 parent_session.clone(),
968714 breakpoint_store.clone(),
969715 config.clone(),
970− delegate,
716+ binary,
971717 message_tx,
972− caps,
973− fails,
974718 cx.clone(),
975719 )
976720 .await?;
@@ -1047,16 +791,23 @@ impl Session { · 70 unmodified lines
1047791 &self.capabilities
1048792 }
1049793
794+ pub fn binary(&self) -> &DebugAdapterBinary {
795+ let Mode::Local(local_mode) = &self.mode else {
796+ panic!("Session is not local");
797+ };
798+ &local_mode.binary
799+ }
800+
1050801 pub fn adapter_name(&self) -> SharedString {
1051802 match &self.mode {
1052− Mode::Local(local_mode) => local_mode.adapter.name().into(),
803+ Mode::Local(local_mode) => local_mode.definition.adapter.clone().into(),
1053804 Mode::Remote(remote_mode) => remote_mode._adapter_name.clone(),
1054805 }
1055806 }
1056807
1057− pub fn configuration(&self) -> Option<DebugAdapterConfig> {
808+ pub fn configuration(&self) -> Option<DebugTaskDefinition> {
1058809 if let Mode::Local(local_mode) = &self.mode {
1059− Some(local_mode.config.clone())
810+ Some(local_mode.definition.clone())
1060811 } else {
1061812 None
1062813 }
crates/project/src/debugger/test.rs+98−0
@@ -0,0 +1,98 @@
1+use std::{path::Path, sync::Arc};
2+
3+use anyhow::Result;
4+use dap::{DebugRequestType, client::DebugAdapterClient};
5+use gpui::{App, AppContext, Entity, Subscription, Task};
6+use task::DebugTaskDefinition;
7+
8+use crate::Project;
9+
10+use super::session::Session;
11+
12+pub 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+
31+pub 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+
46+pub 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+
67+fn 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+}
crates/project/src/project.rs+32−51
@@ -25,6 +25,7 @@ mod environment; · 24 unmodified lines
2525 use buffer_diff::BufferDiff;
2626 pub use environment::{EnvironmentErrorMessage, ProjectEnvironmentEvent};
2727 use git_store::{Repository, RepositoryId};
28+use task::DebugTaskDefinition;
2829 pub mod search_history;
2930 mod yarn;
3031
@@ -38,7 +39,7 @@ use client::{ · 7 unmodified lines
3839 };
3940 use clock::ReplicaId;
4041
41−use dap::{DapRegistry, DebugAdapterConfig, client::DebugAdapterClient};
42+use dap::{DapRegistry, client::DebugAdapterClient};
4243
4344 use collections::{BTreeSet, HashMap, HashSet};
4445 use debounced_delay::DebouncedDelay;
@@ -106,7 +107,7 @@ use terminals::Terminals; · 61 unmodified lines
106107 use text::{Anchor, BufferId};
107108 use toolchain_store::EmptyToolchainStore;
108109 use util::{
109− ResultExt as _, maybe,
110+ ResultExt as _,
110111 paths::{SanitizedPath, compare_paths},
111112 };
112113 use worktree::{CreatedEntry, Snapshot, Traversal};
@@ -870,11 +871,9 @@ impl Project { · 757 unmodified lines
870871 node.clone(),
871872 fs.clone(),
872873 languages.clone(),
873− debug_adapters.clone(),
874874 environment.clone(),
875875 toolchain_store.read(cx).as_language_toolchain_store(),
876876 breakpoint_store.clone(),
877− worktree_store.clone(),
878877 cx,
879878 )
880879 });
@@ -1458,64 +1457,46 @@ impl Project { · 577 unmodified lines
14581457 }
14591458 }
14601459
1461− pub fn queue_debug_session(&mut self, config: DebugAdapterConfig, cx: &mut Context<Self>) {
1462− if config.locator.is_none() {
1463− self.start_debug_session(config, cx).detach_and_log_err(cx);
1464− }
1465− }
1466−
14671460 pub fn start_debug_session(
14681461 &mut self,
1469− config: DebugAdapterConfig,
1462+ config: DebugTaskDefinition,
14701463 cx: &mut Context<Self>,
14711464 ) -> Task<Result<Entity<Session>>> {
1472− let worktree = maybe!({ self.worktrees(cx).next() });
1473−
1474− let Some(worktree) = &worktree else {
1465+ let Some(worktree) = self.worktrees(cx).next() else {
14751466 return Task::ready(Err(anyhow!("Failed to find a worktree")));
14761467 };
14771468
1478− self.dap_store
1479− .update(cx, |dap_store, cx| {
1480− dap_store.new_session(config, worktree, None, cx)
1481− })
1482− .1
1483− }
1469+ let Some(adapter) = self.debug_adapters.adapter(&config.adapter) else {
1470+ return Task::ready(Err(anyhow!("Failed to find a debug adapter")));
1471+ };
14841472
1485− #[cfg(any(test, feature = "test-support"))]
1486− pub fn fake_debug_session(
1487− &mut self,
1488− request: task::DebugRequestType,
1489− caps: Option<dap::Capabilities>,
1490− fails: bool,
1491− cx: &mut Context<Self>,
1492− ) -> Task<Result<Entity<Session>>> {
1493− use dap::{Capabilities, FakeAdapter};
1494− use task::DebugRequestDisposition;
1473+ let user_installed_path = ProjectSettings::get_global(cx)
1474+ .dap
1475+ .get(&adapter.name())
1476+ .and_then(|s| s.binary.as_ref().map(PathBuf::from));
14951477
1496− let worktree = maybe!({ self.worktrees(cx).next() });
1478+ let result = cx.spawn(async move |this, cx| {
1479+ let delegate = this.update(cx, |project, cx| {
1480+ project
1481+ .dap_store
1482+ .update(cx, |dap_store, cx| dap_store.delegate(&worktree, cx))
1483+ })?;
14971484
1498− let Some(worktree) = &worktree else {
1499− return Task::ready(Err(anyhow!("Failed to find a worktree")));
1500− };
1501− let config = DebugAdapterConfig {
1502− label: "test config".into(),
1503− adapter: FakeAdapter::ADAPTER_NAME.into(),
1504− request: DebugRequestDisposition::UserConfigured(request),
1505− initialize_args: None,
1506− tcp_connection: None,
1507− locator: None,
1508− stop_on_entry: None,
1509− };
1510− let caps = caps.unwrap_or(Capabilities {
1511− supports_step_back: Some(false),
1512− ..Default::default()
1485+ let binary = adapter
1486+ .get_binary(&delegate, &config, user_installed_path, cx)
1487+ .await?;
1488+
1489+ let ret = this
1490+ .update(cx, |project, cx| {
1491+ project.dap_store.update(cx, |dap_store, cx| {
1492+ dap_store.new_session(binary, config, None, cx)
1493+ })
1494+ })?
1495+ .1
1496+ .await;
1497+ ret
15131498 });
1514− self.dap_store
1515− .update(cx, |dap_store, cx| {
1516− dap_store.new_fake_session(config, worktree, None, caps, fails, cx)
1517− })
1518− .1
1499+ result
15191500 }
15201501
15211502 #[cfg(any(test, feature = "test-support"))]
crates/project/src/project_tests.rs+1−1
@@ -39,7 +39,7 @@ use std::{env, mem, num::NonZeroU32, ops::Range, str::FromStr, sync::OnceLock, t · 38 unmodified lines
3939 use task::{ResolvedTask, TaskContext};
4040 use unindent::Unindent as _;
4141 use util::{
42− TryFutureExt as _, assert_set_eq, path,
42+ TryFutureExt as _, assert_set_eq, maybe, path,
4343 paths::PathMatcher,
4444 separator,
4545 test::{TempTree, marked_text_offsets},
crates/remote_server/src/headless_project.rs+1−3
@@ -72,7 +72,7 @@ impl HeadlessProject { · 71 unmodified lines
7272 http_client,
7373 node_runtime,
7474 languages,
75− debug_adapters,
75+ debug_adapters: _debug_adapters,
7676 extension_host_proxy: proxy,
7777 }: HeadlessAppState,
7878 cx: &mut Context<Self>,
@@ -112,11 +112,9 @@ impl HeadlessProject { · 33 unmodified lines
112112 node_runtime.clone(),
113113 fs.clone(),
114114 languages.clone(),
115− debug_adapters.clone(),
116115 environment.clone(),
117116 toolchain_store.read(cx).as_language_toolchain_store(),
118117 breakpoint_store.clone(),
119− worktree_store.clone(),
120118 cx,
121119 )
122120 });
crates/task/src/lib.rs+4−4
@@ -104,7 +104,7 @@ impl ResolvedTask { · 103 unmodified lines
104104 }
105105
106106 /// Get the configuration for the debug adapter that should be used for this task.
107− pub fn resolved_debug_adapter_config(&self) -> Option<DebugAdapterConfig> {
107+ pub fn resolved_debug_adapter_config(&self) -> Option<DebugTaskDefinition> {
108108 match self.original_task.task_type.clone() {
109109 TaskType::Debug(debug_args) if self.resolved.is_some() => {
110110 let resolved = self
@@ -127,10 +127,10 @@ impl ResolvedTask { · 16 unmodified lines
127127 })
128128 .collect();
129129
130− Some(DebugAdapterConfig {
130+ Some(DebugTaskDefinition {
131131 label: resolved.label.clone(),
132132 adapter: debug_args.adapter.clone(),
133− request: DebugRequestDisposition::UserConfigured(match debug_args.request {
133+ request: match debug_args.request {
134134 crate::task_template::DebugArgsRequest::Launch => {
135135 DebugRequestType::Launch(LaunchConfig {
136136 program: resolved.command.clone(),
@@ -141,7 +141,7 @@ impl ResolvedTask { · 4 unmodified lines
141141 crate::task_template::DebugArgsRequest::Attach(attach_config) => {
142142 DebugRequestType::Attach(attach_config)
143143 }
144− }),
144+ },
145145 initialize_args: debug_args.initialize_args,
146146 tcp_connection: debug_args.tcp_connection,
147147 locator: debug_args.locator.clone(),
crates/tasks_ui/src/modal.rs+3−4
@@ -361,9 +361,8 @@ impl PickerDelegate for TasksModalDelegate { · 360 unmodified lines
361361
362362 match task.task_type() {
363363 TaskType::Debug(config) if config.locator.is_none() => {
364− let Some(config): Option<DebugTaskDefinition> = task
365− .resolved_debug_adapter_config()
366− .and_then(|config| config.try_into().ok())
364+ let Some(config): Option<DebugTaskDefinition> =
365+ task.resolved_debug_adapter_config()
367366 else {
368367 return;
369368 };
@@ -382,7 +381,7 @@ impl PickerDelegate for TasksModalDelegate { · 12 unmodified lines
382381 .update(cx, |workspace, cx| {
383382 workspace.project().update(cx, |project, cx| {
384383 project
385− .start_debug_session(config.into(), cx)
384+ .start_debug_session(config, cx)
386385 .detach_and_log_err(cx);
387386 });
388387 })
crates/workspace/src/workspace.rs+2−2
@@ -96,7 +96,7 @@ use std::{ · 95 unmodified lines
9696 sync::{Arc, LazyLock, Weak, atomic::AtomicUsize},
9797 time::Duration,
9898 };
99−use task::{DebugAdapterConfig, SpawnInTerminal, TaskId};
99+use task::{DebugTaskDefinition, SpawnInTerminal, TaskId};
100100 use theme::{ActiveTheme, SystemAppearance, ThemeSettings};
101101 pub use toolbar::{Toolbar, ToolbarItemEvent, ToolbarItemLocation, ToolbarItemView};
102102 pub use ui;
@@ -858,7 +858,7 @@ pub struct Workspace { · 755 unmodified lines
858858 serialized_ssh_project: Option<SerializedSshProject>,
859859 _items_serializer: Task<Result<()>>,
860860 session_id: Option<String>,
861− debug_task_queue: HashMap<task::TaskId, DebugAdapterConfig>,
861+ debug_task_queue: HashMap<task::TaskId, DebugTaskDefinition>,
862862 }
863863
864864 impl EventEmitter<Event> for Workspace {}