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 ---------
Unified · Split
| @@ -3,13 +3,13 @@ use anyhow::{Context as _, Ok, Result, anyhow}; · 2 unmodified lines | |||
| 3 | use async_compression::futures::bufread::GzipDecoder; | 3 | use async_compression::futures::bufread::GzipDecoder; |
| 4 | use async_tar::Archive; | 4 | use async_tar::Archive; |
| 5 | use async_trait::async_trait; | 5 | use async_trait::async_trait; |
| 6 | use dap_types::StartDebuggingRequestArguments; | ||
| 6 | use futures::io::BufReader; | 7 | use futures::io::BufReader; |
| 7 | use gpui::{AsyncApp, SharedString}; | 8 | use gpui::{AsyncApp, SharedString}; |
| 8 | pub use http_client::{HttpClient, github::latest_github_release}; | 9 | pub use http_client::{HttpClient, github::latest_github_release}; |
| 9 | use language::LanguageToolchainStore; | 10 | use language::LanguageToolchainStore; |
| 10 | use node_runtime::NodeRuntime; | 11 | use node_runtime::NodeRuntime; |
| 11 | use serde::{Deserialize, Serialize}; | 12 | use serde::{Deserialize, Serialize}; |
| 12 | use serde_json::Value; | ||
| 13 | use settings::WorktreeId; | 13 | use settings::WorktreeId; |
| 14 | use smol::{self, fs::File, lock::Mutex}; | 14 | use smol::{self, fs::File, lock::Mutex}; |
| 15 | use std::{ | 15 | use std::{ |
| @@ -22,7 +22,7 @@ use std::{ · 6 unmodified lines | |||
| 22 | path::PathBuf, | 22 | path::PathBuf, |
| 23 | sync::Arc, | 23 | sync::Arc, |
| 24 | }; | 24 | }; |
| 25 | use task::{DebugAdapterConfig, DebugTaskDefinition}; | 25 | use task::DebugTaskDefinition; |
| 26 | use util::ResultExt; | 26 | use util::ResultExt; |
| 27 | 27 | ||
| 28 | #[derive(Clone, Debug, PartialEq, Eq)] | 28 | #[derive(Clone, Debug, PartialEq, Eq)] |
| @@ -93,13 +93,15 @@ pub struct TcpArguments { · 64 unmodified lines | |||
| 93 | pub port: u16, | 93 | pub port: u16, |
| 94 | pub timeout: Option<u64>, | 94 | pub timeout: Option<u64>, |
| 95 | } | 95 | } |
| 96 | #[derive(Default, Debug, Clone)] | 96 | #[derive(Debug, Clone)] |
| 97 | pub struct DebugAdapterBinary { | 97 | pub struct DebugAdapterBinary { |
| 98 | pub adapter_name: DebugAdapterName, | ||
| 98 | pub command: String, | 99 | pub command: String, |
| 99 | pub arguments: Option<Vec<OsString>>, | 100 | pub arguments: Option<Vec<OsString>>, |
| 100 | pub envs: Option<HashMap<String, String>>, | 101 | pub envs: Option<HashMap<String, String>>, |
| 101 | pub cwd: Option<PathBuf>, | 102 | pub cwd: Option<PathBuf>, |
| 102 | pub connection: Option<TcpArguments>, | 103 | pub connection: Option<TcpArguments>, |
| 104 | pub request_args: StartDebuggingRequestArguments, | ||
| 103 | } | 105 | } |
| 104 | 106 | ||
| 105 | #[derive(Debug)] | 107 | #[derive(Debug)] |
| @@ -220,7 +222,7 @@ pub trait DebugAdapter: 'static + Send + Sync { · 114 unmodified lines | |||
| 220 | async fn get_binary( | 222 | async fn get_binary( |
| 221 | &self, | 223 | &self, |
| 222 | delegate: &dyn DapDelegate, | 224 | delegate: &dyn DapDelegate, |
| 223 | config: &DebugAdapterConfig, | 225 | config: &DebugTaskDefinition, |
| 224 | user_installed_path: Option<PathBuf>, | 226 | user_installed_path: Option<PathBuf>, |
| 225 | cx: &mut AsyncApp, | 227 | cx: &mut AsyncApp, |
| 226 | ) -> Result<DebugAdapterBinary> { | 228 | ) -> Result<DebugAdapterBinary> { |
| @@ -284,13 +286,10 @@ pub trait DebugAdapter: 'static + Send + Sync { · 57 unmodified lines | |||
| 284 | async fn get_installed_binary( | 286 | async fn get_installed_binary( |
| 285 | &self, | 287 | &self, |
| 286 | delegate: &dyn DapDelegate, | 288 | delegate: &dyn DapDelegate, |
| 287 | config: &DebugAdapterConfig, | 289 | config: &DebugTaskDefinition, |
| 288 | user_installed_path: Option<PathBuf>, | 290 | user_installed_path: Option<PathBuf>, |
| 289 | cx: &mut AsyncApp, | 291 | cx: &mut AsyncApp, |
| 290 | ) -> Result<DebugAdapterBinary>; | 292 | ) -> Result<DebugAdapterBinary>; |
| 291 | |||
| 292 | /// Should return base configuration to make the debug adapter work | ||
| 293 | fn request_args(&self, config: &DebugTaskDefinition) -> Value; | ||
| 294 | } | 293 | } |
| 295 | #[cfg(any(test, feature = "test-support"))] | 294 | #[cfg(any(test, feature = "test-support"))] |
| 296 | pub struct FakeAdapter {} | 295 | pub struct FakeAdapter {} |
| @@ -302,6 +301,31 @@ impl FakeAdapter { · 5 unmodified lines | |||
| 302 | pub fn new() -> Self { | 301 | pub fn new() -> Self { |
| 303 | Self {} | 302 | Self {} |
| 304 | } | 303 | } |
| 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 | } | ||
| 305 | } | 329 | } |
| 306 | 330 | ||
| 307 | #[cfg(any(test, feature = "test-support"))] | 331 | #[cfg(any(test, feature = "test-support"))] |
| @@ -314,16 +338,18 @@ impl DebugAdapter for FakeAdapter { · 6 unmodified lines | |||
| 314 | async fn get_binary( | 338 | async fn get_binary( |
| 315 | &self, | 339 | &self, |
| 316 | _: &dyn DapDelegate, | 340 | _: &dyn DapDelegate, |
| 317 | _: &DebugAdapterConfig, | 341 | config: &DebugTaskDefinition, |
| 318 | _: Option<PathBuf>, | 342 | _: Option<PathBuf>, |
| 319 | _: &mut AsyncApp, | 343 | _: &mut AsyncApp, |
| 320 | ) -> Result<DebugAdapterBinary> { | 344 | ) -> Result<DebugAdapterBinary> { |
| 321 | Ok(DebugAdapterBinary { | 345 | Ok(DebugAdapterBinary { |
| 346 | adapter_name: Self::ADAPTER_NAME.into(), | ||
| 322 | command: "command".into(), | 347 | command: "command".into(), |
| 323 | arguments: None, | 348 | arguments: None, |
| 324 | connection: None, | 349 | connection: None, |
| 325 | envs: None, | 350 | envs: None, |
| 326 | cwd: None, | 351 | cwd: None, |
| 352 | request_args: self.request_args(config), | ||
| 327 | }) | 353 | }) |
| 328 | } | 354 | } |
| 329 | 355 | ||
| @@ -345,27 +371,10 @@ impl DebugAdapter for FakeAdapter { · 15 unmodified lines | |||
| 345 | async fn get_installed_binary( | 371 | async fn get_installed_binary( |
| 346 | &self, | 372 | &self, |
| 347 | _: &dyn DapDelegate, | 373 | _: &dyn DapDelegate, |
| 348 | _: &DebugAdapterConfig, | 374 | _: &DebugTaskDefinition, |
| 349 | _: Option<PathBuf>, | 375 | _: Option<PathBuf>, |
| 350 | _: &mut AsyncApp, | 376 | _: &mut AsyncApp, |
| 351 | ) -> Result<DebugAdapterBinary> { | 377 | ) -> Result<DebugAdapterBinary> { |
| 352 | unimplemented!("get installed binary"); | 378 | unimplemented!("get installed binary"); |
| 353 | } | 379 | } |
| 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 | } | ||
| 371 | } | 380 | } |
| @@ -39,7 +39,6 @@ impl SessionId { · 38 unmodified lines | |||
| 39 | /// Represents a connection to the debug adapter process, either via stdout/stdin or a socket. | 39 | /// Represents a connection to the debug adapter process, either via stdout/stdin or a socket. |
| 40 | pub struct DebugAdapterClient { | 40 | pub struct DebugAdapterClient { |
| 41 | id: SessionId, | 41 | id: SessionId, |
| 42 | name: DebugAdapterName, | ||
| 43 | sequence_count: AtomicU64, | 42 | sequence_count: AtomicU64, |
| 44 | binary: DebugAdapterBinary, | 43 | binary: DebugAdapterBinary, |
| 45 | executor: BackgroundExecutor, | 44 | executor: BackgroundExecutor, |
| @@ -51,7 +50,6 @@ pub type DapMessageHandler = Box<dyn FnMut(Message) + 'static + Send + Sync>; · 5 unmodified lines | |||
| 51 | impl DebugAdapterClient { | 50 | impl DebugAdapterClient { |
| 52 | pub async fn start( | 51 | pub async fn start( |
| 53 | id: SessionId, | 52 | id: SessionId, |
| 54 | name: DebugAdapterName, | ||
| 55 | binary: DebugAdapterBinary, | 53 | binary: DebugAdapterBinary, |
| 56 | message_handler: DapMessageHandler, | 54 | message_handler: DapMessageHandler, |
| 57 | cx: AsyncApp, | 55 | cx: AsyncApp, |
| @@ -60,7 +58,6 @@ impl DebugAdapterClient { · 2 unmodified lines | |||
| 60 | TransportDelegate::start(&binary, cx.clone()).await?; | 58 | TransportDelegate::start(&binary, cx.clone()).await?; |
| 61 | let this = Self { | 59 | let this = Self { |
| 62 | id, | 60 | id, |
| 63 | name, | ||
| 64 | binary, | 61 | binary, |
| 65 | transport_delegate, | 62 | transport_delegate, |
| 66 | sequence_count: AtomicU64::new(1), | 63 | sequence_count: AtomicU64::new(1), |
| @@ -91,6 +88,7 @@ impl DebugAdapterClient { · 24 unmodified lines | |||
| 91 | ) -> Result<Self> { | 88 | ) -> Result<Self> { |
| 92 | let binary = match self.transport_delegate.transport() { | 89 | let binary = match self.transport_delegate.transport() { |
| 93 | crate::transport::Transport::Tcp(tcp_transport) => DebugAdapterBinary { | 90 | crate::transport::Transport::Tcp(tcp_transport) => DebugAdapterBinary { |
| 91 | adapter_name: binary.adapter_name, | ||
| 94 | command: binary.command, | 92 | command: binary.command, |
| 95 | arguments: binary.arguments, | 93 | arguments: binary.arguments, |
| 96 | envs: binary.envs, | 94 | envs: binary.envs, |
| @@ -100,11 +98,12 @@ impl DebugAdapterClient { · 3 unmodified lines | |||
| 100 | port: tcp_transport.port, | 98 | port: tcp_transport.port, |
| 101 | timeout: Some(tcp_transport.timeout), | 99 | timeout: Some(tcp_transport.timeout), |
| 102 | }), | 100 | }), |
| 101 | request_args: binary.request_args, | ||
| 103 | }, | 102 | }, |
| 104 | _ => self.binary.clone(), | 103 | _ => self.binary.clone(), |
| 105 | }; | 104 | }; |
| 106 | 105 | ||
| 107 | Self::start(session_id, self.name(), binary, message_handler, cx).await | 106 | Self::start(session_id, binary, message_handler, cx).await |
| 108 | } | 107 | } |
| 109 | 108 | ||
| 110 | async fn handle_receive_messages( | 109 | async fn handle_receive_messages( |
| @@ -189,7 +188,17 @@ impl DebugAdapterClient { · 78 unmodified lines | |||
| 189 | 188 | ||
| 190 | let response = response??; | 189 | let response = response??; |
| 191 | match response.success { | 190 | 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 | } | ||
| 193 | false => Err(anyhow!("Request failed: {}", response.message.unwrap_or_default())), | 202 | false => Err(anyhow!("Request failed: {}", response.message.unwrap_or_default())), |
| 194 | } | 203 | } |
| 195 | } | 204 | } |
| @@ -211,7 +220,7 @@ impl DebugAdapterClient { · 15 unmodified lines | |||
| 211 | } | 220 | } |
| 212 | 221 | ||
| 213 | pub fn name(&self) -> DebugAdapterName { | 222 | pub fn name(&self) -> DebugAdapterName { |
| 214 | self.name.clone() | 223 | self.binary.adapter_name.clone() |
| 215 | } | 224 | } |
| 216 | pub fn binary(&self) -> &DebugAdapterBinary { | 225 | pub fn binary(&self) -> &DebugAdapterBinary { |
| 217 | &self.binary | 226 | &self.binary |
| @@ -238,14 +247,14 @@ impl DebugAdapterClient { · 20 unmodified lines | |||
| 238 | } | 247 | } |
| 239 | 248 | ||
| 240 | #[cfg(any(test, feature = "test-support"))] | 249 | #[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) |
| 242 | where | 251 | where |
| 243 | F: 'static | 252 | F: 'static |
| 244 | + Send | 253 | + Send |
| 245 | + FnMut(u64, R::Arguments) -> Result<R::Response, dap_types::ErrorResponse>, | 254 | + FnMut(u64, R::Arguments) -> Result<R::Response, dap_types::ErrorResponse>, |
| 246 | { | 255 | { |
| 247 | let transport = self.transport_delegate.transport().as_fake(); | 256 | let transport = self.transport_delegate.transport().as_fake(); |
| 248 | transport.on_request::<R, F>(handler).await; | 257 | transport.on_request::<R, F>(handler); |
| 249 | } | 258 | } |
| 250 | 259 | ||
| 251 | #[cfg(any(test, feature = "test-support"))] | 260 | #[cfg(any(test, feature = "test-support"))] |
| @@ -282,7 +291,7 @@ mod tests { · 30 unmodified lines | |||
| 282 | use crate::{client::DebugAdapterClient, debugger_settings::DebuggerSettings}; | 291 | use crate::{client::DebugAdapterClient, debugger_settings::DebuggerSettings}; |
| 283 | use dap_types::{ | 292 | use dap_types::{ |
| 284 | Capabilities, InitializeRequestArguments, InitializeRequestArgumentsPathFormat, | 293 | Capabilities, InitializeRequestArguments, InitializeRequestArgumentsPathFormat, |
| 285 | RunInTerminalRequestArguments, | 294 | RunInTerminalRequestArguments, StartDebuggingRequestArguments, |
| 286 | messages::Events, | 295 | messages::Events, |
| 287 | requests::{Initialize, Request, RunInTerminal}, | 296 | requests::{Initialize, Request, RunInTerminal}, |
| 288 | }; | 297 | }; |
| @@ -312,13 +321,17 @@ mod tests { · 23 unmodified lines | |||
| 312 | 321 | ||
| 313 | let client = DebugAdapterClient::start( | 322 | let client = DebugAdapterClient::start( |
| 314 | crate::client::SessionId(1), | 323 | crate::client::SessionId(1), |
| 315 | DebugAdapterName("adapter".into()), | ||
| 316 | DebugAdapterBinary { | 324 | DebugAdapterBinary { |
| 325 | adapter_name: "adapter".into(), | ||
| 317 | command: "command".into(), | 326 | command: "command".into(), |
| 318 | arguments: Default::default(), | 327 | arguments: Default::default(), |
| 319 | envs: Default::default(), | 328 | envs: Default::default(), |
| 320 | connection: None, | 329 | connection: None, |
| 321 | cwd: None, | 330 | cwd: None, |
| 331 | request_args: StartDebuggingRequestArguments { | ||
| 332 | configuration: serde_json::Value::Null, | ||
| 333 | request: dap_types::StartDebuggingRequestArgumentsRequest::Launch, | ||
| 334 | }, | ||
| 322 | }, | 335 | }, |
| 323 | Box::new(|_| panic!("Did not expect to hit this code path")), | 336 | Box::new(|_| panic!("Did not expect to hit this code path")), |
| 324 | cx.to_async(), | 337 | cx.to_async(), |
| @@ -326,14 +339,12 @@ mod tests { · 1 unmodified line | |||
| 326 | .await | 339 | .await |
| 327 | .unwrap(); | 340 | .unwrap(); |
| 328 | 341 | ||
| 329 | client | 342 | client.on_request::<Initialize, _>(move |_, _| { |
| 330 | .on_request::<Initialize, _>(move |_, _| { | 343 | Ok(dap_types::Capabilities { |
| 331 | Ok(dap_types::Capabilities { | 344 | supports_configuration_done_request: Some(true), |
| 332 | supports_configuration_done_request: Some(true), | 345 | ..Default::default() |
| 333 | ..Default::default() | ||
| 334 | }) | ||
| 335 | }) | 346 | }) |
| 336 | .await; | 347 | }); |
| 337 | 348 | ||
| 338 | cx.run_until_parked(); | 349 | cx.run_until_parked(); |
| 339 | 350 | ||
| @@ -381,13 +392,17 @@ mod tests { · 41 unmodified lines | |||
| 381 | 392 | ||
| 382 | let client = DebugAdapterClient::start( | 393 | let client = DebugAdapterClient::start( |
| 383 | crate::client::SessionId(1), | 394 | crate::client::SessionId(1), |
| 384 | DebugAdapterName("adapter".into()), | ||
| 385 | DebugAdapterBinary { | 395 | DebugAdapterBinary { |
| 396 | adapter_name: "adapter".into(), | ||
| 386 | command: "command".into(), | 397 | command: "command".into(), |
| 387 | arguments: Default::default(), | 398 | arguments: Default::default(), |
| 388 | envs: Default::default(), | 399 | envs: Default::default(), |
| 389 | connection: None, | 400 | connection: None, |
| 390 | cwd: None, | 401 | cwd: None, |
| 402 | request_args: StartDebuggingRequestArguments { | ||
| 403 | configuration: serde_json::Value::Null, | ||
| 404 | request: dap_types::StartDebuggingRequestArgumentsRequest::Launch, | ||
| 405 | }, | ||
| 391 | }, | 406 | }, |
| 392 | Box::new({ | 407 | Box::new({ |
| 393 | let called_event_handler = called_event_handler.clone(); | 408 | let called_event_handler = called_event_handler.clone(); |
| @@ -431,13 +446,17 @@ mod tests { · 37 unmodified lines | |||
| 431 | 446 | ||
| 432 | let client = DebugAdapterClient::start( | 447 | let client = DebugAdapterClient::start( |
| 433 | crate::client::SessionId(1), | 448 | crate::client::SessionId(1), |
| 434 | DebugAdapterName("test-adapter".into()), | ||
| 435 | DebugAdapterBinary { | 449 | DebugAdapterBinary { |
| 450 | adapter_name: "test-adapter".into(), | ||
| 436 | command: "command".into(), | 451 | command: "command".into(), |
| 437 | arguments: Default::default(), | 452 | arguments: Default::default(), |
| 438 | envs: Default::default(), | 453 | envs: Default::default(), |
| 439 | connection: None, | 454 | connection: None, |
| 440 | cwd: None, | 455 | cwd: None, |
| 456 | request_args: dap_types::StartDebuggingRequestArguments { | ||
| 457 | configuration: serde_json::Value::Null, | ||
| 458 | request: dap_types::StartDebuggingRequestArgumentsRequest::Launch, | ||
| 459 | }, | ||
| 441 | }, | 460 | }, |
| 442 | Box::new({ | 461 | Box::new({ |
| 443 | let called_event_handler = called_event_handler.clone(); | 462 | let called_event_handler = called_event_handler.clone(); |
| @@ -699,14 +699,8 @@ impl StdioTransport { · 698 unmodified lines | |||
| 699 | } | 699 | } |
| 700 | 700 | ||
| 701 | #[cfg(any(test, feature = "test-support"))] | 701 | #[cfg(any(test, feature = "test-support"))] |
| 702 | type RequestHandler = Box< | 702 | type RequestHandler = |
| 703 | dyn Send | 703 | Box<dyn Send + FnMut(u64, serde_json::Value) -> dap_types::messages::Response>; |
| 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 | >; | ||
| 710 | 704 | ||
| 711 | #[cfg(any(test, feature = "test-support"))] | 705 | #[cfg(any(test, feature = "test-support"))] |
| 712 | type ResponseHandler = Box<dyn Send + Fn(Response)>; | 706 | type ResponseHandler = Box<dyn Send + Fn(Response)>; |
| @@ -714,45 +708,41 @@ type ResponseHandler = Box<dyn Send + Fn(Response)>; · 1 unmodified line | |||
| 714 | #[cfg(any(test, feature = "test-support"))] | 708 | #[cfg(any(test, feature = "test-support"))] |
| 715 | pub struct FakeTransport { | 709 | pub struct FakeTransport { |
| 716 | // for sending fake response back from adapter side | 710 | // 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>>>, |
| 718 | // for reverse request responses | 712 | // for reverse request responses |
| 719 | response_handlers: Arc<Mutex<HashMap<&'static str, ResponseHandler>>>, | 713 | response_handlers: Arc<parking_lot::Mutex<HashMap<&'static str, ResponseHandler>>>, |
| 720 | } | 714 | } |
| 721 | 715 | ||
| 722 | #[cfg(any(test, feature = "test-support"))] | 716 | #[cfg(any(test, feature = "test-support"))] |
| 723 | impl FakeTransport { | 717 | 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) |
| 725 | where | 719 | where |
| 726 | F: 'static + Send + FnMut(u64, R::Arguments) -> Result<R::Response, ErrorResponse>, | 720 | F: 'static + Send + FnMut(u64, R::Arguments) -> Result<R::Response, ErrorResponse>, |
| 727 | { | 721 | { |
| 728 | self.request_handlers.lock().await.insert( | 722 | self.request_handlers.lock().insert( |
| 729 | R::COMMAND, | 723 | R::COMMAND, |
| 730 | Box::new( | 724 | Box::new(move |seq, args| { |
| 731 | move |seq, args, writer: Arc<Mutex<async_pipe::PipeWriter>>| { | 725 | let result = handler(seq, serde_json::from_value(args).unwrap()); |
| 732 | let response = handler(seq, serde_json::from_value(args).unwrap()); | 726 | let response = match result { |
| 733 | 727 | Ok(response) => Response { | |
| 734 | let message = serde_json::to_string(&Message::Response(Response { | ||
| 735 | seq: seq + 1, | 728 | seq: seq + 1, |
| 736 | request_seq: seq, | 729 | request_seq: seq, |
| 737 | success: response.as_ref().is_ok(), | 730 | success: true, |
| 738 | command: R::COMMAND.into(), | 731 | command: R::COMMAND.into(), |
| 739 | body: util::maybe!({ serde_json::to_value(response.ok()?).ok() }), | 732 | body: Some(serde_json::to_value(response).unwrap()), |
| 740 | message: None, | 733 | message: None, |
| 741 | })) | 734 | }, |
| 742 | .unwrap(); | 735 | Err(response) => Response { |
| 743 | 736 | seq: seq + 1, | |
| 744 | let writer = writer.clone(); | 737 | request_seq: seq, |
| 745 | 738 | success: false, | |
| 746 | Box::pin(async move { | 739 | command: R::COMMAND.into(), |
| 747 | let mut writer = writer.lock().await; | 740 | body: Some(serde_json::to_value(response).unwrap()), |
| 748 | writer | 741 | message: None, |
| 749 | .write_all(TransportDelegate::build_rpc_message(message).as_bytes()) | 742 | }, |
| 750 | .await | 743 | }; |
| 751 | .unwrap(); | 744 | response |
| 752 | writer.flush().await.unwrap(); | 745 | }), |
| 753 | }) | ||
| 754 | }, | ||
| 755 | ), | ||
| 756 | ); | 746 | ); |
| 757 | } | 747 | } |
| 758 | 748 | ||
| @@ -762,14 +752,13 @@ impl FakeTransport { · 3 unmodified lines | |||
| 762 | { | 752 | { |
| 763 | self.response_handlers | 753 | self.response_handlers |
| 764 | .lock() | 754 | .lock() |
| 765 | .await | ||
| 766 | .insert(R::COMMAND, Box::new(handler)); | 755 | .insert(R::COMMAND, Box::new(handler)); |
| 767 | } | 756 | } |
| 768 | 757 | ||
| 769 | async fn start(cx: AsyncApp) -> Result<(TransportPipe, Self)> { | 758 | async fn start(cx: AsyncApp) -> Result<(TransportPipe, Self)> { |
| 770 | let this = Self { | 759 | let this = Self { |
| 771 | request_handlers: Arc::new(Mutex::new(HashMap::default())), | 760 | request_handlers: Arc::new(parking_lot::Mutex::new(HashMap::default())), |
| 772 | response_handlers: Arc::new(Mutex::new(HashMap::default())), | 761 | response_handlers: Arc::new(parking_lot::Mutex::new(HashMap::default())), |
| 773 | }; | 762 | }; |
| 774 | use dap_types::requests::{Request, RunInTerminal, StartDebugging}; | 763 | use dap_types::requests::{Request, RunInTerminal, StartDebugging}; |
| 775 | use serde_json::json; | 764 | use serde_json::json; |
| @@ -816,23 +805,31 @@ impl FakeTransport { · 40 unmodified lines | |||
| 816 | .unwrap(); | 805 | .unwrap(); |
| 817 | writer.flush().await.unwrap(); | 806 | writer.flush().await.unwrap(); |
| 818 | } else { | 807 | } else { |
| 819 | if let Some(handle) = request_handlers | 808 | let response = if let Some(handle) = request_handlers |
| 820 | .lock() | 809 | .lock() |
| 821 | .await | ||
| 822 | .get_mut(request.command.as_str()) | 810 | .get_mut(request.command.as_str()) |
| 823 | { | 811 | { |
| 824 | handle( | 812 | handle( |
| 825 | request.seq, | 813 | request.seq, |
| 826 | request.arguments.unwrap_or(json!({})), | 814 | request.arguments.unwrap_or(json!({})), |
| 827 | stdout_writer.clone(), | ||
| 828 | ) | 815 | ) |
| 829 | .await; | ||
| 830 | } else { | 816 | } else { |
| 831 | log::error!( | 817 | panic!("No request handler for {}", request.command); |
| 832 | "No request handler for {}", | 818 | }; |
| 833 | request.command | 819 | let message = |
| 834 | ); | 820 | serde_json::to_string(&Message::Response(response)) |
| 835 | } | 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(); | ||
| 836 | } | 833 | } |
| 837 | } | 834 | } |
| 838 | Message::Event(event) => { | 835 | Message::Event(event) => { |
| @@ -850,10 +847,8 @@ impl FakeTransport { · 11 unmodified lines | |||
| 850 | writer.flush().await.unwrap(); | 847 | writer.flush().await.unwrap(); |
| 851 | } | 848 | } |
| 852 | Message::Response(response) => { | 849 | Message::Response(response) => { |
| 853 | if let Some(handle) = response_handlers | 850 | if let Some(handle) = |
| 854 | .lock() | 851 | response_handlers.lock().get(response.command.as_str()) |
| 855 | .await | ||
| 856 | .get(response.command.as_str()) | ||
| 857 | { | 852 | { |
| 858 | handle(response); | 853 | handle(response); |
| 859 | } else { | 854 | } else { |
| @@ -4,7 +4,7 @@ use anyhow::{Result, bail}; · 3 unmodified lines | |||
| 4 | use async_trait::async_trait; | 4 | use async_trait::async_trait; |
| 5 | use dap::adapters::latest_github_release; | 5 | use dap::adapters::latest_github_release; |
| 6 | use gpui::AsyncApp; | 6 | use gpui::AsyncApp; |
| 7 | use task::{DebugAdapterConfig, DebugRequestType, DebugTaskDefinition}; | 7 | use task::{DebugRequestType, DebugTaskDefinition}; |
| 8 | 8 | ||
| 9 | use crate::*; | 9 | use crate::*; |
| 10 | 10 | ||
| @@ -15,6 +15,42 @@ pub(crate) struct CodeLldbDebugAdapter { · 4 unmodified lines | |||
| 15 | 15 | ||
| 16 | impl CodeLldbDebugAdapter { | 16 | impl CodeLldbDebugAdapter { |
| 17 | const ADAPTER_NAME: &'static str = "CodeLLDB"; | 17 | 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 | } | ||
| 18 | } | 54 | } |
| 19 | 55 | ||
| 20 | #[async_trait(?Send)] | 56 | #[async_trait(?Send)] |
| @@ -86,7 +122,7 @@ impl DebugAdapter for CodeLldbDebugAdapter { · 65 unmodified lines | |||
| 86 | async fn get_installed_binary( | 122 | async fn get_installed_binary( |
| 87 | &self, | 123 | &self, |
| 88 | _: &dyn DapDelegate, | 124 | _: &dyn DapDelegate, |
| 89 | _: &DebugAdapterConfig, | 125 | config: &DebugTaskDefinition, |
| 90 | _: Option<PathBuf>, | 126 | _: Option<PathBuf>, |
| 91 | _: &mut AsyncApp, | 127 | _: &mut AsyncApp, |
| 92 | ) -> Result<DebugAdapterBinary> { | 128 | ) -> Result<DebugAdapterBinary> { |
| @@ -111,39 +147,10 @@ impl DebugAdapter for CodeLldbDebugAdapter { · 18 unmodified lines | |||
| 111 | .to_string() | 147 | .to_string() |
| 112 | .into(), | 148 | .into(), |
| 113 | ]), | 149 | ]), |
| 114 | ..Default::default() | 150 | request_args: self.request_args(config), |
| 151 | adapter_name: "test".into(), | ||
| 152 | envs: None, | ||
| 153 | connection: None, | ||
| 115 | }) | 154 | }) |
| 116 | } | 155 | } |
| 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 | } | ||
| 149 | } | 156 | } |
| @@ -12,7 +12,7 @@ use anyhow::{Result, anyhow}; · 11 unmodified lines | |||
| 12 | use async_trait::async_trait; | 12 | use async_trait::async_trait; |
| 13 | use codelldb::CodeLldbDebugAdapter; | 13 | use codelldb::CodeLldbDebugAdapter; |
| 14 | use dap::{ | 14 | use dap::{ |
| 15 | DapRegistry, | 15 | DapRegistry, DebugRequestType, |
| 16 | adapters::{ | 16 | adapters::{ |
| 17 | self, AdapterVersion, DapDelegate, DebugAdapter, DebugAdapterBinary, DebugAdapterName, | 17 | self, AdapterVersion, DapDelegate, DebugAdapter, DebugAdapterBinary, DebugAdapterName, |
| 18 | GithubRepo, | 18 | GithubRepo, |
| @@ -25,7 +25,7 @@ use lldb::LldbDebugAdapter; · 6 unmodified lines | |||
| 25 | use php::PhpDebugAdapter; | 25 | use php::PhpDebugAdapter; |
| 26 | use python::PythonDebugAdapter; | 26 | use python::PythonDebugAdapter; |
| 27 | use serde_json::{Value, json}; | 27 | use serde_json::{Value, json}; |
| 28 | use task::{DebugAdapterConfig, TCPHost}; | 28 | use task::TCPHost; |
| 29 | 29 | ||
| 30 | pub fn init(registry: Arc<DapRegistry>) { | 30 | pub fn init(registry: Arc<DapRegistry>) { |
| 31 | registry.add_adapter(Arc::from(CodeLldbDebugAdapter::default())); | 31 | registry.add_adapter(Arc::from(CodeLldbDebugAdapter::default())); |
| @@ -51,3 +51,16 @@ pub(crate) async fn configure_tcp_connection( · 19 unmodified lines | |||
| 51 | 51 | ||
| 52 | Ok((host, port, timeout)) | 52 | Ok((host, port, timeout)) |
| 53 | } | 53 | } |
| 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 | } | ||
| @@ -2,8 +2,9 @@ use std::ffi::OsStr; · 1 unmodified line | |||
| 2 | 2 | ||
| 3 | use anyhow::{Result, bail}; | 3 | use anyhow::{Result, bail}; |
| 4 | use async_trait::async_trait; | 4 | use async_trait::async_trait; |
| 5 | use dap::StartDebuggingRequestArguments; | ||
| 5 | use gpui::AsyncApp; | 6 | use gpui::AsyncApp; |
| 6 | use task::{DebugAdapterConfig, DebugRequestType, DebugTaskDefinition}; | 7 | use task::{DebugRequestType, DebugTaskDefinition}; |
| 7 | 8 | ||
| 8 | use crate::*; | 9 | use crate::*; |
| 9 | 10 | ||
| @@ -12,6 +13,44 @@ pub(crate) struct GdbDebugAdapter; · 2 unmodified lines | |||
| 12 | 13 | ||
| 13 | impl GdbDebugAdapter { | 14 | impl GdbDebugAdapter { |
| 14 | const ADAPTER_NAME: &'static str = "GDB"; | 15 | 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 | } | ||
| 15 | } | 54 | } |
| 16 | 55 | ||
| 17 | #[async_trait(?Send)] | 56 | #[async_trait(?Send)] |
| @@ -23,7 +62,7 @@ impl DebugAdapter for GdbDebugAdapter { · 5 unmodified lines | |||
| 23 | async fn get_binary( | 62 | async fn get_binary( |
| 24 | &self, | 63 | &self, |
| 25 | delegate: &dyn DapDelegate, | 64 | delegate: &dyn DapDelegate, |
| 26 | _: &DebugAdapterConfig, | 65 | config: &DebugTaskDefinition, |
| 27 | user_installed_path: Option<std::path::PathBuf>, | 66 | user_installed_path: Option<std::path::PathBuf>, |
| 28 | _: &mut AsyncApp, | 67 | _: &mut AsyncApp, |
| 29 | ) -> Result<DebugAdapterBinary> { | 68 | ) -> Result<DebugAdapterBinary> { |
| @@ -43,11 +82,13 @@ impl DebugAdapter for GdbDebugAdapter { · 13 unmodified lines | |||
| 43 | let gdb_path = user_setting_path.unwrap_or(gdb_path?); | 82 | let gdb_path = user_setting_path.unwrap_or(gdb_path?); |
| 44 | 83 | ||
| 45 | Ok(DebugAdapterBinary { | 84 | Ok(DebugAdapterBinary { |
| 85 | adapter_name: Self::ADAPTER_NAME.into(), | ||
| 46 | command: gdb_path, | 86 | command: gdb_path, |
| 47 | arguments: Some(vec!["-i=dap".into()]), | 87 | arguments: Some(vec!["-i=dap".into()]), |
| 48 | envs: None, | 88 | envs: None, |
| 49 | cwd: None, | 89 | cwd: None, |
| 50 | connection: None, | 90 | connection: None, |
| 91 | request_args: self.request_args(config), | ||
| 51 | }) | 92 | }) |
| 52 | } | 93 | } |
| 53 | 94 | ||
| @@ -66,45 +107,10 @@ impl DebugAdapter for GdbDebugAdapter { · 12 unmodified lines | |||
| 66 | async fn get_installed_binary( | 107 | async fn get_installed_binary( |
| 67 | &self, | 108 | &self, |
| 68 | _: &dyn DapDelegate, | 109 | _: &dyn DapDelegate, |
| 69 | _: &DebugAdapterConfig, | 110 | _: &DebugTaskDefinition, |
| 70 | _: Option<std::path::PathBuf>, | 111 | _: Option<std::path::PathBuf>, |
| 71 | _: &mut AsyncApp, | 112 | _: &mut AsyncApp, |
| 72 | ) -> Result<DebugAdapterBinary> { | 113 | ) -> Result<DebugAdapterBinary> { |
| 73 | unimplemented!("GDB cannot be installed by Zed (yet)") | 114 | unimplemented!("GDB cannot be installed by Zed (yet)") |
| 74 | } | 115 | } |
| 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 | } | ||
| 110 | } | 116 | } |
| @@ -1,3 +1,4 @@ | |||
| 1 | use dap::StartDebuggingRequestArguments; | ||
| 1 | use gpui::AsyncApp; | 2 | use gpui::AsyncApp; |
| 2 | use std::{ffi::OsStr, path::PathBuf}; | 3 | use std::{ffi::OsStr, path::PathBuf}; |
| 3 | use task::DebugTaskDefinition; | 4 | use task::DebugTaskDefinition; |
| @@ -9,6 +10,31 @@ pub(crate) struct GoDebugAdapter; · 5 unmodified lines | |||
| 9 | 10 | ||
| 10 | impl GoDebugAdapter { | 11 | impl GoDebugAdapter { |
| 11 | const ADAPTER_NAME: &'static str = "Delve"; | 12 | 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 | } | ||
| 12 | } | 38 | } |
| 13 | 39 | ||
| 14 | #[async_trait(?Send)] | 40 | #[async_trait(?Send)] |
| @@ -20,7 +46,7 @@ impl DebugAdapter for GoDebugAdapter { · 5 unmodified lines | |||
| 20 | async fn get_binary( | 46 | async fn get_binary( |
| 21 | &self, | 47 | &self, |
| 22 | delegate: &dyn DapDelegate, | 48 | delegate: &dyn DapDelegate, |
| 23 | config: &DebugAdapterConfig, | 49 | config: &DebugTaskDefinition, |
| 24 | user_installed_path: Option<PathBuf>, | 50 | user_installed_path: Option<PathBuf>, |
| 25 | cx: &mut AsyncApp, | 51 | cx: &mut AsyncApp, |
| 26 | ) -> Result<DebugAdapterBinary> { | 52 | ) -> Result<DebugAdapterBinary> { |
| @@ -53,7 +79,7 @@ impl DebugAdapter for GoDebugAdapter { · 26 unmodified lines | |||
| 53 | async fn get_installed_binary( | 79 | async fn get_installed_binary( |
| 54 | &self, | 80 | &self, |
| 55 | delegate: &dyn DapDelegate, | 81 | delegate: &dyn DapDelegate, |
| 56 | config: &DebugAdapterConfig, | 82 | config: &DebugTaskDefinition, |
| 57 | _: Option<PathBuf>, | 83 | _: Option<PathBuf>, |
| 58 | _: &mut AsyncApp, | 84 | _: &mut AsyncApp, |
| 59 | ) -> Result<DebugAdapterBinary> { | 85 | ) -> Result<DebugAdapterBinary> { |
| @@ -66,6 +92,7 @@ impl DebugAdapter for GoDebugAdapter { · 6 unmodified lines | |||
| 66 | let (host, port, timeout) = crate::configure_tcp_connection(tcp_connection).await?; | 92 | let (host, port, timeout) = crate::configure_tcp_connection(tcp_connection).await?; |
| 67 | 93 | ||
| 68 | Ok(DebugAdapterBinary { | 94 | Ok(DebugAdapterBinary { |
| 95 | adapter_name: self.name(), | ||
| 69 | command: delve_path, | 96 | command: delve_path, |
| 70 | arguments: Some(vec![ | 97 | arguments: Some(vec![ |
| 71 | "dap".into(), | 98 | "dap".into(), |
| @@ -79,29 +106,7 @@ impl DebugAdapter for GoDebugAdapter { · 7 unmodified lines | |||
| 79 | port, | 106 | port, |
| 80 | timeout, | 107 | timeout, |
| 81 | }), | 108 | }), |
| 109 | request_args: self.request_args(config), | ||
| 82 | }) | 110 | }) |
| 83 | } | 111 | } |
| 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 | } | ||
| 107 | } | 112 | } |
| @@ -1,4 +1,5 @@ | |||
| 1 | use adapters::latest_github_release; | 1 | use adapters::latest_github_release; |
| 2 | use dap::StartDebuggingRequestArguments; | ||
| 2 | use gpui::AsyncApp; | 3 | use gpui::AsyncApp; |
| 3 | use std::path::PathBuf; | 4 | use std::path::PathBuf; |
| 4 | use task::{DebugRequestType, DebugTaskDefinition}; | 5 | use task::{DebugRequestType, DebugTaskDefinition}; |
| @@ -12,6 +13,40 @@ impl JsDebugAdapter { · 7 unmodified lines | |||
| 12 | const ADAPTER_NAME: &'static str = "JavaScript"; | 13 | const ADAPTER_NAME: &'static str = "JavaScript"; |
| 13 | const ADAPTER_NPM_NAME: &'static str = "vscode-js-debug"; | 14 | const ADAPTER_NPM_NAME: &'static str = "vscode-js-debug"; |
| 14 | const ADAPTER_PATH: &'static str = "js-debug/src/dapDebugServer.js"; | 15 | 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 | } | ||
| 15 | } | 50 | } |
| 16 | 51 | ||
| 17 | #[async_trait(?Send)] | 52 | #[async_trait(?Send)] |
| @@ -49,7 +84,7 @@ impl DebugAdapter for JsDebugAdapter { · 31 unmodified lines | |||
| 49 | async fn get_installed_binary( | 84 | async fn get_installed_binary( |
| 50 | &self, | 85 | &self, |
| 51 | delegate: &dyn DapDelegate, | 86 | delegate: &dyn DapDelegate, |
| 52 | config: &DebugAdapterConfig, | 87 | config: &DebugTaskDefinition, |
| 53 | user_installed_path: Option<PathBuf>, | 88 | user_installed_path: Option<PathBuf>, |
| 54 | _: &mut AsyncApp, | 89 | _: &mut AsyncApp, |
| 55 | ) -> Result<DebugAdapterBinary> { | 90 | ) -> Result<DebugAdapterBinary> { |
| @@ -71,6 +106,7 @@ impl DebugAdapter for JsDebugAdapter { · 15 unmodified lines | |||
| 71 | let (host, port, timeout) = crate::configure_tcp_connection(tcp_connection).await?; | 106 | let (host, port, timeout) = crate::configure_tcp_connection(tcp_connection).await?; |
| 72 | 107 | ||
| 73 | Ok(DebugAdapterBinary { | 108 | Ok(DebugAdapterBinary { |
| 109 | adapter_name: self.name(), | ||
| 74 | command: delegate | 110 | command: delegate |
| 75 | .node_runtime() | 111 | .node_runtime() |
| 76 | .binary_path() | 112 | .binary_path() |
| @@ -89,6 +125,7 @@ impl DebugAdapter for JsDebugAdapter { · 12 unmodified lines | |||
| 89 | port, | 125 | port, |
| 90 | timeout, | 126 | timeout, |
| 91 | }), | 127 | }), |
| 128 | request_args: self.request_args(config), | ||
| 92 | }) | 129 | }) |
| 93 | } | 130 | } |
| 94 | 131 | ||
| @@ -107,35 +144,4 @@ impl DebugAdapter for JsDebugAdapter { · 12 unmodified lines | |||
| 107 | 144 | ||
| 108 | return Ok(()); | 145 | return Ok(()); |
| 109 | } | 146 | } |
| 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 | } | ||
| 141 | } | 147 | } |
| @@ -3,7 +3,7 @@ use std::{ffi::OsStr, path::PathBuf}; · 2 unmodified lines | |||
| 3 | use anyhow::Result; | 3 | use anyhow::Result; |
| 4 | use async_trait::async_trait; | 4 | use async_trait::async_trait; |
| 5 | use gpui::AsyncApp; | 5 | use gpui::AsyncApp; |
| 6 | use task::{DebugAdapterConfig, DebugRequestType, DebugTaskDefinition}; | 6 | use task::{DebugRequestType, DebugTaskDefinition}; |
| 7 | 7 | ||
| 8 | use crate::*; | 8 | use crate::*; |
| 9 | 9 | ||
| @@ -12,6 +12,40 @@ pub(crate) struct LldbDebugAdapter; · 2 unmodified lines | |||
| 12 | 12 | ||
| 13 | impl LldbDebugAdapter { | 13 | impl LldbDebugAdapter { |
| 14 | const ADAPTER_NAME: &'static str = "LLDB"; | 14 | 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 | } | ||
| 15 | } | 49 | } |
| 16 | 50 | ||
| 17 | #[async_trait(?Send)] | 51 | #[async_trait(?Send)] |
| @@ -23,7 +57,7 @@ impl DebugAdapter for LldbDebugAdapter { · 5 unmodified lines | |||
| 23 | async fn get_binary( | 57 | async fn get_binary( |
| 24 | &self, | 58 | &self, |
| 25 | delegate: &dyn DapDelegate, | 59 | delegate: &dyn DapDelegate, |
| 26 | _: &DebugAdapterConfig, | 60 | config: &DebugTaskDefinition, |
| 27 | user_installed_path: Option<PathBuf>, | 61 | user_installed_path: Option<PathBuf>, |
| 28 | _: &mut AsyncApp, | 62 | _: &mut AsyncApp, |
| 29 | ) -> Result<DebugAdapterBinary> { | 63 | ) -> Result<DebugAdapterBinary> { |
| @@ -37,11 +71,13 @@ impl DebugAdapter for LldbDebugAdapter { · 7 unmodified lines | |||
| 37 | }; | 71 | }; |
| 38 | 72 | ||
| 39 | Ok(DebugAdapterBinary { | 73 | Ok(DebugAdapterBinary { |
| 74 | adapter_name: Self::ADAPTER_NAME.into(), | ||
| 40 | command: lldb_dap_path, | 75 | command: lldb_dap_path, |
| 41 | arguments: None, | 76 | arguments: None, |
| 42 | envs: None, | 77 | envs: None, |
| 43 | cwd: None, | 78 | cwd: None, |
| 44 | connection: None, | 79 | connection: None, |
| 80 | request_args: self.request_args(config), | ||
| 45 | }) | 81 | }) |
| 46 | } | 82 | } |
| 47 | 83 | ||
| @@ -60,40 +96,10 @@ impl DebugAdapter for LldbDebugAdapter { · 12 unmodified lines | |||
| 60 | async fn get_installed_binary( | 96 | async fn get_installed_binary( |
| 61 | &self, | 97 | &self, |
| 62 | _: &dyn DapDelegate, | 98 | _: &dyn DapDelegate, |
| 63 | _: &DebugAdapterConfig, | 99 | _: &DebugTaskDefinition, |
| 64 | _: Option<PathBuf>, | 100 | _: Option<PathBuf>, |
| 65 | _: &mut AsyncApp, | 101 | _: &mut AsyncApp, |
| 66 | ) -> Result<DebugAdapterBinary> { | 102 | ) -> Result<DebugAdapterBinary> { |
| 67 | unimplemented!("LLDB debug adapter cannot be installed by Zed (yet)") | 103 | unimplemented!("LLDB debug adapter cannot be installed by Zed (yet)") |
| 68 | } | 104 | } |
| 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 | } | ||
| 99 | } | 105 | } |
| @@ -13,6 +13,28 @@ impl PhpDebugAdapter { · 12 unmodified lines | |||
| 13 | const ADAPTER_NAME: &'static str = "PHP"; | 13 | const ADAPTER_NAME: &'static str = "PHP"; |
| 14 | const ADAPTER_PACKAGE_NAME: &'static str = "vscode-php-debug"; | 14 | const ADAPTER_PACKAGE_NAME: &'static str = "vscode-php-debug"; |
| 15 | const ADAPTER_PATH: &'static str = "extension/out/phpDebug.js"; | 15 | 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 | } | ||
| 16 | } | 38 | } |
| 17 | 39 | ||
| 18 | #[async_trait(?Send)] | 40 | #[async_trait(?Send)] |
| @@ -50,7 +72,7 @@ impl DebugAdapter for PhpDebugAdapter { · 31 unmodified lines | |||
| 50 | async fn get_installed_binary( | 72 | async fn get_installed_binary( |
| 51 | &self, | 73 | &self, |
| 52 | delegate: &dyn DapDelegate, | 74 | delegate: &dyn DapDelegate, |
| 53 | config: &DebugAdapterConfig, | 75 | config: &DebugTaskDefinition, |
| 54 | user_installed_path: Option<PathBuf>, | 76 | user_installed_path: Option<PathBuf>, |
| 55 | _: &mut AsyncApp, | 77 | _: &mut AsyncApp, |
| 56 | ) -> Result<DebugAdapterBinary> { | 78 | ) -> Result<DebugAdapterBinary> { |
| @@ -72,6 +94,7 @@ impl DebugAdapter for PhpDebugAdapter { · 15 unmodified lines | |||
| 72 | let (host, port, timeout) = crate::configure_tcp_connection(tcp_connection).await?; | 94 | let (host, port, timeout) = crate::configure_tcp_connection(tcp_connection).await?; |
| 73 | 95 | ||
| 74 | Ok(DebugAdapterBinary { | 96 | Ok(DebugAdapterBinary { |
| 97 | adapter_name: self.name(), | ||
| 75 | command: delegate | 98 | command: delegate |
| 76 | .node_runtime() | 99 | .node_runtime() |
| 77 | .binary_path() | 100 | .binary_path() |
| @@ -89,6 +112,7 @@ impl DebugAdapter for PhpDebugAdapter { · 11 unmodified lines | |||
| 89 | }), | 112 | }), |
| 90 | cwd: None, | 113 | cwd: None, |
| 91 | envs: None, | 114 | envs: None, |
| 115 | request_args: self.request_args(config)?, | ||
| 92 | }) | 116 | }) |
| 93 | } | 117 | } |
| 94 | 118 | ||
| @@ -107,21 +131,4 @@ impl DebugAdapter for PhpDebugAdapter { · 12 unmodified lines | |||
| 107 | 131 | ||
| 108 | Ok(()) | 132 | Ok(()) |
| 109 | } | 133 | } |
| 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 | } | ||
| 127 | } | 134 | } |
| @@ -1,5 +1,5 @@ | |||
| 1 | use crate::*; | 1 | use crate::*; |
| 2 | use dap::DebugRequestType; | 2 | use dap::{DebugRequestType, StartDebuggingRequestArguments}; |
| 3 | use gpui::AsyncApp; | 3 | use gpui::AsyncApp; |
| 4 | use std::{ffi::OsStr, path::PathBuf}; | 4 | use std::{ffi::OsStr, path::PathBuf}; |
| 5 | use task::DebugTaskDefinition; | 5 | use task::DebugTaskDefinition; |
| @@ -12,6 +12,38 @@ impl PythonDebugAdapter { · 6 unmodified lines | |||
| 12 | const ADAPTER_PACKAGE_NAME: &'static str = "debugpy"; | 12 | const ADAPTER_PACKAGE_NAME: &'static str = "debugpy"; |
| 13 | const ADAPTER_PATH: &'static str = "src/debugpy/adapter"; | 13 | const ADAPTER_PATH: &'static str = "src/debugpy/adapter"; |
| 14 | const LANGUAGE_NAME: &'static str = "Python"; | 14 | 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 | } | ||
| 15 | } | 47 | } |
| 16 | 48 | ||
| 17 | #[async_trait(?Send)] | 49 | #[async_trait(?Send)] |
| @@ -64,7 +96,7 @@ impl DebugAdapter for PythonDebugAdapter { · 46 unmodified lines | |||
| 64 | async fn get_installed_binary( | 96 | async fn get_installed_binary( |
| 65 | &self, | 97 | &self, |
| 66 | delegate: &dyn DapDelegate, | 98 | delegate: &dyn DapDelegate, |
| 67 | config: &DebugAdapterConfig, | 99 | config: &DebugTaskDefinition, |
| 68 | user_installed_path: Option<PathBuf>, | 100 | user_installed_path: Option<PathBuf>, |
| 69 | cx: &mut AsyncApp, | 101 | cx: &mut AsyncApp, |
| 70 | ) -> Result<DebugAdapterBinary> { | 102 | ) -> Result<DebugAdapterBinary> { |
| @@ -109,6 +141,7 @@ impl DebugAdapter for PythonDebugAdapter { · 38 unmodified lines | |||
| 109 | }; | 141 | }; |
| 110 | 142 | ||
| 111 | Ok(DebugAdapterBinary { | 143 | Ok(DebugAdapterBinary { |
| 144 | adapter_name: self.name(), | ||
| 112 | command: python_path.ok_or(anyhow!("failed to find binary path for python"))?, | 145 | command: python_path.ok_or(anyhow!("failed to find binary path for python"))?, |
| 113 | arguments: Some(vec![ | 146 | arguments: Some(vec![ |
| 114 | debugpy_dir.join(Self::ADAPTER_PATH).into(), | 147 | debugpy_dir.join(Self::ADAPTER_PATH).into(), |
| @@ -122,35 +155,7 @@ impl DebugAdapter for PythonDebugAdapter { · 7 unmodified lines | |||
| 122 | }), | 155 | }), |
| 123 | cwd: None, | 156 | cwd: None, |
| 124 | envs: None, | 157 | envs: None, |
| 158 | request_args: self.request_args(config), | ||
| 125 | }) | 159 | }) |
| 126 | } | 160 | } |
| 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 | } | ||
| 156 | } | 161 | } |
| @@ -228,10 +228,7 @@ impl PickerDelegate for AttachModalDelegate { · 227 unmodified lines | |||
| 228 | let config = self.debug_config.clone(); | 228 | let config = self.debug_config.clone(); |
| 229 | self.project | 229 | self.project |
| 230 | .update(cx, |project, cx| { | 230 | .update(cx, |project, cx| { |
| 231 | #[cfg(any(test, feature = "test-support"))] | 231 | let ret = project.start_debug_session(config, cx); |
| 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); | ||
| 235 | ret | 232 | ret |
| 236 | }) | 233 | }) |
| 237 | .detach_and_log_err(cx); | 234 | .detach_and_log_err(cx); |
| @@ -146,7 +146,7 @@ impl NewSessionModal { · 145 unmodified lines | |||
| 146 | { | 146 | { |
| 147 | this.start_debug_session(debug_config, cx) | 147 | this.start_debug_session(debug_config, cx) |
| 148 | } else { | 148 | } else { |
| 149 | this.start_debug_session(config.into(), cx) | 149 | this.start_debug_session(config, cx) |
| 150 | } | 150 | } |
| 151 | })?; | 151 | })?; |
| 152 | let spawn_result = task.await; | 152 | let spawn_result = task.await; |
| @@ -26,18 +26,30 @@ async fn test_direct_attach_to_process(executor: BackgroundExecutor, cx: &mut Te · 25 unmodified lines | |||
| 26 | let workspace = init_test_workspace(&project, cx).await; | 26 | let workspace = init_test_workspace(&project, cx).await; |
| 27 | let cx = &mut VisualTestContext::from_window(*workspace, cx); | 27 | let cx = &mut VisualTestContext::from_window(*workspace, cx); |
| 28 | 28 | ||
| 29 | let task = project.update(cx, |project, cx| { | 29 | let session = debugger::test::start_debug_session_with( |
| 30 | project.fake_debug_session( | 30 | &project, |
| 31 | dap::DebugRequestType::Attach(AttachConfig { | 31 | cx, |
| 32 | DebugTaskDefinition { | ||
| 33 | adapter: "fake-adapter".to_string(), | ||
| 34 | request: dap::DebugRequestType::Attach(AttachConfig { | ||
| 32 | process_id: Some(10), | 35 | process_id: Some(10), |
| 33 | }), | 36 | }), |
| 34 | None, | 37 | label: "label".to_string(), |
| 35 | false, | 38 | initialize_args: None, |
| 36 | cx, | 39 | tcp_connection: None, |
| 37 | ) | 40 | locator: None, |
| 38 | }); | 41 | stop_on_entry: None, |
| 39 | 42 | }, | |
| 40 | let session = task.await.unwrap(); | 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(); | ||
| 41 | 53 | ||
| 42 | cx.run_until_parked(); | 54 | cx.run_until_parked(); |
| 43 | 55 | ||
| @@ -77,7 +89,15 @@ async fn test_show_attach_modal_and_select_process( · 33 unmodified lines | |||
| 77 | let project = Project::test(fs, ["/project".as_ref()], cx).await; | 89 | let project = Project::test(fs, ["/project".as_ref()], cx).await; |
| 78 | let workspace = init_test_workspace(&project, cx).await; | 90 | let workspace = init_test_workspace(&project, cx).await; |
| 79 | let cx = &mut VisualTestContext::from_window(*workspace, cx); | 91 | 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); | ||
| 80 | 97 | ||
| 98 | Ok(()) | ||
| 99 | }); | ||
| 100 | }); | ||
| 81 | let attach_modal = workspace | 101 | let attach_modal = workspace |
| 82 | .update(cx, |workspace, window, cx| { | 102 | .update(cx, |workspace, window, cx| { |
| 83 | workspace.toggle_modal(window, cx, |window, cx| { | 103 | workspace.toggle_modal(window, cx, |window, cx| { |
| @@ -3,7 +3,6 @@ use dap::requests::StackTrace; · 2 unmodified lines | |||
| 3 | use gpui::{BackgroundExecutor, TestAppContext, VisualTestContext}; | 3 | use gpui::{BackgroundExecutor, TestAppContext, VisualTestContext}; |
| 4 | use project::{FakeFs, Project}; | 4 | use project::{FakeFs, Project}; |
| 5 | use serde_json::json; | 5 | use serde_json::json; |
| 6 | use task::LaunchConfig; | ||
| 7 | use tests::{init_test, init_test_workspace}; | 6 | use tests::{init_test, init_test_workspace}; |
| 8 | 7 | ||
| 9 | #[gpui::test] | 8 | #[gpui::test] |
| @@ -29,26 +28,17 @@ async fn test_handle_output_event(executor: BackgroundExecutor, cx: &mut TestApp · 19 unmodified lines | |||
| 29 | }) | 28 | }) |
| 30 | .unwrap(); | 29 | .unwrap(); |
| 31 | 30 | ||
| 32 | let task = project.update(cx, |project, cx| { | 31 | let session = debugger::test::start_debug_session(&project, cx, |_| {}) |
| 33 | project.fake_debug_session( | 32 | .await |
| 34 | dap::DebugRequestType::Launch(LaunchConfig::default()), | 33 | .unwrap(); |
| 35 | None, | ||
| 36 | false, | ||
| 37 | cx, | ||
| 38 | ) | ||
| 39 | }); | ||
| 40 | |||
| 41 | let session = task.await.unwrap(); | ||
| 42 | let client = session.update(cx, |session, _| session.adapter_client().unwrap()); | 34 | let client = session.update(cx, |session, _| session.adapter_client().unwrap()); |
| 43 | 35 | ||
| 44 | client | 36 | client.on_request::<StackTrace, _>(move |_, _| { |
| 45 | .on_request::<StackTrace, _>(move |_, _| { | 37 | Ok(dap::StackTraceResponse { |
| 46 | Ok(dap::StackTraceResponse { | 38 | stack_frames: Vec::default(), |
| 47 | stack_frames: Vec::default(), | 39 | total_frames: None, |
| 48 | total_frames: None, | ||
| 49 | }) | ||
| 50 | }) | 40 | }) |
| 51 | .await; | 41 | }); |
| 52 | 42 | ||
| 53 | client | 43 | client |
| 54 | .fake_event(dap::messages::Events::Output(dap::OutputEvent { | 44 | .fake_event(dap::messages::Events::Output(dap::OutputEvent { |
| @@ -1,7 +1,7 @@ | |||
| 1 | use crate::*; | 1 | use crate::*; |
| 2 | use dap::{ | 2 | use dap::{ |
| 3 | ErrorResponse, RunInTerminalRequestArguments, SourceBreakpoint, StartDebuggingRequestArguments, | 3 | ErrorResponse, Message, RunInTerminalRequestArguments, SourceBreakpoint, |
| 4 | StartDebuggingRequestArgumentsRequest, | 4 | StartDebuggingRequestArguments, StartDebuggingRequestArgumentsRequest, |
| 5 | client::SessionId, | 5 | client::SessionId, |
| 6 | requests::{ | 6 | requests::{ |
| 7 | Continue, Disconnect, Launch, Next, RunInTerminal, SetBreakpoints, StackTrace, | 7 | Continue, Disconnect, Launch, Next, RunInTerminal, SetBreakpoints, StackTrace, |
| @@ -25,7 +25,6 @@ use std::{ · 17 unmodified lines | |||
| 25 | atomic::{AtomicBool, Ordering}, | 25 | atomic::{AtomicBool, Ordering}, |
| 26 | }, | 26 | }, |
| 27 | }; | 27 | }; |
| 28 | use task::LaunchConfig; | ||
| 29 | use terminal_view::{TerminalView, terminal_panel::TerminalPanel}; | 28 | use terminal_view::{TerminalView, terminal_panel::TerminalPanel}; |
| 30 | use tests::{active_debug_session_panel, init_test, init_test_workspace}; | 29 | use tests::{active_debug_session_panel, init_test, init_test_workspace}; |
| 31 | use util::path; | 30 | use util::path; |
| @@ -49,37 +48,26 @@ async fn test_basic_show_debug_panel(executor: BackgroundExecutor, cx: &mut Test · 17 unmodified lines | |||
| 49 | let workspace = init_test_workspace(&project, cx).await; | 48 | let workspace = init_test_workspace(&project, cx).await; |
| 50 | let cx = &mut VisualTestContext::from_window(*workspace, cx); | 49 | let cx = &mut VisualTestContext::from_window(*workspace, cx); |
| 51 | 50 | ||
| 52 | let task = project.update(cx, |project, cx| { | 51 | let session = debugger::test::start_debug_session(&project, cx, |_| {}) |
| 53 | project.fake_debug_session( | 52 | .await |
| 54 | dap::DebugRequestType::Launch(LaunchConfig::default()), | 53 | .unwrap(); |
| 55 | None, | ||
| 56 | false, | ||
| 57 | cx, | ||
| 58 | ) | ||
| 59 | }); | ||
| 60 | |||
| 61 | let session = task.await.unwrap(); | ||
| 62 | let client = session.update(cx, |session, _| session.adapter_client().unwrap()); | 54 | let client = session.update(cx, |session, _| session.adapter_client().unwrap()); |
| 63 | 55 | ||
| 64 | client | 56 | client.on_request::<Threads, _>(move |_, _| { |
| 65 | .on_request::<Threads, _>(move |_, _| { | 57 | Ok(dap::ThreadsResponse { |
| 66 | Ok(dap::ThreadsResponse { | 58 | threads: vec![dap::Thread { |
| 67 | threads: vec![dap::Thread { | 59 | id: 1, |
| 68 | id: 1, | 60 | name: "Thread 1".into(), |
| 69 | name: "Thread 1".into(), | 61 | }], |
| 70 | }], | ||
| 71 | }) | ||
| 72 | }) | 62 | }) |
| 73 | .await; | 63 | }); |
| 74 | 64 | ||
| 75 | client | 65 | client.on_request::<StackTrace, _>(move |_, _| { |
| 76 | .on_request::<StackTrace, _>(move |_, _| { | 66 | Ok(dap::StackTraceResponse { |
| 77 | Ok(dap::StackTraceResponse { | 67 | stack_frames: Vec::default(), |
| 78 | stack_frames: Vec::default(), | 68 | total_frames: None, |
| 79 | total_frames: None, | ||
| 80 | }) | ||
| 81 | }) | 69 | }) |
| 82 | .await; | 70 | }); |
| 83 | 71 | ||
| 84 | cx.run_until_parked(); | 72 | cx.run_until_parked(); |
| 85 | 73 | ||
| @@ -199,37 +187,26 @@ async fn test_we_can_only_have_one_panel_per_debug_session( · 113 unmodified lines | |||
| 199 | let workspace = init_test_workspace(&project, cx).await; | 187 | let workspace = init_test_workspace(&project, cx).await; |
| 200 | let cx = &mut VisualTestContext::from_window(*workspace, cx); | 188 | let cx = &mut VisualTestContext::from_window(*workspace, cx); |
| 201 | 189 | ||
| 202 | let task = project.update(cx, |project, cx| { | 190 | let session = debugger::test::start_debug_session(&project, cx, |_| {}) |
| 203 | project.fake_debug_session( | 191 | .await |
| 204 | dap::DebugRequestType::Launch(LaunchConfig::default()), | 192 | .unwrap(); |
| 205 | None, | ||
| 206 | false, | ||
| 207 | cx, | ||
| 208 | ) | ||
| 209 | }); | ||
| 210 | |||
| 211 | let session = task.await.unwrap(); | ||
| 212 | let client = session.update(cx, |session, _| session.adapter_client().unwrap()); | 193 | let client = session.update(cx, |session, _| session.adapter_client().unwrap()); |
| 213 | 194 | ||
| 214 | client | 195 | client.on_request::<Threads, _>(move |_, _| { |
| 215 | .on_request::<Threads, _>(move |_, _| { | 196 | Ok(dap::ThreadsResponse { |
| 216 | Ok(dap::ThreadsResponse { | 197 | threads: vec![dap::Thread { |
| 217 | threads: vec![dap::Thread { | 198 | id: 1, |
| 218 | id: 1, | 199 | name: "Thread 1".into(), |
| 219 | name: "Thread 1".into(), | 200 | }], |
| 220 | }], | ||
| 221 | }) | ||
| 222 | }) | 201 | }) |
| 223 | .await; | 202 | }); |
| 224 | 203 | ||
| 225 | client | 204 | client.on_request::<StackTrace, _>(move |_, _| { |
| 226 | .on_request::<StackTrace, _>(move |_, _| { | 205 | Ok(dap::StackTraceResponse { |
| 227 | Ok(dap::StackTraceResponse { | 206 | stack_frames: Vec::default(), |
| 228 | stack_frames: Vec::default(), | 207 | total_frames: None, |
| 229 | total_frames: None, | ||
| 230 | }) | ||
| 231 | }) | 208 | }) |
| 232 | .await; | 209 | }); |
| 233 | 210 | ||
| 234 | cx.run_until_parked(); | 211 | cx.run_until_parked(); |
| 235 | 212 | ||
| @@ -377,16 +354,9 @@ async fn test_handle_successful_run_in_terminal_reverse_request( · 141 unmodified lines | |||
| 377 | let workspace = init_test_workspace(&project, cx).await; | 354 | let workspace = init_test_workspace(&project, cx).await; |
| 378 | let cx = &mut VisualTestContext::from_window(*workspace, cx); | 355 | let cx = &mut VisualTestContext::from_window(*workspace, cx); |
| 379 | 356 | ||
| 380 | let task = project.update(cx, |project, cx| { | 357 | let session = debugger::test::start_debug_session(&project, cx, |_| {}) |
| 381 | project.fake_debug_session( | 358 | .await |
| 382 | dap::DebugRequestType::Launch(LaunchConfig::default()), | 359 | .unwrap(); |
| 383 | None, | ||
| 384 | false, | ||
| 385 | cx, | ||
| 386 | ) | ||
| 387 | }); | ||
| 388 | |||
| 389 | let session = task.await.unwrap(); | ||
| 390 | let client = session.update(cx, |session, _| session.adapter_client().unwrap()); | 360 | let client = session.update(cx, |session, _| session.adapter_client().unwrap()); |
| 391 | 361 | ||
| 392 | client | 362 | client |
| @@ -474,16 +444,9 @@ async fn test_handle_error_run_in_terminal_reverse_request( · 81 unmodified lines | |||
| 474 | let workspace = init_test_workspace(&project, cx).await; | 444 | let workspace = init_test_workspace(&project, cx).await; |
| 475 | let cx = &mut VisualTestContext::from_window(*workspace, cx); | 445 | let cx = &mut VisualTestContext::from_window(*workspace, cx); |
| 476 | 446 | ||
| 477 | let task = project.update(cx, |project, cx| { | 447 | let session = debugger::test::start_debug_session(&project, cx, |_| {}) |
| 478 | project.fake_debug_session( | 448 | .await |
| 479 | dap::DebugRequestType::Launch(LaunchConfig::default()), | 449 | .unwrap(); |
| 480 | None, | ||
| 481 | false, | ||
| 482 | cx, | ||
| 483 | ) | ||
| 484 | }); | ||
| 485 | |||
| 486 | let session = task.await.unwrap(); | ||
| 487 | let client = session.update(cx, |session, _| session.adapter_client().unwrap()); | 450 | let client = session.update(cx, |session, _| session.adapter_client().unwrap()); |
| 488 | 451 | ||
| 489 | client | 452 | client |
| @@ -559,28 +522,19 @@ async fn test_handle_start_debugging_reverse_request( · 69 unmodified lines | |||
| 559 | let workspace = init_test_workspace(&project, cx).await; | 522 | let workspace = init_test_workspace(&project, cx).await; |
| 560 | let cx = &mut VisualTestContext::from_window(*workspace, cx); | 523 | let cx = &mut VisualTestContext::from_window(*workspace, cx); |
| 561 | 524 | ||
| 562 | let task = project.update(cx, |project, cx| { | 525 | let session = debugger::test::start_debug_session(&project, cx, |_| {}) |
| 563 | project.fake_debug_session( | 526 | .await |
| 564 | dap::DebugRequestType::Launch(LaunchConfig::default()), | 527 | .unwrap(); |
| 565 | None, | ||
| 566 | false, | ||
| 567 | cx, | ||
| 568 | ) | ||
| 569 | }); | ||
| 570 | |||
| 571 | let session = task.await.unwrap(); | ||
| 572 | let client = session.update(cx, |session, _| session.adapter_client().unwrap()); | 528 | let client = session.update(cx, |session, _| session.adapter_client().unwrap()); |
| 573 | 529 | ||
| 574 | client | 530 | client.on_request::<dap::requests::Threads, _>(move |_, _| { |
| 575 | .on_request::<dap::requests::Threads, _>(move |_, _| { | 531 | Ok(dap::ThreadsResponse { |
| 576 | Ok(dap::ThreadsResponse { | 532 | threads: vec![dap::Thread { |
| 577 | threads: vec![dap::Thread { | 533 | id: 1, |
| 578 | id: 1, | 534 | name: "Thread 1".into(), |
| 579 | name: "Thread 1".into(), | 535 | }], |
| 580 | }], | ||
| 581 | }) | ||
| 582 | }) | 536 | }) |
| 583 | .await; | 537 | }); |
| 584 | 538 | ||
| 585 | client | 539 | client |
| 586 | .on_response::<StartDebugging, _>({ | 540 | .on_response::<StartDebugging, _>({ |
| @@ -593,7 +547,9 @@ async fn test_handle_start_debugging_reverse_request( · 6 unmodified lines | |||
| 593 | } | 547 | } |
| 594 | }) | 548 | }) |
| 595 | .await; | 549 | .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, |_| {}); | ||
| 597 | client | 553 | client |
| 598 | .fake_reverse_request::<StartDebugging>(StartDebuggingRequestArguments { | 554 | .fake_reverse_request::<StartDebugging>(StartDebuggingRequestArguments { |
| 599 | configuration: json!({}), | 555 | configuration: json!({}), |
| @@ -612,20 +568,16 @@ async fn test_handle_start_debugging_reverse_request( · 12 unmodified lines | |||
| 612 | }); | 568 | }); |
| 613 | let child_client = child_session.update(cx, |session, _| session.adapter_client().unwrap()); | 569 | let child_client = child_session.update(cx, |session, _| session.adapter_client().unwrap()); |
| 614 | 570 | ||
| 615 | child_client | 571 | child_client.on_request::<dap::requests::Threads, _>(move |_, _| { |
| 616 | .on_request::<dap::requests::Threads, _>(move |_, _| { | 572 | Ok(dap::ThreadsResponse { |
| 617 | Ok(dap::ThreadsResponse { | 573 | threads: vec![dap::Thread { |
| 618 | threads: vec![dap::Thread { | 574 | id: 1, |
| 619 | id: 1, | 575 | name: "Thread 1".into(), |
| 620 | name: "Thread 1".into(), | 576 | }], |
| 621 | }], | ||
| 622 | }) | ||
| 623 | }) | 577 | }) |
| 624 | .await; | 578 | }); |
| 625 | 579 | ||
| 626 | child_client | 580 | child_client.on_request::<Disconnect, _>(move |_, _| Ok(())); |
| 627 | .on_request::<Disconnect, _>(move |_, _| Ok(())) | ||
| 628 | .await; | ||
| 629 | 581 | ||
| 630 | child_client | 582 | child_client |
| 631 | .fake_event(dap::messages::Events::Stopped(dap::StoppedEvent { | 583 | .fake_event(dap::messages::Events::Stopped(dap::StoppedEvent { |
| @@ -677,31 +629,24 @@ async fn test_shutdown_children_when_parent_session_shutdown( · 45 unmodified lines | |||
| 677 | let workspace = init_test_workspace(&project, cx).await; | 629 | let workspace = init_test_workspace(&project, cx).await; |
| 678 | let cx = &mut VisualTestContext::from_window(*workspace, cx); | 630 | let cx = &mut VisualTestContext::from_window(*workspace, cx); |
| 679 | 631 | ||
| 680 | let task = project.update(cx, |project, cx| { | 632 | let parent_session = debugger::test::start_debug_session(&project, cx, |_| {}) |
| 681 | project.fake_debug_session( | 633 | .await |
| 682 | dap::DebugRequestType::Launch(LaunchConfig::default()), | 634 | .unwrap(); |
| 683 | None, | ||
| 684 | false, | ||
| 685 | cx, | ||
| 686 | ) | ||
| 687 | }); | ||
| 688 | |||
| 689 | let parent_session = task.await.unwrap(); | ||
| 690 | let client = parent_session.update(cx, |session, _| session.adapter_client().unwrap()); | 635 | let client = parent_session.update(cx, |session, _| session.adapter_client().unwrap()); |
| 691 | 636 | ||
| 692 | client | 637 | client.on_request::<dap::requests::Threads, _>(move |_, _| { |
| 693 | .on_request::<dap::requests::Threads, _>(move |_, _| { | 638 | Ok(dap::ThreadsResponse { |
| 694 | Ok(dap::ThreadsResponse { | 639 | threads: vec![dap::Thread { |
| 695 | threads: vec![dap::Thread { | 640 | id: 1, |
| 696 | id: 1, | 641 | name: "Thread 1".into(), |
| 697 | name: "Thread 1".into(), | 642 | }], |
| 698 | }], | ||
| 699 | }) | ||
| 700 | }) | 643 | }) |
| 701 | .await; | 644 | }); |
| 702 | 645 | ||
| 703 | client.on_response::<StartDebugging, _>(move |_| {}).await; | 646 | 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, |_| {}); | ||
| 705 | // start first child session | 650 | // start first child session |
| 706 | client | 651 | client |
| 707 | .fake_reverse_request::<StartDebugging>(StartDebuggingRequestArguments { | 652 | .fake_reverse_request::<StartDebugging>(StartDebuggingRequestArguments { |
| @@ -729,9 +674,7 @@ async fn test_shutdown_children_when_parent_session_shutdown( · 21 unmodified lines | |||
| 729 | let first_child_client = | 674 | let first_child_client = |
| 730 | first_child_session.update(cx, |session, _| session.adapter_client().unwrap()); | 675 | first_child_session.update(cx, |session, _| session.adapter_client().unwrap()); |
| 731 | 676 | ||
| 732 | first_child_client | 677 | first_child_client.on_request::<Disconnect, _>(move |_, _| Ok(())); |
| 733 | .on_request::<Disconnect, _>(move |_, _| Ok(())) | ||
| 734 | .await; | ||
| 735 | 678 | ||
| 736 | // configure second child session | 679 | // configure second child session |
| 737 | let second_child_session = dap_store.read_with(cx, |dap_store, _| { | 680 | 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 | |||
| 740 | let second_child_client = | 683 | let second_child_client = |
| 741 | second_child_session.update(cx, |session, _| session.adapter_client().unwrap()); | 684 | second_child_session.update(cx, |session, _| session.adapter_client().unwrap()); |
| 742 | 685 | ||
| 743 | second_child_client | 686 | second_child_client.on_request::<Disconnect, _>(move |_, _| Ok(())); |
| 744 | .on_request::<Disconnect, _>(move |_, _| Ok(())) | ||
| 745 | .await; | ||
| 746 | 687 | ||
| 747 | cx.run_until_parked(); | 688 | cx.run_until_parked(); |
| 748 | 689 | ||
| @@ -796,20 +737,15 @@ async fn test_shutdown_parent_session_if_all_children_are_shutdown( · 47 unmodified lines | |||
| 796 | let workspace = init_test_workspace(&project, cx).await; | 737 | let workspace = init_test_workspace(&project, cx).await; |
| 797 | let cx = &mut VisualTestContext::from_window(*workspace, cx); | 738 | let cx = &mut VisualTestContext::from_window(*workspace, cx); |
| 798 | 739 | ||
| 799 | let task = project.update(cx, |project, cx| { | 740 | let parent_session = debugger::test::start_debug_session(&project, cx, |_| {}) |
| 800 | project.fake_debug_session( | 741 | .await |
| 801 | dap::DebugRequestType::Launch(LaunchConfig::default()), | 742 | .unwrap(); |
| 802 | None, | ||
| 803 | false, | ||
| 804 | cx, | ||
| 805 | ) | ||
| 806 | }); | ||
| 807 | |||
| 808 | let parent_session = task.await.unwrap(); | ||
| 809 | let client = parent_session.update(cx, |session, _| session.adapter_client().unwrap()); | 743 | let client = parent_session.update(cx, |session, _| session.adapter_client().unwrap()); |
| 810 | 744 | ||
| 811 | client.on_response::<StartDebugging, _>(move |_| {}).await; | 745 | 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, |_| {}); | ||
| 813 | // start first child session | 749 | // start first child session |
| 814 | client | 750 | client |
| 815 | .fake_reverse_request::<StartDebugging>(StartDebuggingRequestArguments { | 751 | .fake_reverse_request::<StartDebugging>(StartDebuggingRequestArguments { |
| @@ -837,9 +773,7 @@ async fn test_shutdown_parent_session_if_all_children_are_shutdown( · 21 unmodified lines | |||
| 837 | let first_child_client = | 773 | let first_child_client = |
| 838 | first_child_session.update(cx, |session, _| session.adapter_client().unwrap()); | 774 | first_child_session.update(cx, |session, _| session.adapter_client().unwrap()); |
| 839 | 775 | ||
| 840 | first_child_client | 776 | first_child_client.on_request::<Disconnect, _>(move |_, _| Ok(())); |
| 841 | .on_request::<Disconnect, _>(move |_, _| Ok(())) | ||
| 842 | .await; | ||
| 843 | 777 | ||
| 844 | // configure second child session | 778 | // configure second child session |
| 845 | let second_child_session = dap_store.read_with(cx, |dap_store, _| { | 779 | 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 | |||
| 848 | let second_child_client = | 782 | let second_child_client = |
| 849 | second_child_session.update(cx, |session, _| session.adapter_client().unwrap()); | 783 | second_child_session.update(cx, |session, _| session.adapter_client().unwrap()); |
| 850 | 784 | ||
| 851 | second_child_client | 785 | second_child_client.on_request::<Disconnect, _>(move |_, _| Ok(())); |
| 852 | .on_request::<Disconnect, _>(move |_, _| Ok(())) | ||
| 853 | .await; | ||
| 854 | 786 | ||
| 855 | cx.run_until_parked(); | 787 | cx.run_until_parked(); |
| 856 | 788 | ||
| @@ -926,123 +858,107 @@ async fn test_debug_panel_item_thread_status_reset_on_failure( · 69 unmodified lines | |||
| 926 | let workspace = init_test_workspace(&project, cx).await; | 858 | let workspace = init_test_workspace(&project, cx).await; |
| 927 | let cx = &mut VisualTestContext::from_window(*workspace, cx); | 859 | let cx = &mut VisualTestContext::from_window(*workspace, cx); |
| 928 | 860 | ||
| 929 | let task = project.update(cx, |project, cx| { | 861 | let session = debugger::test::start_debug_session(&project, cx, |client| { |
| 930 | project.fake_debug_session( | 862 | client.on_request::<dap::requests::Initialize, _>(move |_, _| { |
| 931 | dap::DebugRequestType::Launch(LaunchConfig::default()), | 863 | Ok(dap::Capabilities { |
| 932 | Some(dap::Capabilities { | ||
| 933 | supports_step_back: Some(true), | 864 | supports_step_back: Some(true), |
| 934 | ..Default::default() | 865 | ..Default::default() |
| 935 | }), | 866 | }) |
| 936 | false, | 867 | }); |
| 937 | cx, | 868 | }) |
| 938 | ) | 869 | .await |
| 939 | }); | 870 | .unwrap(); |
| 940 | 871 | ||
| 941 | let session = task.await.unwrap(); | ||
| 942 | let client = session.update(cx, |session, _| session.adapter_client().unwrap()); | 872 | let client = session.update(cx, |session, _| session.adapter_client().unwrap()); |
| 943 | const THREAD_ID_NUM: u64 = 1; | 873 | const THREAD_ID_NUM: u64 = 1; |
| 944 | 874 | ||
| 945 | client | 875 | client.on_request::<dap::requests::Threads, _>(move |_, _| { |
| 946 | .on_request::<dap::requests::Threads, _>(move |_, _| { | 876 | Ok(dap::ThreadsResponse { |
| 947 | Ok(dap::ThreadsResponse { | 877 | threads: vec![dap::Thread { |
| 948 | threads: vec![dap::Thread { | 878 | id: THREAD_ID_NUM, |
| 949 | id: THREAD_ID_NUM, | 879 | name: "Thread 1".into(), |
| 950 | name: "Thread 1".into(), | 880 | }], |
| 951 | }], | ||
| 952 | }) | ||
| 953 | }) | 881 | }) |
| 954 | .await; | 882 | }); |
| 955 | 883 | ||
| 956 | client.on_request::<Launch, _>(move |_, _| Ok(())).await; | 884 | client.on_request::<Launch, _>(move |_, _| Ok(())); |
| 957 | 885 | ||
| 958 | client | 886 | client.on_request::<StackTrace, _>(move |_, _| { |
| 959 | .on_request::<StackTrace, _>(move |_, _| { | 887 | Ok(dap::StackTraceResponse { |
| 960 | Ok(dap::StackTraceResponse { | 888 | stack_frames: Vec::default(), |
| 961 | stack_frames: Vec::default(), | 889 | total_frames: None, |
| 962 | total_frames: None, | ||
| 963 | }) | ||
| 964 | }) | 890 | }) |
| 965 | .await; | 891 | }); |
| 966 | 892 | ||
| 967 | client | 893 | client.on_request::<Next, _>(move |_, _| { |
| 968 | .on_request::<Next, _>(move |_, _| { | 894 | Err(ErrorResponse { |
| 969 | Err(ErrorResponse { | 895 | error: Some(dap::Message { |
| 970 | error: Some(dap::Message { | 896 | id: 1, |
| 971 | id: 1, | 897 | format: "error".into(), |
| 972 | format: "error".into(), | 898 | variables: None, |
| 973 | variables: None, | 899 | send_telemetry: None, |
| 974 | send_telemetry: None, | 900 | show_user: None, |
| 975 | show_user: None, | 901 | url: None, |
| 976 | url: None, | 902 | url_label: None, |
| 977 | url_label: None, | 903 | }), |
| 978 | }), | ||
| 979 | }) | ||
| 980 | }) | 904 | }) |
| 981 | .await; | 905 | }); |
| 982 | 906 | ||
| 983 | client | 907 | client.on_request::<StepOut, _>(move |_, _| { |
| 984 | .on_request::<StepOut, _>(move |_, _| { | 908 | Err(ErrorResponse { |
| 985 | Err(ErrorResponse { | 909 | error: Some(dap::Message { |
| 986 | error: Some(dap::Message { | 910 | id: 1, |
| 987 | id: 1, | 911 | format: "error".into(), |
| 988 | format: "error".into(), | 912 | variables: None, |
| 989 | variables: None, | 913 | send_telemetry: None, |
| 990 | send_telemetry: None, | 914 | show_user: None, |
| 991 | show_user: None, | 915 | url: None, |
| 992 | url: None, | 916 | url_label: None, |
| 993 | url_label: None, | 917 | }), |
| 994 | }), | ||
| 995 | }) | ||
| 996 | }) | 918 | }) |
| 997 | .await; | 919 | }); |
| 998 | 920 | ||
| 999 | client | 921 | client.on_request::<StepIn, _>(move |_, _| { |
| 1000 | .on_request::<StepIn, _>(move |_, _| { | 922 | Err(ErrorResponse { |
| 1001 | Err(ErrorResponse { | 923 | error: Some(dap::Message { |
| 1002 | error: Some(dap::Message { | 924 | id: 1, |
| 1003 | id: 1, | 925 | format: "error".into(), |
| 1004 | format: "error".into(), | 926 | variables: None, |
| 1005 | variables: None, | 927 | send_telemetry: None, |
| 1006 | send_telemetry: None, | 928 | show_user: None, |
| 1007 | show_user: None, | 929 | url: None, |
| 1008 | url: None, | 930 | url_label: None, |
| 1009 | url_label: None, | 931 | }), |
| 1010 | }), | ||
| 1011 | }) | ||
| 1012 | }) | 932 | }) |
| 1013 | .await; | 933 | }); |
| 1014 | 934 | ||
| 1015 | client | 935 | client.on_request::<StepBack, _>(move |_, _| { |
| 1016 | .on_request::<StepBack, _>(move |_, _| { | 936 | Err(ErrorResponse { |
| 1017 | Err(ErrorResponse { | 937 | error: Some(dap::Message { |
| 1018 | error: Some(dap::Message { | 938 | id: 1, |
| 1019 | id: 1, | 939 | format: "error".into(), |
| 1020 | format: "error".into(), | 940 | variables: None, |
| 1021 | variables: None, | 941 | send_telemetry: None, |
| 1022 | send_telemetry: None, | 942 | show_user: None, |
| 1023 | show_user: None, | 943 | url: None, |
| 1024 | url: None, | 944 | url_label: None, |
| 1025 | url_label: None, | 945 | }), |
| 1026 | }), | ||
| 1027 | }) | ||
| 1028 | }) | 946 | }) |
| 1029 | .await; | 947 | }); |
| 1030 | 948 | ||
| 1031 | client | 949 | client.on_request::<Continue, _>(move |_, _| { |
| 1032 | .on_request::<Continue, _>(move |_, _| { | 950 | Err(ErrorResponse { |
| 1033 | Err(ErrorResponse { | 951 | error: Some(dap::Message { |
| 1034 | error: Some(dap::Message { | 952 | id: 1, |
| 1035 | id: 1, | 953 | format: "error".into(), |
| 1036 | format: "error".into(), | 954 | variables: None, |
| 1037 | variables: None, | 955 | send_telemetry: None, |
| 1038 | send_telemetry: None, | 956 | show_user: None, |
| 1039 | show_user: None, | 957 | url: None, |
| 1040 | url: None, | 958 | url_label: None, |
| 1041 | url_label: None, | 959 | }), |
| 1042 | }), | ||
| 1043 | }) | ||
| 1044 | }) | 960 | }) |
| 1045 | .await; | 961 | }); |
| 1046 | 962 | ||
| 1047 | client | 963 | client |
| 1048 | .fake_event(dap::messages::Events::Stopped(dap::StoppedEvent { | 964 | .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 | |||
| 1157 | .update(cx, |_, _, cx| worktree.read(cx).id()) | 1073 | .update(cx, |_, _, cx| worktree.read(cx).id()) |
| 1158 | .unwrap(); | 1074 | .unwrap(); |
| 1159 | 1075 | ||
| 1160 | let task = project.update(cx, |project, cx| { | 1076 | let session = debugger::test::start_debug_session(&project, cx, |_| {}) |
| 1161 | project.fake_debug_session( | 1077 | .await |
| 1162 | dap::DebugRequestType::Launch(LaunchConfig::default()), | 1078 | .unwrap(); |
| 1163 | None, | ||
| 1164 | false, | ||
| 1165 | cx, | ||
| 1166 | ) | ||
| 1167 | }); | ||
| 1168 | |||
| 1169 | let session = task.await.unwrap(); | ||
| 1170 | let client = session.update(cx, |session, _| session.adapter_client().unwrap()); | 1079 | let client = session.update(cx, |session, _| session.adapter_client().unwrap()); |
| 1171 | 1080 | ||
| 1172 | let buffer = project | 1081 | let buffer = project |
| @@ -1186,16 +1095,14 @@ async fn test_send_breakpoints_when_editor_has_been_saved( · 13 unmodified lines | |||
| 1186 | ) | 1095 | ) |
| 1187 | }); | 1096 | }); |
| 1188 | 1097 | ||
| 1189 | client.on_request::<Launch, _>(move |_, _| Ok(())).await; | 1098 | client.on_request::<Launch, _>(move |_, _| Ok(())); |
| 1190 | 1099 | ||
| 1191 | client | 1100 | client.on_request::<StackTrace, _>(move |_, _| { |
| 1192 | .on_request::<StackTrace, _>(move |_, _| { | 1101 | Ok(dap::StackTraceResponse { |
| 1193 | Ok(dap::StackTraceResponse { | 1102 | stack_frames: Vec::default(), |
| 1194 | stack_frames: Vec::default(), | 1103 | total_frames: None, |
| 1195 | total_frames: None, | ||
| 1196 | }) | ||
| 1197 | }) | 1104 | }) |
| 1198 | .await; | 1105 | }); |
| 1199 | 1106 | ||
| 1200 | client | 1107 | client |
| 1201 | .fake_event(dap::messages::Events::Stopped(dap::StoppedEvent { | 1108 | .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 | |||
| 1210 | .await; | 1117 | .await; |
| 1211 | 1118 | ||
| 1212 | let called_set_breakpoints = Arc::new(AtomicBool::new(false)); | 1119 | let called_set_breakpoints = Arc::new(AtomicBool::new(false)); |
| 1213 | client | 1120 | client.on_request::<SetBreakpoints, _>({ |
| 1214 | .on_request::<SetBreakpoints, _>({ | 1121 | let called_set_breakpoints = called_set_breakpoints.clone(); |
| 1215 | let called_set_breakpoints = called_set_breakpoints.clone(); | 1122 | move |_, args| { |
| 1216 | move |_, args| { | 1123 | assert_eq!(path!("/project/main.rs"), args.source.path.unwrap()); |
| 1217 | assert_eq!(path!("/project/main.rs"), args.source.path.unwrap()); | 1124 | assert_eq!( |
| 1218 | assert_eq!( | 1125 | vec![SourceBreakpoint { |
| 1219 | vec![SourceBreakpoint { | 1126 | line: 2, |
| 1220 | line: 2, | 1127 | column: None, |
| 1221 | column: None, | 1128 | condition: None, |
| 1222 | condition: None, | 1129 | hit_condition: None, |
| 1223 | hit_condition: None, | 1130 | log_message: None, |
| 1224 | log_message: None, | 1131 | mode: None |
| 1225 | mode: None | 1132 | }], |
| 1226 | }], | 1133 | args.breakpoints.unwrap() |
| 1227 | args.breakpoints.unwrap() | 1134 | ); |
| 1228 | ); | 1135 | assert!(!args.source_modified.unwrap()); |
| 1229 | assert!(!args.source_modified.unwrap()); | ||
| 1230 | 1136 | ||
| 1231 | called_set_breakpoints.store(true, Ordering::SeqCst); | 1137 | called_set_breakpoints.store(true, Ordering::SeqCst); |
| 1232 | 1138 | ||
| 1233 | Ok(dap::SetBreakpointsResponse { | 1139 | Ok(dap::SetBreakpointsResponse { |
| 1234 | breakpoints: Vec::default(), | 1140 | breakpoints: Vec::default(), |
| 1235 | }) | 1141 | }) |
| 1236 | } | 1142 | } |
| 1237 | }) | 1143 | }); |
| 1238 | .await; | ||
| 1239 | 1144 | ||
| 1240 | editor.update_in(cx, |editor, window, cx| { | 1145 | editor.update_in(cx, |editor, window, cx| { |
| 1241 | editor.move_down(&actions::MoveDown, window, cx); | 1146 | editor.move_down(&actions::MoveDown, window, cx); |
| @@ -1250,32 +1155,30 @@ async fn test_send_breakpoints_when_editor_has_been_saved( · 8 unmodified lines | |||
| 1250 | ); | 1155 | ); |
| 1251 | 1156 | ||
| 1252 | let called_set_breakpoints = Arc::new(AtomicBool::new(false)); | 1157 | let called_set_breakpoints = Arc::new(AtomicBool::new(false)); |
| 1253 | client | 1158 | client.on_request::<SetBreakpoints, _>({ |
| 1254 | .on_request::<SetBreakpoints, _>({ | 1159 | let called_set_breakpoints = called_set_breakpoints.clone(); |
| 1255 | let called_set_breakpoints = called_set_breakpoints.clone(); | 1160 | move |_, args| { |
| 1256 | move |_, args| { | 1161 | assert_eq!(path!("/project/main.rs"), args.source.path.unwrap()); |
| 1257 | assert_eq!(path!("/project/main.rs"), args.source.path.unwrap()); | 1162 | assert_eq!( |
| 1258 | assert_eq!( | 1163 | vec![SourceBreakpoint { |
| 1259 | vec![SourceBreakpoint { | 1164 | line: 3, |
| 1260 | line: 3, | 1165 | column: None, |
| 1261 | column: None, | 1166 | condition: None, |
| 1262 | condition: None, | 1167 | hit_condition: None, |
| 1263 | hit_condition: None, | 1168 | log_message: None, |
| 1264 | log_message: None, | 1169 | mode: None |
| 1265 | mode: None | 1170 | }], |
| 1266 | }], | 1171 | args.breakpoints.unwrap() |
| 1267 | args.breakpoints.unwrap() | 1172 | ); |
| 1268 | ); | 1173 | assert!(args.source_modified.unwrap()); |
| 1269 | assert!(args.source_modified.unwrap()); | ||
| 1270 | 1174 | ||
| 1271 | called_set_breakpoints.store(true, Ordering::SeqCst); | 1175 | called_set_breakpoints.store(true, Ordering::SeqCst); |
| 1272 | 1176 | ||
| 1273 | Ok(dap::SetBreakpointsResponse { | 1177 | Ok(dap::SetBreakpointsResponse { |
| 1274 | breakpoints: Vec::default(), | 1178 | breakpoints: Vec::default(), |
| 1275 | }) | 1179 | }) |
| 1276 | } | 1180 | } |
| 1277 | }) | 1181 | }); |
| 1278 | .await; | ||
| 1279 | 1182 | ||
| 1280 | editor.update_in(cx, |editor, window, cx| { | 1183 | editor.update_in(cx, |editor, window, cx| { |
| 1281 | editor.move_up(&actions::MoveUp, window, cx); | 1184 | editor.move_up(&actions::MoveUp, window, cx); |
| @@ -1387,49 +1290,40 @@ async fn test_unsetting_breakpoints_on_clear_breakpoint_action( · 105 unmodified lines | |||
| 1387 | editor.toggle_breakpoint(&actions::ToggleBreakpoint, window, cx); | 1290 | editor.toggle_breakpoint(&actions::ToggleBreakpoint, window, cx); |
| 1388 | }); | 1291 | }); |
| 1389 | 1292 | ||
| 1390 | let task = project.update(cx, |project, cx| { | 1293 | let session = debugger::test::start_debug_session(&project, cx, |_| {}) |
| 1391 | project.fake_debug_session( | 1294 | .await |
| 1392 | dap::DebugRequestType::Launch(LaunchConfig::default()), | 1295 | .unwrap(); |
| 1393 | None, | ||
| 1394 | false, | ||
| 1395 | cx, | ||
| 1396 | ) | ||
| 1397 | }); | ||
| 1398 | |||
| 1399 | let session = task.await.unwrap(); | ||
| 1400 | let client = session.update(cx, |session, _| session.adapter_client().unwrap()); | 1296 | let client = session.update(cx, |session, _| session.adapter_client().unwrap()); |
| 1401 | 1297 | ||
| 1402 | let called_set_breakpoints = Arc::new(AtomicBool::new(false)); | 1298 | let called_set_breakpoints = Arc::new(AtomicBool::new(false)); |
| 1403 | 1299 | ||
| 1404 | client | 1300 | client.on_request::<SetBreakpoints, _>({ |
| 1405 | .on_request::<SetBreakpoints, _>({ | 1301 | let called_set_breakpoints = called_set_breakpoints.clone(); |
| 1406 | let called_set_breakpoints = called_set_breakpoints.clone(); | 1302 | move |_, args| { |
| 1407 | move |_, args| { | 1303 | assert!( |
| 1408 | assert!( | 1304 | args.breakpoints.is_none_or(|bps| bps.is_empty()), |
| 1409 | args.breakpoints.is_none_or(|bps| bps.is_empty()), | 1305 | "Send empty breakpoint sets to clear them from DAP servers" |
| 1410 | "Send empty breakpoint sets to clear them from DAP servers" | 1306 | ); |
| 1411 | ); | ||
| 1412 | 1307 | ||
| 1413 | match args | 1308 | match args |
| 1414 | .source | 1309 | .source |
| 1415 | .path | 1310 | .path |
| 1416 | .expect("We should always send a breakpoint's path") | 1311 | .expect("We should always send a breakpoint's path") |
| 1417 | .as_str() | 1312 | .as_str() |
| 1418 | { | 1313 | { |
| 1419 | "/project/main.rs" | "/project/second.rs" => {} | 1314 | "/project/main.rs" | "/project/second.rs" => {} |
| 1420 | _ => { | 1315 | _ => { |
| 1421 | panic!("Unset breakpoints for path that doesn't have any") | 1316 | panic!("Unset breakpoints for path that doesn't have any") |
| 1422 | } | ||
| 1423 | } | 1317 | } |
| 1318 | } | ||
| 1424 | 1319 | ||
| 1425 | called_set_breakpoints.store(true, Ordering::SeqCst); | 1320 | called_set_breakpoints.store(true, Ordering::SeqCst); |
| 1426 | 1321 | ||
| 1427 | Ok(dap::SetBreakpointsResponse { | 1322 | Ok(dap::SetBreakpointsResponse { |
| 1428 | breakpoints: Vec::default(), | 1323 | breakpoints: Vec::default(), |
| 1429 | }) | 1324 | }) |
| 1430 | } | 1325 | } |
| 1431 | }) | 1326 | }); |
| 1432 | .await; | ||
| 1433 | 1327 | ||
| 1434 | cx.dispatch_action(crate::ClearAllBreakpoints); | 1328 | cx.dispatch_action(crate::ClearAllBreakpoints); |
| 1435 | cx.run_until_parked(); | 1329 | cx.run_until_parked(); |
| @@ -1464,13 +1358,20 @@ async fn test_debug_session_is_shutdown_when_attach_and_launch_request_fails( · 28 unmodified lines | |||
| 1464 | let workspace = init_test_workspace(&project, cx).await; | 1358 | let workspace = init_test_workspace(&project, cx).await; |
| 1465 | let cx = &mut VisualTestContext::from_window(*workspace, cx); | 1359 | let cx = &mut VisualTestContext::from_window(*workspace, cx); |
| 1466 | 1360 | ||
| 1467 | let task = project.update(cx, |project, cx| { | 1361 | let task = project::debugger::test::start_debug_session(&project, cx, |client| { |
| 1468 | project.fake_debug_session( | 1362 | client.on_request::<dap::requests::Initialize, _>(|_, _| { |
| 1469 | dap::DebugRequestType::Launch(LaunchConfig::default()), | 1363 | Err(ErrorResponse { |
| 1470 | None, | 1364 | error: Some(Message { |
| 1471 | true, | 1365 | format: "failed to launch".to_string(), |
| 1472 | cx, | 1366 | id: 1, |
| 1473 | ) | 1367 | variables: None, |
| 1368 | send_telemetry: None, | ||
| 1369 | show_user: None, | ||
| 1370 | url: None, | ||
| 1371 | url_label: None, | ||
| 1372 | }), | ||
| 1373 | }) | ||
| 1374 | }); | ||
| 1474 | }); | 1375 | }); |
| 1475 | 1376 | ||
| 1476 | assert!( | 1377 | assert!( |
| @@ -4,15 +4,17 @@ use crate::{ · 3 unmodified lines | |||
| 4 | }; | 4 | }; |
| 5 | use dap::{ | 5 | use dap::{ |
| 6 | StoppedEvent, | 6 | StoppedEvent, |
| 7 | requests::{Modules, StackTrace, Threads}, | 7 | requests::{Initialize, Modules}, |
| 8 | }; | 8 | }; |
| 9 | use gpui::{BackgroundExecutor, TestAppContext, VisualTestContext}; | 9 | use gpui::{BackgroundExecutor, TestAppContext, VisualTestContext}; |
| 10 | use project::{FakeFs, Project}; | 10 | use project::{ |
| 11 | FakeFs, Project, | ||
| 12 | debugger::{self}, | ||
| 13 | }; | ||
| 11 | use std::sync::{ | 14 | use std::sync::{ |
| 12 | Arc, | 15 | Arc, |
| 13 | atomic::{AtomicBool, AtomicI32, Ordering}, | 16 | atomic::{AtomicBool, AtomicI32, Ordering}, |
| 14 | }; | 17 | }; |
| 15 | use task::LaunchConfig; | ||
| 16 | 18 | ||
| 17 | #[gpui::test] | 19 | #[gpui::test] |
| 18 | async fn test_module_list(executor: BackgroundExecutor, cx: &mut TestAppContext) { | 20 | 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 | |||
| 29 | .unwrap(); | 31 | .unwrap(); |
| 30 | let cx = &mut VisualTestContext::from_window(*workspace, cx); | 32 | let cx = &mut VisualTestContext::from_window(*workspace, cx); |
| 31 | 33 | ||
| 32 | let task = project.update(cx, |project, cx| { | 34 | let session = debugger::test::start_debug_session(&project, cx, |client| { |
| 33 | project.fake_debug_session( | 35 | client.on_request::<Initialize, _>(move |_, _| { |
| 34 | dap::DebugRequestType::Launch(LaunchConfig::default()), | 36 | Ok(dap::Capabilities { |
| 35 | Some(dap::Capabilities { | ||
| 36 | supports_modules_request: Some(true), | 37 | supports_modules_request: Some(true), |
| 37 | ..Default::default() | 38 | ..Default::default() |
| 38 | }), | 39 | }) |
| 39 | false, | 40 | }); |
| 40 | cx, | 41 | }) |
| 41 | ) | 42 | .await |
| 42 | }); | 43 | .unwrap(); |
| 43 | 44 | ||
| 44 | let session = task.await.unwrap(); | ||
| 45 | let client = session.update(cx, |session, _| session.adapter_client().unwrap()); | 45 | let client = session.update(cx, |session, _| session.adapter_client().unwrap()); |
| 46 | 46 | ||
| 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 | |||
| 57 | let called_modules = Arc::new(AtomicBool::new(false)); | 47 | let called_modules = Arc::new(AtomicBool::new(false)); |
| 58 | let modules = vec![ | 48 | let modules = vec![ |
| 59 | dap::Module { | 49 | dap::Module { |
| @@ -82,38 +72,25 @@ async fn test_module_list(executor: BackgroundExecutor, cx: &mut TestAppContext) · 22 unmodified lines | |||
| 82 | }, | 72 | }, |
| 83 | ]; | 73 | ]; |
| 84 | 74 | ||
| 85 | client | 75 | client.on_request::<Modules, _>({ |
| 86 | .on_request::<Threads, _>(move |_, _| { | 76 | let called_modules = called_modules.clone(); |
| 87 | Ok(dap::ThreadsResponse { | 77 | let modules_request_count = AtomicI32::new(0); |
| 88 | threads: vec![dap::Thread { | 78 | let modules = modules.clone(); |
| 89 | id: 1, | 79 | move |_, _| { |
| 90 | name: "Thread 1".into(), | 80 | modules_request_count.fetch_add(1, Ordering::SeqCst); |
| 91 | }], | 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), | ||
| 92 | }) | 91 | }) |
| 93 | }) | 92 | } |
| 94 | .await; | 93 | }); |
| 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; | ||
| 117 | 94 | ||
| 118 | client | 95 | client |
| 119 | .fake_event(dap::messages::Events::Stopped(StoppedEvent { | 96 | .fake_event(dap::messages::Events::Stopped(StoppedEvent { |
| @@ -5,14 +5,13 @@ use crate::{ · 4 unmodified lines | |||
| 5 | }; | 5 | }; |
| 6 | use dap::{ | 6 | use dap::{ |
| 7 | StackFrame, | 7 | StackFrame, |
| 8 | requests::{StackTrace, Threads}, | 8 | requests::{Scopes, StackTrace, Threads}, |
| 9 | }; | 9 | }; |
| 10 | use editor::{Editor, ToPoint as _}; | 10 | use editor::{Editor, ToPoint as _}; |
| 11 | use gpui::{BackgroundExecutor, TestAppContext, VisualTestContext}; | 11 | use gpui::{BackgroundExecutor, TestAppContext, VisualTestContext}; |
| 12 | use project::{FakeFs, Project}; | 12 | use project::{FakeFs, Project, debugger}; |
| 13 | use serde_json::json; | 13 | use serde_json::json; |
| 14 | use std::sync::Arc; | 14 | use std::sync::Arc; |
| 15 | use task::LaunchConfig; | ||
| 16 | use unindent::Unindent as _; | 15 | use unindent::Unindent as _; |
| 17 | use util::path; | 16 | use util::path; |
| 18 | 17 | ||
| @@ -51,29 +50,20 @@ async fn test_fetch_initial_stack_frames_and_go_to_stack_frame( · 32 unmodified lines | |||
| 51 | let project = Project::test(fs, [path!("/project").as_ref()], cx).await; | 50 | let project = Project::test(fs, [path!("/project").as_ref()], cx).await; |
| 52 | let workspace = init_test_workspace(&project, cx).await; | 51 | let workspace = init_test_workspace(&project, cx).await; |
| 53 | let cx = &mut VisualTestContext::from_window(*workspace, cx); | 52 | let cx = &mut VisualTestContext::from_window(*workspace, cx); |
| 54 | 53 | let session = debugger::test::start_debug_session(&project, cx, |_| {}) | |
| 55 | let task = project.update(cx, |project, cx| { | 54 | .await |
| 56 | project.fake_debug_session( | 55 | .unwrap(); |
| 57 | dap::DebugRequestType::Launch(LaunchConfig::default()), | ||
| 58 | None, | ||
| 59 | false, | ||
| 60 | cx, | ||
| 61 | ) | ||
| 62 | }); | ||
| 63 | |||
| 64 | let session = task.await.unwrap(); | ||
| 65 | let client = session.update(cx, |session, _| session.adapter_client().unwrap()); | 56 | let client = session.update(cx, |session, _| session.adapter_client().unwrap()); |
| 66 | 57 | client.on_request::<Scopes, _>(move |_, _| Ok(dap::ScopesResponse { scopes: vec![] })); | |
| 67 | client | 58 | |
| 68 | .on_request::<Threads, _>(move |_, _| { | 59 | client.on_request::<Threads, _>(move |_, _| { |
| 69 | Ok(dap::ThreadsResponse { | 60 | Ok(dap::ThreadsResponse { |
| 70 | threads: vec![dap::Thread { | 61 | threads: vec![dap::Thread { |
| 71 | id: 1, | 62 | id: 1, |
| 72 | name: "Thread 1".into(), | 63 | name: "Thread 1".into(), |
| 73 | }], | 64 | }], |
| 74 | }) | ||
| 75 | }) | 65 | }) |
| 76 | .await; | 66 | }); |
| 77 | 67 | ||
| 78 | let stack_frames = vec![ | 68 | let stack_frames = vec![ |
| 79 | StackFrame { | 69 | StackFrame { |
| @@ -122,19 +112,17 @@ async fn test_fetch_initial_stack_frames_and_go_to_stack_frame( · 42 unmodified lines | |||
| 122 | }, | 112 | }, |
| 123 | ]; | 113 | ]; |
| 124 | 114 | ||
| 125 | client | 115 | client.on_request::<StackTrace, _>({ |
| 126 | .on_request::<StackTrace, _>({ | 116 | let stack_frames = Arc::new(stack_frames.clone()); |
| 127 | let stack_frames = Arc::new(stack_frames.clone()); | 117 | move |_, args| { |
| 128 | move |_, args| { | 118 | assert_eq!(1, args.thread_id); |
| 129 | assert_eq!(1, args.thread_id); | 119 | |
| 130 | 120 | Ok(dap::StackTraceResponse { | |
| 131 | Ok(dap::StackTraceResponse { | 121 | stack_frames: (*stack_frames).clone(), |
| 132 | stack_frames: (*stack_frames).clone(), | 122 | total_frames: None, |
| 133 | total_frames: None, | 123 | }) |
| 134 | }) | 124 | } |
| 135 | } | 125 | }); |
| 136 | }) | ||
| 137 | .await; | ||
| 138 | 126 | ||
| 139 | client | 127 | client |
| 140 | .fake_event(dap::messages::Events::Stopped(dap::StoppedEvent { | 128 | .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 | |||
| 241 | }); | 229 | }); |
| 242 | 230 | ||
| 243 | let cx = &mut VisualTestContext::from_window(*workspace, cx); | 231 | let cx = &mut VisualTestContext::from_window(*workspace, cx); |
| 244 | 232 | let session = debugger::test::start_debug_session(&project, cx, |_| {}) | |
| 245 | let task = project.update(cx, |project, cx| { | 233 | .await |
| 246 | project.fake_debug_session( | 234 | .unwrap(); |
| 247 | dap::DebugRequestType::Launch(LaunchConfig::default()), | ||
| 248 | None, | ||
| 249 | false, | ||
| 250 | cx, | ||
| 251 | ) | ||
| 252 | }); | ||
| 253 | |||
| 254 | let session = task.await.unwrap(); | ||
| 255 | let client = session.update(cx, |session, _| session.adapter_client().unwrap()); | 235 | let client = session.update(cx, |session, _| session.adapter_client().unwrap()); |
| 256 | 236 | ||
| 257 | client | 237 | client.on_request::<Threads, _>(move |_, _| { |
| 258 | .on_request::<Threads, _>(move |_, _| { | 238 | Ok(dap::ThreadsResponse { |
| 259 | Ok(dap::ThreadsResponse { | 239 | threads: vec![dap::Thread { |
| 260 | threads: vec![dap::Thread { | 240 | id: 1, |
| 261 | id: 1, | 241 | name: "Thread 1".into(), |
| 262 | name: "Thread 1".into(), | 242 | }], |
| 263 | }], | ||
| 264 | }) | ||
| 265 | }) | 243 | }) |
| 266 | .await; | 244 | }); |
| 245 | |||
| 246 | client.on_request::<Scopes, _>(move |_, _| Ok(dap::ScopesResponse { scopes: vec![] })); | ||
| 267 | 247 | ||
| 268 | let stack_frames = vec![ | 248 | let stack_frames = vec![ |
| 269 | StackFrame { | 249 | StackFrame { |
| @@ -312,19 +292,17 @@ async fn test_select_stack_frame(executor: BackgroundExecutor, cx: &mut TestAppC · 42 unmodified lines | |||
| 312 | }, | 292 | }, |
| 313 | ]; | 293 | ]; |
| 314 | 294 | ||
| 315 | client | 295 | client.on_request::<StackTrace, _>({ |
| 316 | .on_request::<StackTrace, _>({ | 296 | let stack_frames = Arc::new(stack_frames.clone()); |
| 317 | let stack_frames = Arc::new(stack_frames.clone()); | 297 | move |_, args| { |
| 318 | move |_, args| { | 298 | assert_eq!(1, args.thread_id); |
| 319 | assert_eq!(1, args.thread_id); | 299 | |
| 320 | 300 | Ok(dap::StackTraceResponse { | |
| 321 | Ok(dap::StackTraceResponse { | 301 | stack_frames: (*stack_frames).clone(), |
| 322 | stack_frames: (*stack_frames).clone(), | 302 | total_frames: None, |
| 323 | total_frames: None, | 303 | }) |
| 324 | }) | 304 | } |
| 325 | } | 305 | }); |
| 326 | }) | ||
| 327 | .await; | ||
| 328 | 306 | ||
| 329 | client | 307 | client |
| 330 | .fake_event(dap::messages::Events::Stopped(dap::StoppedEvent { | 308 | .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 | |||
| 517 | let workspace = init_test_workspace(&project, cx).await; | 495 | let workspace = init_test_workspace(&project, cx).await; |
| 518 | let cx = &mut VisualTestContext::from_window(*workspace, cx); | 496 | let cx = &mut VisualTestContext::from_window(*workspace, cx); |
| 519 | 497 | ||
| 520 | let task = project.update(cx, |project, cx| { | 498 | let session = debugger::test::start_debug_session(&project, cx, |_| {}) |
| 521 | project.fake_debug_session( | 499 | .await |
| 522 | dap::DebugRequestType::Launch(LaunchConfig::default()), | 500 | .unwrap(); |
| 523 | None, | ||
| 524 | false, | ||
| 525 | cx, | ||
| 526 | ) | ||
| 527 | }); | ||
| 528 | |||
| 529 | let session = task.await.unwrap(); | ||
| 530 | let client = session.update(cx, |session, _| session.adapter_client().unwrap()); | 501 | let client = session.update(cx, |session, _| session.adapter_client().unwrap()); |
| 531 | 502 | ||
| 532 | client | 503 | client.on_request::<Threads, _>(move |_, _| { |
| 533 | .on_request::<Threads, _>(move |_, _| { | 504 | Ok(dap::ThreadsResponse { |
| 534 | Ok(dap::ThreadsResponse { | 505 | threads: vec![dap::Thread { |
| 535 | threads: vec![dap::Thread { | 506 | id: 1, |
| 536 | id: 1, | 507 | name: "Thread 1".into(), |
| 537 | name: "Thread 1".into(), | 508 | }], |
| 538 | }], | ||
| 539 | }) | ||
| 540 | }) | 509 | }) |
| 541 | .await; | 510 | }); |
| 511 | |||
| 512 | client.on_request::<Scopes, _>(move |_, _| Ok(dap::ScopesResponse { scopes: vec![] })); | ||
| 542 | 513 | ||
| 543 | let stack_frames = vec![ | 514 | let stack_frames = vec![ |
| 544 | StackFrame { | 515 | StackFrame { |
| @@ -697,19 +668,17 @@ async fn test_collapsed_entries(executor: BackgroundExecutor, cx: &mut TestAppCo · 152 unmodified lines | |||
| 697 | }, | 668 | }, |
| 698 | ]; | 669 | ]; |
| 699 | 670 | ||
| 700 | client | 671 | client.on_request::<StackTrace, _>({ |
| 701 | .on_request::<StackTrace, _>({ | 672 | let stack_frames = Arc::new(stack_frames.clone()); |
| 702 | let stack_frames = Arc::new(stack_frames.clone()); | 673 | move |_, args| { |
| 703 | move |_, args| { | 674 | assert_eq!(1, args.thread_id); |
| 704 | assert_eq!(1, args.thread_id); | 675 | |
| 705 | 676 | Ok(dap::StackTraceResponse { | |
| 706 | Ok(dap::StackTraceResponse { | 677 | stack_frames: (*stack_frames).clone(), |
| 707 | stack_frames: (*stack_frames).clone(), | 678 | total_frames: None, |
| 708 | total_frames: None, | 679 | }) |
| 709 | }) | 680 | } |
| 710 | } | 681 | }); |
| 711 | }) | ||
| 712 | .await; | ||
| 713 | 682 | ||
| 714 | client | 683 | client |
| 715 | .fake_event(dap::messages::Events::Stopped(dap::StoppedEvent { | 684 | .fake_event(dap::messages::Events::Stopped(dap::StoppedEvent { |
| @@ -15,9 +15,8 @@ use dap::{ · 14 unmodified lines | |||
| 15 | }; | 15 | }; |
| 16 | use gpui::{BackgroundExecutor, TestAppContext, VisualTestContext}; | 16 | use gpui::{BackgroundExecutor, TestAppContext, VisualTestContext}; |
| 17 | use menu::{SelectFirst, SelectNext, SelectPrevious}; | 17 | use menu::{SelectFirst, SelectNext, SelectPrevious}; |
| 18 | use project::{FakeFs, Project}; | 18 | use project::{FakeFs, Project, debugger}; |
| 19 | use serde_json::json; | 19 | use serde_json::json; |
| 20 | use task::LaunchConfig; | ||
| 21 | use unindent::Unindent as _; | 20 | use unindent::Unindent as _; |
| 22 | use util::path; | 21 | use util::path; |
| 23 | 22 | ||
| @@ -55,29 +54,19 @@ async fn test_basic_fetch_initial_scope_and_variables( · 31 unmodified lines | |||
| 55 | }) | 54 | }) |
| 56 | .unwrap(); | 55 | .unwrap(); |
| 57 | let cx = &mut VisualTestContext::from_window(*workspace, cx); | 56 | let cx = &mut VisualTestContext::from_window(*workspace, cx); |
| 58 | 57 | let session = debugger::test::start_debug_session(&project, cx, |_| {}) | |
| 59 | let task = project.update(cx, |project, cx| { | 58 | .await |
| 60 | project.fake_debug_session( | 59 | .unwrap(); |
| 61 | dap::DebugRequestType::Launch(LaunchConfig::default()), | ||
| 62 | None, | ||
| 63 | false, | ||
| 64 | cx, | ||
| 65 | ) | ||
| 66 | }); | ||
| 67 | |||
| 68 | let session = task.await.unwrap(); | ||
| 69 | let client = session.update(cx, |session, _| session.adapter_client().unwrap()); | 60 | let client = session.update(cx, |session, _| session.adapter_client().unwrap()); |
| 70 | 61 | ||
| 71 | client | 62 | client.on_request::<dap::requests::Threads, _>(move |_, _| { |
| 72 | .on_request::<dap::requests::Threads, _>(move |_, _| { | 63 | Ok(dap::ThreadsResponse { |
| 73 | Ok(dap::ThreadsResponse { | 64 | threads: vec![dap::Thread { |
| 74 | threads: vec![dap::Thread { | 65 | id: 1, |
| 75 | id: 1, | 66 | name: "Thread 1".into(), |
| 76 | name: "Thread 1".into(), | 67 | }], |
| 77 | }], | ||
| 78 | }) | ||
| 79 | }) | 68 | }) |
| 80 | .await; | 69 | }); |
| 81 | 70 | ||
| 82 | let stack_frames = vec![StackFrame { | 71 | let stack_frames = vec![StackFrame { |
| 83 | id: 1, | 72 | id: 1, |
| @@ -102,19 +91,17 @@ async fn test_basic_fetch_initial_scope_and_variables( · 18 unmodified lines | |||
| 102 | presentation_hint: None, | 91 | presentation_hint: None, |
| 103 | }]; | 92 | }]; |
| 104 | 93 | ||
| 105 | client | 94 | client.on_request::<StackTrace, _>({ |
| 106 | .on_request::<StackTrace, _>({ | 95 | let stack_frames = Arc::new(stack_frames.clone()); |
| 107 | let stack_frames = Arc::new(stack_frames.clone()); | 96 | move |_, args| { |
| 108 | move |_, args| { | 97 | assert_eq!(1, args.thread_id); |
| 109 | assert_eq!(1, args.thread_id); | 98 | |
| 110 | 99 | Ok(dap::StackTraceResponse { | |
| 111 | Ok(dap::StackTraceResponse { | 100 | stack_frames: (*stack_frames).clone(), |
| 112 | stack_frames: (*stack_frames).clone(), | 101 | total_frames: None, |
| 113 | total_frames: None, | 102 | }) |
| 114 | }) | 103 | } |
| 115 | } | 104 | }); |
| 116 | }) | ||
| 117 | .await; | ||
| 118 | 105 | ||
| 119 | let scopes = vec![Scope { | 106 | let scopes = vec![Scope { |
| 120 | name: "Scope 1".into(), | 107 | name: "Scope 1".into(), |
| @@ -130,18 +117,16 @@ async fn test_basic_fetch_initial_scope_and_variables( · 9 unmodified lines | |||
| 130 | end_column: None, | 117 | end_column: None, |
| 131 | }]; | 118 | }]; |
| 132 | 119 | ||
| 133 | client | 120 | client.on_request::<Scopes, _>({ |
| 134 | .on_request::<Scopes, _>({ | 121 | let scopes = Arc::new(scopes.clone()); |
| 135 | let scopes = Arc::new(scopes.clone()); | 122 | move |_, args| { |
| 136 | move |_, args| { | 123 | assert_eq!(1, args.frame_id); |
| 137 | assert_eq!(1, args.frame_id); | ||
| 138 | 124 | ||
| 139 | Ok(dap::ScopesResponse { | 125 | Ok(dap::ScopesResponse { |
| 140 | scopes: (*scopes).clone(), | 126 | scopes: (*scopes).clone(), |
| 141 | }) | 127 | }) |
| 142 | } | 128 | } |
| 143 | }) | 129 | }); |
| 144 | .await; | ||
| 145 | 130 | ||
| 146 | let variables = vec![ | 131 | let variables = vec![ |
| 147 | Variable { | 132 | Variable { |
| @@ -172,18 +157,16 @@ async fn test_basic_fetch_initial_scope_and_variables( · 24 unmodified lines | |||
| 172 | }, | 157 | }, |
| 173 | ]; | 158 | ]; |
| 174 | 159 | ||
| 175 | client | 160 | client.on_request::<Variables, _>({ |
| 176 | .on_request::<Variables, _>({ | 161 | let variables = Arc::new(variables.clone()); |
| 177 | let variables = Arc::new(variables.clone()); | 162 | move |_, args| { |
| 178 | move |_, args| { | 163 | assert_eq!(2, args.variables_reference); |
| 179 | assert_eq!(2, args.variables_reference); | ||
| 180 | 164 | ||
| 181 | Ok(dap::VariablesResponse { | 165 | Ok(dap::VariablesResponse { |
| 182 | variables: (*variables).clone(), | 166 | variables: (*variables).clone(), |
| 183 | }) | 167 | }) |
| 184 | } | 168 | } |
| 185 | }) | 169 | }); |
| 186 | .await; | ||
| 187 | 170 | ||
| 188 | client | 171 | client |
| 189 | .fake_event(dap::messages::Events::Stopped(dap::StoppedEvent { | 172 | .fake_event(dap::messages::Events::Stopped(dap::StoppedEvent { |
| @@ -283,39 +266,28 @@ async fn test_fetch_variables_for_multiple_scopes( · 93 unmodified lines | |||
| 283 | .unwrap(); | 266 | .unwrap(); |
| 284 | let cx = &mut VisualTestContext::from_window(*workspace, cx); | 267 | let cx = &mut VisualTestContext::from_window(*workspace, cx); |
| 285 | 268 | ||
| 286 | let task = project.update(cx, |project, cx| { | 269 | let session = debugger::test::start_debug_session(&project, cx, |_| {}) |
| 287 | project.fake_debug_session( | 270 | .await |
| 288 | dap::DebugRequestType::Launch(LaunchConfig::default()), | 271 | .unwrap(); |
| 289 | None, | ||
| 290 | false, | ||
| 291 | cx, | ||
| 292 | ) | ||
| 293 | }); | ||
| 294 | |||
| 295 | let session = task.await.unwrap(); | ||
| 296 | let client = session.update(cx, |session, _| session.adapter_client().unwrap()); | 272 | let client = session.update(cx, |session, _| session.adapter_client().unwrap()); |
| 297 | 273 | ||
| 298 | client | 274 | client.on_request::<dap::requests::Threads, _>(move |_, _| { |
| 299 | .on_request::<dap::requests::Threads, _>(move |_, _| { | 275 | Ok(dap::ThreadsResponse { |
| 300 | Ok(dap::ThreadsResponse { | 276 | threads: vec![dap::Thread { |
| 301 | threads: vec![dap::Thread { | 277 | id: 1, |
| 302 | id: 1, | 278 | name: "Thread 1".into(), |
| 303 | name: "Thread 1".into(), | 279 | }], |
| 304 | }], | ||
| 305 | }) | ||
| 306 | }) | 280 | }) |
| 307 | .await; | 281 | }); |
| 308 | 282 | ||
| 309 | client | 283 | client.on_request::<Initialize, _>(move |_, _| { |
| 310 | .on_request::<Initialize, _>(move |_, _| { | 284 | Ok(dap::Capabilities { |
| 311 | Ok(dap::Capabilities { | 285 | supports_step_back: Some(false), |
| 312 | supports_step_back: Some(false), | 286 | ..Default::default() |
| 313 | ..Default::default() | ||
| 314 | }) | ||
| 315 | }) | 287 | }) |
| 316 | .await; | 288 | }); |
| 317 | 289 | ||
| 318 | client.on_request::<Launch, _>(move |_, _| Ok(())).await; | 290 | client.on_request::<Launch, _>(move |_, _| Ok(())); |
| 319 | 291 | ||
| 320 | let stack_frames = vec![StackFrame { | 292 | let stack_frames = vec![StackFrame { |
| 321 | id: 1, | 293 | id: 1, |
| @@ -340,19 +312,17 @@ async fn test_fetch_variables_for_multiple_scopes( · 18 unmodified lines | |||
| 340 | presentation_hint: None, | 312 | presentation_hint: None, |
| 341 | }]; | 313 | }]; |
| 342 | 314 | ||
| 343 | client | 315 | client.on_request::<StackTrace, _>({ |
| 344 | .on_request::<StackTrace, _>({ | 316 | let stack_frames = Arc::new(stack_frames.clone()); |
| 345 | let stack_frames = Arc::new(stack_frames.clone()); | 317 | move |_, args| { |
| 346 | move |_, args| { | 318 | assert_eq!(1, args.thread_id); |
| 347 | assert_eq!(1, args.thread_id); | 319 | |
| 348 | 320 | Ok(dap::StackTraceResponse { | |
| 349 | Ok(dap::StackTraceResponse { | 321 | stack_frames: (*stack_frames).clone(), |
| 350 | stack_frames: (*stack_frames).clone(), | 322 | total_frames: None, |
| 351 | total_frames: None, | 323 | }) |
| 352 | }) | 324 | } |
| 353 | } | 325 | }); |
| 354 | }) | ||
| 355 | .await; | ||
| 356 | 326 | ||
| 357 | let scopes = vec![ | 327 | let scopes = vec![ |
| 358 | Scope { | 328 | Scope { |
| @@ -383,18 +353,16 @@ async fn test_fetch_variables_for_multiple_scopes( · 24 unmodified lines | |||
| 383 | }, | 353 | }, |
| 384 | ]; | 354 | ]; |
| 385 | 355 | ||
| 386 | client | 356 | client.on_request::<Scopes, _>({ |
| 387 | .on_request::<Scopes, _>({ | 357 | let scopes = Arc::new(scopes.clone()); |
| 388 | let scopes = Arc::new(scopes.clone()); | 358 | move |_, args| { |
| 389 | move |_, args| { | 359 | assert_eq!(1, args.frame_id); |
| 390 | assert_eq!(1, args.frame_id); | ||
| 391 | 360 | ||
| 392 | Ok(dap::ScopesResponse { | 361 | Ok(dap::ScopesResponse { |
| 393 | scopes: (*scopes).clone(), | 362 | scopes: (*scopes).clone(), |
| 394 | }) | 363 | }) |
| 395 | } | 364 | } |
| 396 | }) | 365 | }); |
| 397 | .await; | ||
| 398 | 366 | ||
| 399 | let mut variables = HashMap::default(); | 367 | let mut variables = HashMap::default(); |
| 400 | variables.insert( | 368 | variables.insert( |
| @@ -445,16 +413,14 @@ async fn test_fetch_variables_for_multiple_scopes( · 44 unmodified lines | |||
| 445 | }], | 413 | }], |
| 446 | ); | 414 | ); |
| 447 | 415 | ||
| 448 | client | 416 | client.on_request::<Variables, _>({ |
| 449 | .on_request::<Variables, _>({ | 417 | let variables = Arc::new(variables.clone()); |
| 450 | let variables = Arc::new(variables.clone()); | 418 | move |_, args| { |
| 451 | move |_, args| { | 419 | Ok(dap::VariablesResponse { |
| 452 | Ok(dap::VariablesResponse { | 420 | variables: variables.get(&args.variables_reference).unwrap().clone(), |
| 453 | variables: variables.get(&args.variables_reference).unwrap().clone(), | 421 | }) |
| 454 | }) | 422 | } |
| 455 | } | 423 | }); |
| 456 | }) | ||
| 457 | .await; | ||
| 458 | 424 | ||
| 459 | client | 425 | client |
| 460 | .fake_event(dap::messages::Events::Stopped(dap::StoppedEvent { | 426 | .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 | |||
| 562 | }) | 528 | }) |
| 563 | .unwrap(); | 529 | .unwrap(); |
| 564 | let cx = &mut VisualTestContext::from_window(*workspace, cx); | 530 | let cx = &mut VisualTestContext::from_window(*workspace, cx); |
| 565 | 531 | let session = debugger::test::start_debug_session(&project, cx, |_| {}) | |
| 566 | let task = project.update(cx, |project, cx| { | 532 | .await |
| 567 | project.fake_debug_session( | 533 | .unwrap(); |
| 568 | dap::DebugRequestType::Launch(LaunchConfig::default()), | ||
| 569 | None, | ||
| 570 | false, | ||
| 571 | cx, | ||
| 572 | ) | ||
| 573 | }); | ||
| 574 | |||
| 575 | let session = task.await.unwrap(); | ||
| 576 | let client = session.update(cx, |session, _| session.adapter_client().unwrap()); | 534 | let client = session.update(cx, |session, _| session.adapter_client().unwrap()); |
| 577 | 535 | ||
| 578 | client | 536 | client.on_request::<dap::requests::Threads, _>(move |_, _| { |
| 579 | .on_request::<dap::requests::Threads, _>(move |_, _| { | 537 | Ok(dap::ThreadsResponse { |
| 580 | Ok(dap::ThreadsResponse { | 538 | threads: vec![dap::Thread { |
| 581 | threads: vec![dap::Thread { | 539 | id: 1, |
| 582 | id: 1, | 540 | name: "Thread 1".into(), |
| 583 | name: "Thread 1".into(), | 541 | }], |
| 584 | }], | ||
| 585 | }) | ||
| 586 | }) | 542 | }) |
| 587 | .await; | 543 | }); |
| 588 | 544 | ||
| 589 | client | 545 | client.on_request::<Initialize, _>(move |_, _| { |
| 590 | .on_request::<Initialize, _>(move |_, _| { | 546 | Ok(dap::Capabilities { |
| 591 | Ok(dap::Capabilities { | 547 | supports_step_back: Some(false), |
| 592 | supports_step_back: Some(false), | 548 | ..Default::default() |
| 593 | ..Default::default() | ||
| 594 | }) | ||
| 595 | }) | 549 | }) |
| 596 | .await; | 550 | }); |
| 597 | 551 | ||
| 598 | client.on_request::<Launch, _>(move |_, _| Ok(())).await; | 552 | client.on_request::<Launch, _>(move |_, _| Ok(())); |
| 599 | 553 | ||
| 600 | let stack_frames = vec![StackFrame { | 554 | let stack_frames = vec![StackFrame { |
| 601 | id: 1, | 555 | id: 1, |
| @@ -620,19 +574,17 @@ async fn test_keyboard_navigation(executor: BackgroundExecutor, cx: &mut TestApp · 18 unmodified lines | |||
| 620 | presentation_hint: None, | 574 | presentation_hint: None, |
| 621 | }]; | 575 | }]; |
| 622 | 576 | ||
| 623 | client | 577 | client.on_request::<StackTrace, _>({ |
| 624 | .on_request::<StackTrace, _>({ | 578 | let stack_frames = Arc::new(stack_frames.clone()); |
| 625 | let stack_frames = Arc::new(stack_frames.clone()); | 579 | move |_, args| { |
| 626 | move |_, args| { | 580 | assert_eq!(1, args.thread_id); |
| 627 | assert_eq!(1, args.thread_id); | 581 | |
| 628 | 582 | Ok(dap::StackTraceResponse { | |
| 629 | Ok(dap::StackTraceResponse { | 583 | stack_frames: (*stack_frames).clone(), |
| 630 | stack_frames: (*stack_frames).clone(), | 584 | total_frames: None, |
| 631 | total_frames: None, | 585 | }) |
| 632 | }) | 586 | } |
| 633 | } | 587 | }); |
| 634 | }) | ||
| 635 | .await; | ||
| 636 | 588 | ||
| 637 | let scopes = vec![ | 589 | let scopes = vec![ |
| 638 | Scope { | 590 | Scope { |
| @@ -663,18 +615,16 @@ async fn test_keyboard_navigation(executor: BackgroundExecutor, cx: &mut TestApp · 24 unmodified lines | |||
| 663 | }, | 615 | }, |
| 664 | ]; | 616 | ]; |
| 665 | 617 | ||
| 666 | client | 618 | client.on_request::<Scopes, _>({ |
| 667 | .on_request::<Scopes, _>({ | 619 | let scopes = Arc::new(scopes.clone()); |
| 668 | let scopes = Arc::new(scopes.clone()); | 620 | move |_, args| { |
| 669 | move |_, args| { | 621 | assert_eq!(1, args.frame_id); |
| 670 | assert_eq!(1, args.frame_id); | ||
| 671 | 622 | ||
| 672 | Ok(dap::ScopesResponse { | 623 | Ok(dap::ScopesResponse { |
| 673 | scopes: (*scopes).clone(), | 624 | scopes: (*scopes).clone(), |
| 674 | }) | 625 | }) |
| 675 | } | 626 | } |
| 676 | }) | 627 | }); |
| 677 | .await; | ||
| 678 | 628 | ||
| 679 | let scope1_variables = vec![ | 629 | let scope1_variables = vec![ |
| 680 | Variable { | 630 | Variable { |
| @@ -748,25 +698,23 @@ async fn test_keyboard_navigation(executor: BackgroundExecutor, cx: &mut TestApp · 67 unmodified lines | |||
| 748 | value_location_reference: None, | 698 | value_location_reference: None, |
| 749 | }]; | 699 | }]; |
| 750 | 700 | ||
| 751 | client | 701 | client.on_request::<Variables, _>({ |
| 752 | .on_request::<Variables, _>({ | 702 | let scope1_variables = Arc::new(scope1_variables.clone()); |
| 753 | let scope1_variables = Arc::new(scope1_variables.clone()); | 703 | let nested_variables = Arc::new(nested_variables.clone()); |
| 754 | let nested_variables = Arc::new(nested_variables.clone()); | 704 | let scope2_variables = Arc::new(scope2_variables.clone()); |
| 755 | let scope2_variables = Arc::new(scope2_variables.clone()); | 705 | move |_, args| match args.variables_reference { |
| 756 | move |_, args| match args.variables_reference { | 706 | 4 => Ok(dap::VariablesResponse { |
| 757 | 4 => Ok(dap::VariablesResponse { | 707 | variables: (*scope2_variables).clone(), |
| 758 | variables: (*scope2_variables).clone(), | 708 | }), |
| 759 | }), | 709 | 3 => Ok(dap::VariablesResponse { |
| 760 | 3 => Ok(dap::VariablesResponse { | 710 | variables: (*nested_variables).clone(), |
| 761 | variables: (*nested_variables).clone(), | 711 | }), |
| 762 | }), | 712 | 2 => Ok(dap::VariablesResponse { |
| 763 | 2 => Ok(dap::VariablesResponse { | 713 | variables: (*scope1_variables).clone(), |
| 764 | variables: (*scope1_variables).clone(), | 714 | }), |
| 765 | }), | 715 | id => unreachable!("unexpected variables reference {id}"), |
| 766 | id => unreachable!("unexpected variables reference {id}"), | 716 | } |
| 767 | } | 717 | }); |
| 768 | }) | ||
| 769 | .await; | ||
| 770 | 718 | ||
| 771 | client | 719 | client |
| 772 | .fake_event(dap::messages::Events::Stopped(dap::StoppedEvent { | 720 | .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 | |||
| 1365 | let workspace = init_test_workspace(&project, cx).await; | 1313 | let workspace = init_test_workspace(&project, cx).await; |
| 1366 | let cx = &mut VisualTestContext::from_window(*workspace, cx); | 1314 | let cx = &mut VisualTestContext::from_window(*workspace, cx); |
| 1367 | 1315 | ||
| 1368 | let task = project.update(cx, |project, cx| { | 1316 | let session = debugger::test::start_debug_session(&project, cx, |_| {}) |
| 1369 | project.fake_debug_session( | 1317 | .await |
| 1370 | dap::DebugRequestType::Launch(LaunchConfig::default()), | 1318 | .unwrap(); |
| 1371 | None, | ||
| 1372 | false, | ||
| 1373 | cx, | ||
| 1374 | ) | ||
| 1375 | }); | ||
| 1376 | |||
| 1377 | let session = task.await.unwrap(); | ||
| 1378 | let client = session.update(cx, |session, _| session.adapter_client().unwrap()); | 1319 | let client = session.update(cx, |session, _| session.adapter_client().unwrap()); |
| 1379 | 1320 | ||
| 1380 | client | 1321 | client.on_request::<dap::requests::Threads, _>(move |_, _| { |
| 1381 | .on_request::<dap::requests::Threads, _>(move |_, _| { | 1322 | Ok(dap::ThreadsResponse { |
| 1382 | Ok(dap::ThreadsResponse { | 1323 | threads: vec![dap::Thread { |
| 1383 | threads: vec![dap::Thread { | 1324 | id: 1, |
| 1384 | id: 1, | 1325 | name: "Thread 1".into(), |
| 1385 | name: "Thread 1".into(), | 1326 | }], |
| 1386 | }], | ||
| 1387 | }) | ||
| 1388 | }) | 1327 | }) |
| 1389 | .await; | 1328 | }); |
| 1390 | 1329 | ||
| 1391 | client | 1330 | client.on_request::<Initialize, _>(move |_, _| { |
| 1392 | .on_request::<Initialize, _>(move |_, _| { | 1331 | Ok(dap::Capabilities { |
| 1393 | Ok(dap::Capabilities { | 1332 | supports_step_back: Some(false), |
| 1394 | supports_step_back: Some(false), | 1333 | ..Default::default() |
| 1395 | ..Default::default() | ||
| 1396 | }) | ||
| 1397 | }) | 1334 | }) |
| 1398 | .await; | 1335 | }); |
| 1399 | 1336 | ||
| 1400 | client.on_request::<Launch, _>(move |_, _| Ok(())).await; | 1337 | client.on_request::<Launch, _>(move |_, _| Ok(())); |
| 1401 | 1338 | ||
| 1402 | let stack_frames = vec![ | 1339 | let stack_frames = vec![ |
| 1403 | StackFrame { | 1340 | StackFrame { |
| @@ -1446,19 +1383,17 @@ async fn test_variable_list_only_sends_requests_when_rendering( · 42 unmodified lines | |||
| 1446 | }, | 1383 | }, |
| 1447 | ]; | 1384 | ]; |
| 1448 | 1385 | ||
| 1449 | client | 1386 | client.on_request::<StackTrace, _>({ |
| 1450 | .on_request::<StackTrace, _>({ | 1387 | let stack_frames = Arc::new(stack_frames.clone()); |
| 1451 | let stack_frames = Arc::new(stack_frames.clone()); | 1388 | move |_, args| { |
| 1452 | move |_, args| { | 1389 | assert_eq!(1, args.thread_id); |
| 1453 | assert_eq!(1, args.thread_id); | 1390 | |
| 1454 | 1391 | Ok(dap::StackTraceResponse { | |
| 1455 | Ok(dap::StackTraceResponse { | 1392 | stack_frames: (*stack_frames).clone(), |
| 1456 | stack_frames: (*stack_frames).clone(), | 1393 | total_frames: None, |
| 1457 | total_frames: None, | 1394 | }) |
| 1458 | }) | 1395 | } |
| 1459 | } | 1396 | }); |
| 1460 | }) | ||
| 1461 | .await; | ||
| 1462 | 1397 | ||
| 1463 | let frame_1_scopes = vec![Scope { | 1398 | let frame_1_scopes = vec![Scope { |
| 1464 | name: "Frame 1 Scope 1".into(), | 1399 | name: "Frame 1 Scope 1".into(), |
| @@ -1476,25 +1411,23 @@ async fn test_variable_list_only_sends_requests_when_rendering( · 11 unmodified lines | |||
| 1476 | 1411 | ||
| 1477 | let made_scopes_request = Arc::new(AtomicBool::new(false)); | 1412 | let made_scopes_request = Arc::new(AtomicBool::new(false)); |
| 1478 | 1413 | ||
| 1479 | client | 1414 | client.on_request::<Scopes, _>({ |
| 1480 | .on_request::<Scopes, _>({ | 1415 | let frame_1_scopes = Arc::new(frame_1_scopes.clone()); |
| 1481 | let frame_1_scopes = Arc::new(frame_1_scopes.clone()); | 1416 | let made_scopes_request = made_scopes_request.clone(); |
| 1482 | let made_scopes_request = made_scopes_request.clone(); | 1417 | move |_, args| { |
| 1483 | move |_, args| { | 1418 | assert_eq!(1, args.frame_id); |
| 1484 | assert_eq!(1, args.frame_id); | 1419 | assert!( |
| 1485 | assert!( | 1420 | !made_scopes_request.load(Ordering::SeqCst), |
| 1486 | !made_scopes_request.load(Ordering::SeqCst), | 1421 | "We should be caching the scope request" |
| 1487 | "We should be caching the scope request" | 1422 | ); |
| 1488 | ); | ||
| 1489 | 1423 | ||
| 1490 | made_scopes_request.store(true, Ordering::SeqCst); | 1424 | made_scopes_request.store(true, Ordering::SeqCst); |
| 1491 | 1425 | ||
| 1492 | Ok(dap::ScopesResponse { | 1426 | Ok(dap::ScopesResponse { |
| 1493 | scopes: (*frame_1_scopes).clone(), | 1427 | scopes: (*frame_1_scopes).clone(), |
| 1494 | }) | 1428 | }) |
| 1495 | } | 1429 | } |
| 1496 | }) | 1430 | }); |
| 1497 | .await; | ||
| 1498 | 1431 | ||
| 1499 | let frame_1_variables = vec![ | 1432 | let frame_1_variables = vec![ |
| 1500 | Variable { | 1433 | Variable { |
| @@ -1525,18 +1458,16 @@ async fn test_variable_list_only_sends_requests_when_rendering( · 24 unmodified lines | |||
| 1525 | }, | 1458 | }, |
| 1526 | ]; | 1459 | ]; |
| 1527 | 1460 | ||
| 1528 | client | 1461 | client.on_request::<Variables, _>({ |
| 1529 | .on_request::<Variables, _>({ | 1462 | let frame_1_variables = Arc::new(frame_1_variables.clone()); |
| 1530 | let frame_1_variables = Arc::new(frame_1_variables.clone()); | 1463 | move |_, args| { |
| 1531 | move |_, args| { | 1464 | assert_eq!(2, args.variables_reference); |
| 1532 | assert_eq!(2, args.variables_reference); | ||
| 1533 | 1465 | ||
| 1534 | Ok(dap::VariablesResponse { | 1466 | Ok(dap::VariablesResponse { |
| 1535 | variables: (*frame_1_variables).clone(), | 1467 | variables: (*frame_1_variables).clone(), |
| 1536 | }) | 1468 | }) |
| 1537 | } | 1469 | } |
| 1538 | }) | 1470 | }); |
| 1539 | .await; | ||
| 1540 | 1471 | ||
| 1541 | cx.run_until_parked(); | 1472 | cx.run_until_parked(); |
| 1542 | 1473 | ||
| @@ -1629,39 +1560,28 @@ async fn test_it_fetches_scopes_variables_when_you_select_a_stack_frame( · 86 unmodified lines | |||
| 1629 | .unwrap(); | 1560 | .unwrap(); |
| 1630 | let cx = &mut VisualTestContext::from_window(*workspace, cx); | 1561 | let cx = &mut VisualTestContext::from_window(*workspace, cx); |
| 1631 | 1562 | ||
| 1632 | let task = project.update(cx, |project, cx| { | 1563 | let session = debugger::test::start_debug_session(&project, cx, |_| {}) |
| 1633 | project.fake_debug_session( | 1564 | .await |
| 1634 | dap::DebugRequestType::Launch(LaunchConfig::default()), | 1565 | .unwrap(); |
| 1635 | None, | ||
| 1636 | false, | ||
| 1637 | cx, | ||
| 1638 | ) | ||
| 1639 | }); | ||
| 1640 | |||
| 1641 | let session = task.await.unwrap(); | ||
| 1642 | let client = session.update(cx, |session, _| session.adapter_client().unwrap()); | 1566 | let client = session.update(cx, |session, _| session.adapter_client().unwrap()); |
| 1643 | 1567 | ||
| 1644 | client | 1568 | client.on_request::<dap::requests::Threads, _>(move |_, _| { |
| 1645 | .on_request::<dap::requests::Threads, _>(move |_, _| { | 1569 | Ok(dap::ThreadsResponse { |
| 1646 | Ok(dap::ThreadsResponse { | 1570 | threads: vec![dap::Thread { |
| 1647 | threads: vec![dap::Thread { | 1571 | id: 1, |
| 1648 | id: 1, | 1572 | name: "Thread 1".into(), |
| 1649 | name: "Thread 1".into(), | 1573 | }], |
| 1650 | }], | ||
| 1651 | }) | ||
| 1652 | }) | 1574 | }) |
| 1653 | .await; | 1575 | }); |
| 1654 | 1576 | ||
| 1655 | client | 1577 | client.on_request::<Initialize, _>(move |_, _| { |
| 1656 | .on_request::<Initialize, _>(move |_, _| { | 1578 | Ok(dap::Capabilities { |
| 1657 | Ok(dap::Capabilities { | 1579 | supports_step_back: Some(false), |
| 1658 | supports_step_back: Some(false), | 1580 | ..Default::default() |
| 1659 | ..Default::default() | ||
| 1660 | }) | ||
| 1661 | }) | 1581 | }) |
| 1662 | .await; | 1582 | }); |
| 1663 | 1583 | ||
| 1664 | client.on_request::<Launch, _>(move |_, _| Ok(())).await; | 1584 | client.on_request::<Launch, _>(move |_, _| Ok(())); |
| 1665 | 1585 | ||
| 1666 | let stack_frames = vec![ | 1586 | let stack_frames = vec![ |
| 1667 | StackFrame { | 1587 | StackFrame { |
| @@ -1710,19 +1630,17 @@ async fn test_it_fetches_scopes_variables_when_you_select_a_stack_frame( · 42 unmodified lines | |||
| 1710 | }, | 1630 | }, |
| 1711 | ]; | 1631 | ]; |
| 1712 | 1632 | ||
| 1713 | client | 1633 | client.on_request::<StackTrace, _>({ |
| 1714 | .on_request::<StackTrace, _>({ | 1634 | let stack_frames = Arc::new(stack_frames.clone()); |
| 1715 | let stack_frames = Arc::new(stack_frames.clone()); | 1635 | move |_, args| { |
| 1716 | move |_, args| { | 1636 | assert_eq!(1, args.thread_id); |
| 1717 | assert_eq!(1, args.thread_id); | 1637 | |
| 1718 | 1638 | Ok(dap::StackTraceResponse { | |
| 1719 | Ok(dap::StackTraceResponse { | 1639 | stack_frames: (*stack_frames).clone(), |
| 1720 | stack_frames: (*stack_frames).clone(), | 1640 | total_frames: None, |
| 1721 | total_frames: None, | 1641 | }) |
| 1722 | }) | 1642 | } |
| 1723 | } | 1643 | }); |
| 1724 | }) | ||
| 1725 | .await; | ||
| 1726 | 1644 | ||
| 1727 | let frame_1_scopes = vec![Scope { | 1645 | let frame_1_scopes = vec![Scope { |
| 1728 | name: "Frame 1 Scope 1".into(), | 1646 | 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 | |||
| 1757 | let called_second_stack_frame = Arc::new(AtomicBool::new(false)); | 1675 | let called_second_stack_frame = Arc::new(AtomicBool::new(false)); |
| 1758 | let called_first_stack_frame = Arc::new(AtomicBool::new(false)); | 1676 | let called_first_stack_frame = Arc::new(AtomicBool::new(false)); |
| 1759 | 1677 | ||
| 1760 | client | 1678 | client.on_request::<Scopes, _>({ |
| 1761 | .on_request::<Scopes, _>({ | 1679 | let frame_1_scopes = Arc::new(frame_1_scopes.clone()); |
| 1762 | let frame_1_scopes = Arc::new(frame_1_scopes.clone()); | 1680 | let frame_2_scopes = Arc::new(frame_2_scopes.clone()); |
| 1763 | let frame_2_scopes = Arc::new(frame_2_scopes.clone()); | 1681 | let called_first_stack_frame = called_first_stack_frame.clone(); |
| 1764 | let called_first_stack_frame = called_first_stack_frame.clone(); | 1682 | let called_second_stack_frame = called_second_stack_frame.clone(); |
| 1765 | let called_second_stack_frame = called_second_stack_frame.clone(); | 1683 | move |_, args| match args.frame_id { |
| 1766 | move |_, args| match args.frame_id { | 1684 | 1 => { |
| 1767 | 1 => { | 1685 | called_first_stack_frame.store(true, Ordering::SeqCst); |
| 1768 | called_first_stack_frame.store(true, Ordering::SeqCst); | 1686 | Ok(dap::ScopesResponse { |
| 1769 | Ok(dap::ScopesResponse { | 1687 | scopes: (*frame_1_scopes).clone(), |
| 1770 | scopes: (*frame_1_scopes).clone(), | 1688 | }) |
| 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"), | ||
| 1781 | } | 1689 | } |
| 1782 | }) | 1690 | 2 => { |
| 1783 | .await; | 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 | }); | ||
| 1784 | 1700 | ||
| 1785 | let frame_1_variables = vec![ | 1701 | let frame_1_variables = vec![ |
| 1786 | Variable { | 1702 | Variable { |
| @@ -1840,18 +1756,16 @@ async fn test_it_fetches_scopes_variables_when_you_select_a_stack_frame( · 53 unmodified lines | |||
| 1840 | }, | 1756 | }, |
| 1841 | ]; | 1757 | ]; |
| 1842 | 1758 | ||
| 1843 | client | 1759 | client.on_request::<Variables, _>({ |
| 1844 | .on_request::<Variables, _>({ | 1760 | let frame_1_variables = Arc::new(frame_1_variables.clone()); |
| 1845 | let frame_1_variables = Arc::new(frame_1_variables.clone()); | 1761 | move |_, args| { |
| 1846 | move |_, args| { | 1762 | assert_eq!(2, args.variables_reference); |
| 1847 | assert_eq!(2, args.variables_reference); | ||
| 1848 | 1763 | ||
| 1849 | Ok(dap::VariablesResponse { | 1764 | Ok(dap::VariablesResponse { |
| 1850 | variables: (*frame_1_variables).clone(), | 1765 | variables: (*frame_1_variables).clone(), |
| 1851 | }) | 1766 | }) |
| 1852 | } | 1767 | } |
| 1853 | }) | 1768 | }); |
| 1854 | .await; | ||
| 1855 | 1769 | ||
| 1856 | client | 1770 | client |
| 1857 | .fake_event(dap::messages::Events::Stopped(dap::StoppedEvent { | 1771 | .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 | |||
| 1907 | assert_eq!(frame_1_variables, variables); | 1821 | assert_eq!(frame_1_variables, variables); |
| 1908 | }); | 1822 | }); |
| 1909 | 1823 | ||
| 1910 | client | 1824 | client.on_request::<Variables, _>({ |
| 1911 | .on_request::<Variables, _>({ | 1825 | let frame_2_variables = Arc::new(frame_2_variables.clone()); |
| 1912 | let frame_2_variables = Arc::new(frame_2_variables.clone()); | 1826 | move |_, args| { |
| 1913 | move |_, args| { | 1827 | assert_eq!(3, args.variables_reference); |
| 1914 | assert_eq!(3, args.variables_reference); | ||
| 1915 | 1828 | ||
| 1916 | Ok(dap::VariablesResponse { | 1829 | Ok(dap::VariablesResponse { |
| 1917 | variables: (*frame_2_variables).clone(), | 1830 | variables: (*frame_2_variables).clone(), |
| 1918 | }) | 1831 | }) |
| 1919 | } | 1832 | } |
| 1920 | }) | 1833 | }); |
| 1921 | .await; | ||
| 1922 | 1834 | ||
| 1923 | running_state | 1835 | running_state |
| 1924 | .update_in(cx, |running_state, window, cx| { | 1836 | .update_in(cx, |running_state, window, cx| { |
| @@ -16,3 +16,6 @@ pub mod dap_command; · 15 unmodified lines | |||
| 16 | pub mod dap_store; | 16 | pub mod dap_store; |
| 17 | mod locator_store; | 17 | mod locator_store; |
| 18 | pub mod session; | 18 | pub mod session; |
| 19 | |||
| 20 | #[cfg(any(feature = "test-support", test))] | ||
| 21 | pub mod test; | ||
| @@ -3,15 +3,15 @@ use super::{ · 2 unmodified lines | |||
| 3 | locator_store::LocatorStore, | 3 | locator_store::LocatorStore, |
| 4 | session::{self, Session, SessionStateEvent}, | 4 | session::{self, Session, SessionStateEvent}, |
| 5 | }; | 5 | }; |
| 6 | use crate::{ProjectEnvironment, debugger, worktree_store::WorktreeStore}; | 6 | use crate::{ProjectEnvironment, debugger}; |
| 7 | use anyhow::{Result, anyhow}; | 7 | use anyhow::{Result, anyhow}; |
| 8 | use async_trait::async_trait; | 8 | use async_trait::async_trait; |
| 9 | use collections::HashMap; | 9 | use collections::HashMap; |
| 10 | use dap::{ | 10 | use dap::{ |
| 11 | Capabilities, CompletionItem, CompletionsArguments, DapRegistry, ErrorResponse, | 11 | Capabilities, CompletionItem, CompletionsArguments, ErrorResponse, EvaluateArguments, |
| 12 | EvaluateArguments, EvaluateArgumentsContext, EvaluateResponse, RunInTerminalRequestArguments, | 12 | EvaluateArgumentsContext, EvaluateResponse, RunInTerminalRequestArguments, Source, |
| 13 | Source, StartDebuggingRequestArguments, | 13 | StartDebuggingRequestArguments, |
| 14 | adapters::{DapStatus, DebugAdapterName}, | 14 | adapters::{DapStatus, DebugAdapterBinary, DebugAdapterName}, |
| 15 | client::SessionId, | 15 | client::SessionId, |
| 16 | messages::Message, | 16 | messages::Message, |
| 17 | requests::{Completions, Evaluate, Request as _, RunInTerminal, StartDebugging}, | 17 | requests::{Completions, Evaluate, Request as _, RunInTerminal, StartDebugging}, |
| @@ -42,7 +42,7 @@ use std::{ · 24 unmodified lines | |||
| 42 | sync::{Arc, atomic::Ordering::SeqCst}, | 42 | sync::{Arc, atomic::Ordering::SeqCst}, |
| 43 | }; | 43 | }; |
| 44 | use std::{collections::VecDeque, sync::atomic::AtomicU32}; | 44 | use std::{collections::VecDeque, sync::atomic::AtomicU32}; |
| 45 | use task::{DebugAdapterConfig, DebugRequestDisposition}; | 45 | use task::DebugTaskDefinition; |
| 46 | use util::ResultExt as _; | 46 | use util::ResultExt as _; |
| 47 | use worktree::Worktree; | 47 | use worktree::Worktree; |
| 48 | 48 | ||
| @@ -78,10 +78,8 @@ pub struct LocalDapStore { · 29 unmodified lines | |||
| 78 | node_runtime: NodeRuntime, | 78 | node_runtime: NodeRuntime, |
| 79 | next_session_id: AtomicU32, | 79 | next_session_id: AtomicU32, |
| 80 | http_client: Arc<dyn HttpClient>, | 80 | http_client: Arc<dyn HttpClient>, |
| 81 | worktree_store: Entity<WorktreeStore>, | ||
| 82 | environment: Entity<ProjectEnvironment>, | 81 | environment: Entity<ProjectEnvironment>, |
| 83 | language_registry: Arc<LanguageRegistry>, | 82 | language_registry: Arc<LanguageRegistry>, |
| 84 | debug_adapters: Arc<DapRegistry>, | ||
| 85 | toolchain_store: Arc<dyn LanguageToolchainStore>, | 83 | toolchain_store: Arc<dyn LanguageToolchainStore>, |
| 86 | locator_store: Arc<LocatorStore>, | 84 | locator_store: Arc<LocatorStore>, |
| 87 | start_debugging_tx: futures::channel::mpsc::UnboundedSender<(SessionId, Message)>, | 85 | start_debugging_tx: futures::channel::mpsc::UnboundedSender<(SessionId, Message)>, |
| @@ -132,11 +130,9 @@ impl DapStore { · 44 unmodified lines | |||
| 132 | node_runtime: NodeRuntime, | 130 | node_runtime: NodeRuntime, |
| 133 | fs: Arc<dyn Fs>, | 131 | fs: Arc<dyn Fs>, |
| 134 | language_registry: Arc<LanguageRegistry>, | 132 | language_registry: Arc<LanguageRegistry>, |
| 135 | debug_adapters: Arc<DapRegistry>, | ||
| 136 | environment: Entity<ProjectEnvironment>, | 133 | environment: Entity<ProjectEnvironment>, |
| 137 | toolchain_store: Arc<dyn LanguageToolchainStore>, | 134 | toolchain_store: Arc<dyn LanguageToolchainStore>, |
| 138 | breakpoint_store: Entity<BreakpointStore>, | 135 | breakpoint_store: Entity<BreakpointStore>, |
| 139 | worktree_store: Entity<WorktreeStore>, | ||
| 140 | cx: &mut Context<Self>, | 136 | cx: &mut Context<Self>, |
| 141 | ) -> Self { | 137 | ) -> Self { |
| 142 | cx.on_app_quit(Self::shutdown_sessions).detach(); | 138 | cx.on_app_quit(Self::shutdown_sessions).detach(); |
| @@ -170,10 +166,8 @@ impl DapStore { · 27 unmodified lines | |||
| 170 | environment, | 166 | environment, |
| 171 | http_client, | 167 | http_client, |
| 172 | node_runtime, | 168 | node_runtime, |
| 173 | worktree_store, | ||
| 174 | toolchain_store, | 169 | toolchain_store, |
| 175 | language_registry, | 170 | language_registry, |
| 176 | debug_adapters, | ||
| 177 | start_debugging_tx, | 171 | start_debugging_tx, |
| 178 | _start_debugging_task, | 172 | _start_debugging_task, |
| 179 | locator_store: Arc::from(LocatorStore::new()), | 173 | locator_store: Arc::from(LocatorStore::new()), |
| @@ -320,18 +314,12 @@ impl DapStore { · 140 unmodified lines | |||
| 320 | Ok(()) | 314 | Ok(()) |
| 321 | } | 315 | } |
| 322 | 316 | ||
| 323 | pub fn new_session( | 317 | pub fn delegate(&self, worktree: &Entity<Worktree>, cx: &mut App) -> DapAdapterDelegate { |
| 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>>>) { | ||
| 330 | let Some(local_store) = self.as_local() else { | 318 | let Some(local_store) = self.as_local() else { |
| 331 | unimplemented!("Starting session on remote side"); | 319 | unimplemented!("Starting session on remote side"); |
| 332 | }; | 320 | }; |
| 333 | 321 | ||
| 334 | let delegate = DapAdapterDelegate::new( | 322 | DapAdapterDelegate::new( |
| 335 | local_store.fs.clone(), | 323 | local_store.fs.clone(), |
| 336 | worktree.read(cx).id(), | 324 | worktree.read(cx).id(), |
| 337 | local_store.node_runtime.clone(), | 325 | local_store.node_runtime.clone(), |
| @@ -341,7 +329,20 @@ impl DapStore { · 3 unmodified lines | |||
| 341 | local_store.environment.update(cx, |env, cx| { | 329 | local_store.environment.update(cx, |env, cx| { |
| 342 | env.get_worktree_environment(worktree.clone(), cx) | 330 | env.get_worktree_environment(worktree.clone(), cx) |
| 343 | }), | 331 | }), |
| 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 | |||
| 345 | let session_id = local_store.next_session_id(); | 346 | let session_id = local_store.next_session_id(); |
| 346 | 347 | ||
| 347 | if let Some(session) = &parent_session { | 348 | if let Some(session) = &parent_session { |
| @@ -352,7 +353,6 @@ impl DapStore { · 4 unmodified lines | |||
| 352 | 353 | ||
| 353 | let (initialized_tx, initialized_rx) = oneshot::channel(); | 354 | let (initialized_tx, initialized_rx) = oneshot::channel(); |
| 354 | let locator_store = local_store.locator_store.clone(); | 355 | let locator_store = local_store.locator_store.clone(); |
| 355 | let debug_adapters = local_store.debug_adapters.clone(); | ||
| 356 | 356 | ||
| 357 | let start_debugging_tx = local_store.start_debugging_tx.clone(); | 357 | let start_debugging_tx = local_store.start_debugging_tx.clone(); |
| 358 | 358 | ||
| @@ -373,86 +373,31 @@ impl DapStore { · 14 unmodified lines | |||
| 373 | this.breakpoint_store.clone(), | 373 | this.breakpoint_store.clone(), |
| 374 | session_id, | 374 | session_id, |
| 375 | parent_session, | 375 | parent_session, |
| 376 | delegate, | 376 | binary, |
| 377 | config, | 377 | config, |
| 378 | start_debugging_tx.clone(), | 378 | start_debugging_tx.clone(), |
| 379 | initialized_tx, | 379 | initialized_tx, |
| 380 | debug_adapters, | ||
| 381 | cx, | 380 | cx, |
| 382 | ) | 381 | ) |
| 383 | })?; | 382 | })?; |
| 384 | 383 | ||
| 385 | this.update(cx, |_, cx| { | 384 | let ret = this |
| 386 | create_new_session(session_id, initialized_rx, start_client_task, cx) | 385 | .update(cx, |_, cx| { |
| 387 | })? | 386 | create_new_session(session_id, initialized_rx, start_client_task, cx) |
| 388 | .await | 387 | })? |
| 388 | .await; | ||
| 389 | ret | ||
| 389 | }); | 390 | }); |
| 390 | 391 | ||
| 391 | (session_id, task) | 392 | (session_id, task) |
| 392 | } | 393 | } |
| 393 | 394 | ||
| 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 | |||
| 446 | fn handle_start_debugging_request( | 395 | fn handle_start_debugging_request( |
| 447 | &mut self, | 396 | &mut self, |
| 448 | session_id: SessionId, | 397 | session_id: SessionId, |
| 449 | request: dap::messages::Request, | 398 | request: dap::messages::Request, |
| 450 | cx: &mut Context<Self>, | 399 | cx: &mut Context<Self>, |
| 451 | ) -> Task<Result<()>> { | 400 | ) -> Task<Result<()>> { |
| 452 | let Some(local_store) = self.as_local() else { | ||
| 453 | unreachable!("Cannot response for non-local session"); | ||
| 454 | }; | ||
| 455 | |||
| 456 | let Some(parent_session) = self.session_by_id(session_id) else { | 401 | let Some(parent_session) = self.session_by_id(session_id) else { |
| 457 | return Task::ready(Err(anyhow!("Session not found"))); | 402 | return Task::ready(Err(anyhow!("Session not found"))); |
| 458 | }; | 403 | }; |
| @@ -461,41 +406,12 @@ impl DapStore { · 2 unmodified lines | |||
| 461 | request.arguments.unwrap_or_default(), | 406 | request.arguments.unwrap_or_default(), |
| 462 | ) | 407 | ) |
| 463 | .expect("To parse StartDebuggingRequestArguments"); | 408 | .expect("To parse StartDebuggingRequestArguments"); |
| 464 | let worktree = local_store | 409 | let mut binary = parent_session.read(cx).binary().clone(); |
| 465 | .worktree_store | 410 | let config = parent_session.read(cx).configuration().unwrap().clone(); |
| 466 | .update(cx, |this, _| this.worktrees().next()) | 411 | binary.request_args = args; |
| 467 | .expect("worktree-less project"); | ||
| 468 | 412 | ||
| 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")))] | ||
| 497 | let new_session_task = self | 413 | 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) |
| 499 | .1; | 415 | .1; |
| 500 | 416 | ||
| 501 | let request_seq = request.seq; | 417 | let request_seq = request.seq; |
| @@ -607,13 +523,7 @@ impl DapStore { · 105 unmodified lines | |||
| 607 | .map(Arc::from) | 523 | .map(Arc::from) |
| 608 | .or_else(|| { | 524 | .or_else(|| { |
| 609 | self.session_by_id(session_id) | 525 | self.session_by_id(session_id) |
| 610 | .and_then(|session| { | 526 | .and_then(|session| session.read(cx).binary().cwd.as_deref().map(Arc::from)) |
| 611 | session | ||
| 612 | .read(cx) | ||
| 613 | .configuration() | ||
| 614 | .and_then(|config| config.request.cwd()) | ||
| 615 | }) | ||
| 616 | .map(Arc::from) | ||
| 617 | }); | 527 | }); |
| 618 | cx.emit(DapStoreEvent::RunInTerminal { | 528 | cx.emit(DapStoreEvent::RunInTerminal { |
| 619 | session_id, | 529 | session_id, |
| @@ -852,7 +762,7 @@ fn create_new_session( · 232 unmodified lines | |||
| 852 | cx.emit(DapStoreEvent::DebugClientStarted(session_id)); | 762 | cx.emit(DapStoreEvent::DebugClientStarted(session_id)); |
| 853 | cx.notify(); | 763 | cx.notify(); |
| 854 | })?; | 764 | })?; |
| 855 | let seq_result = { | 765 | let seq_result = async || { |
| 856 | session | 766 | session |
| 857 | .update(cx, |session, cx| session.request_initialize(cx))? | 767 | .update(cx, |session, cx| session.request_initialize(cx))? |
| 858 | .await?; | 768 | .await?; |
| @@ -863,12 +773,11 @@ fn create_new_session( · 4 unmodified lines | |||
| 863 | })? | 773 | })? |
| 864 | .await | 774 | .await |
| 865 | }; | 775 | }; |
| 866 | match seq_result { | 776 | match seq_result().await { |
| 867 | Ok(_) => {} | 777 | Ok(_) => {} |
| 868 | Err(error) => { | 778 | Err(error) => { |
| 869 | this.update(cx, |this, cx| { | 779 | this.update(cx, |this, cx| { |
| 870 | cx.emit(DapStoreEvent::Notification(error.to_string())); | 780 | cx.emit(DapStoreEvent::Notification(error.to_string())); |
| 871 | |||
| 872 | this.shutdown_session(session_id, cx) | 781 | this.shutdown_session(session_id, cx) |
| 873 | })? | 782 | })? |
| 874 | .await | 783 | .await |
| @@ -1,9 +1,9 @@ | |||
| 1 | use anyhow::{Result, anyhow}; | 1 | use anyhow::{Result, anyhow}; |
| 2 | use cargo::CargoLocator; | 2 | use cargo::CargoLocator; |
| 3 | use collections::HashMap; | 3 | use collections::HashMap; |
| 4 | use dap::DebugAdapterConfig; | ||
| 5 | use gpui::SharedString; | 4 | use gpui::SharedString; |
| 6 | use locators::DapLocator; | 5 | use locators::DapLocator; |
| 6 | use task::DebugTaskDefinition; | ||
| 7 | 7 | ||
| 8 | mod cargo; | 8 | mod cargo; |
| 9 | mod locators; | 9 | mod locators; |
| @@ -23,7 +23,7 @@ impl LocatorStore { · 13 unmodified lines | |||
| 23 | 23 | ||
| 24 | pub(super) async fn resolve_debug_config( | 24 | pub(super) async fn resolve_debug_config( |
| 25 | &self, | 25 | &self, |
| 26 | debug_config: &mut DebugAdapterConfig, | 26 | debug_config: &mut DebugTaskDefinition, |
| 27 | ) -> Result<()> { | 27 | ) -> Result<()> { |
| 28 | let Some(locator_name) = &debug_config.locator else { | 28 | let Some(locator_name) = &debug_config.locator else { |
| 29 | log::debug!("Attempted to resolve debug config without a locator field"); | 29 | log::debug!("Attempted to resolve debug config without a locator field"); |
| @@ -1,12 +1,12 @@ | |||
| 1 | use super::DapLocator; | 1 | use super::DapLocator; |
| 2 | use anyhow::{Result, anyhow}; | 2 | use anyhow::{Result, anyhow}; |
| 3 | use async_trait::async_trait; | 3 | use async_trait::async_trait; |
| 4 | use dap::DebugAdapterConfig; | ||
| 5 | use serde_json::{Value, json}; | 4 | use serde_json::{Value, json}; |
| 6 | use smol::{ | 5 | use smol::{ |
| 7 | io::AsyncReadExt, | 6 | io::AsyncReadExt, |
| 8 | process::{Command, Stdio}, | 7 | process::{Command, Stdio}, |
| 9 | }; | 8 | }; |
| 9 | use task::DebugTaskDefinition; | ||
| 10 | use util::maybe; | 10 | use util::maybe; |
| 11 | 11 | ||
| 12 | pub(super) struct CargoLocator; | 12 | pub(super) struct CargoLocator; |
| @@ -38,11 +38,9 @@ async fn find_best_executable(executables: &[String], test_name: &str) -> Option · 25 unmodified lines | |||
| 38 | } | 38 | } |
| 39 | #[async_trait] | 39 | #[async_trait] |
| 40 | impl DapLocator for CargoLocator { | 40 | 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<()> { |
| 42 | let Some(launch_config) = (match &mut debug_config.request { | 42 | let Some(launch_config) = (match &mut debug_config.request { |
| 43 | task::DebugRequestDisposition::UserConfigured(task::DebugRequestType::Launch( | 43 | task::DebugRequestType::Launch(launch_config) => Some(launch_config), |
| 44 | launch_config, | ||
| 45 | )) => Some(launch_config), | ||
| 46 | _ => None, | 44 | _ => None, |
| 47 | }) else { | 45 | }) else { |
| 48 | return Err(anyhow!("Couldn't get launch config in locator")); | 46 | return Err(anyhow!("Couldn't get launch config in locator")); |
| @@ -1,8 +1,8 @@ | |||
| 1 | use anyhow::Result; | 1 | use anyhow::Result; |
| 2 | use async_trait::async_trait; | 2 | use async_trait::async_trait; |
| 3 | use dap::DebugAdapterConfig; | 3 | use task::DebugTaskDefinition; |
| 4 | 4 | ||
| 5 | #[async_trait] | 5 | #[async_trait] |
| 6 | pub(super) trait DapLocator: Send + Sync { | 6 | 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<()>; |
| 8 | } | 8 | } |
| @@ -1,5 +1,3 @@ | |||
| 1 | use crate::project_settings::ProjectSettings; | ||
| 2 | |||
| 3 | use super::breakpoint_store::{ | 1 | use super::breakpoint_store::{ |
| 4 | BreakpointStore, BreakpointStoreEvent, BreakpointUpdatedReason, SourceBreakpoint, | 2 | BreakpointStore, BreakpointStoreEvent, BreakpointUpdatedReason, SourceBreakpoint, |
| 5 | }; | 3 | }; |
| @@ -11,22 +9,17 @@ use super::dap_command::{ · 5 unmodified lines | |||
| 11 | StepBackCommand, StepCommand, StepInCommand, StepOutCommand, TerminateCommand, | 9 | StepBackCommand, StepCommand, StepInCommand, StepOutCommand, TerminateCommand, |
| 12 | TerminateThreadsCommand, ThreadsCommand, VariablesCommand, | 10 | TerminateThreadsCommand, ThreadsCommand, VariablesCommand, |
| 13 | }; | 11 | }; |
| 14 | use super::dap_store::DapAdapterDelegate; | ||
| 15 | use anyhow::{Context as _, Result, anyhow}; | 12 | use anyhow::{Context as _, Result, anyhow}; |
| 16 | use collections::{HashMap, HashSet, IndexMap, IndexSet}; | 13 | use collections::{HashMap, HashSet, IndexMap, IndexSet}; |
| 17 | use dap::adapters::{DebugAdapter, DebugAdapterBinary}; | 14 | use dap::adapters::DebugAdapterBinary; |
| 18 | use dap::messages::Response; | 15 | use dap::messages::Response; |
| 19 | use dap::{ | 16 | use dap::{ |
| 20 | Capabilities, ContinueArguments, EvaluateArgumentsContext, Module, Source, StackFrameId, | 17 | Capabilities, ContinueArguments, EvaluateArgumentsContext, Module, Source, StackFrameId, |
| 21 | SteppingGranularity, StoppedEvent, VariableReference, | 18 | SteppingGranularity, StoppedEvent, VariableReference, |
| 22 | adapters::{DapDelegate, DapStatus}, | ||
| 23 | client::{DebugAdapterClient, SessionId}, | 19 | client::{DebugAdapterClient, SessionId}, |
| 24 | messages::{Events, Message}, | 20 | messages::{Events, Message}, |
| 25 | }; | 21 | }; |
| 26 | use dap::{ | 22 | use dap::{ExceptionBreakpointsFilter, ExceptionFilterOptions, OutputEventCategory}; |
| 27 | DapRegistry, DebugRequestType, ExceptionBreakpointsFilter, ExceptionFilterOptions, | ||
| 28 | OutputEventCategory, | ||
| 29 | }; | ||
| 30 | use futures::channel::oneshot; | 23 | use futures::channel::oneshot; |
| 31 | use futures::{FutureExt, future::Shared}; | 24 | use futures::{FutureExt, future::Shared}; |
| 32 | use gpui::{ | 25 | use gpui::{ |
| @@ -35,11 +28,9 @@ use gpui::{ · 2 unmodified lines | |||
| 35 | }; | 28 | }; |
| 36 | use rpc::AnyProtoClient; | 29 | use rpc::AnyProtoClient; |
| 37 | use serde_json::{Value, json}; | 30 | use serde_json::{Value, json}; |
| 38 | use settings::Settings; | ||
| 39 | use smol::stream::StreamExt; | 31 | use smol::stream::StreamExt; |
| 40 | use std::any::TypeId; | 32 | use std::any::TypeId; |
| 41 | use std::collections::BTreeMap; | 33 | use std::collections::BTreeMap; |
| 42 | use std::path::PathBuf; | ||
| 43 | use std::u64; | 34 | use std::u64; |
| 44 | use std::{ | 35 | use std::{ |
| 45 | any::Any, | 36 | any::Any, |
| @@ -48,7 +39,7 @@ use std::{ · 2 unmodified lines | |||
| 48 | path::Path, | 39 | path::Path, |
| 49 | sync::Arc, | 40 | sync::Arc, |
| 50 | }; | 41 | }; |
| 51 | use task::{DebugAdapterConfig, DebugTaskDefinition}; | 42 | use task::DebugTaskDefinition; |
| 52 | use text::{PointUtf16, ToPointUtf16}; | 43 | use text::{PointUtf16, ToPointUtf16}; |
| 53 | use util::{ResultExt, merge_json_value_into}; | 44 | use util::{ResultExt, merge_json_value_into}; |
| 54 | 45 | ||
| @@ -168,9 +159,9 @@ enum Mode { · 113 unmodified lines | |||
| 168 | #[derive(Clone)] | 159 | #[derive(Clone)] |
| 169 | pub struct LocalMode { | 160 | pub struct LocalMode { |
| 170 | client: Arc<DebugAdapterClient>, | 161 | client: Arc<DebugAdapterClient>, |
| 171 | config: DebugAdapterConfig, | 162 | definition: DebugTaskDefinition, |
| 172 | adapter: Arc<dyn DebugAdapter>, | 163 | binary: DebugAdapterBinary, |
| 173 | breakpoint_store: Entity<BreakpointStore>, | 164 | pub(crate) breakpoint_store: Entity<BreakpointStore>, |
| 174 | tmp_breakpoint: Option<SourceBreakpoint>, | 165 | tmp_breakpoint: Option<SourceBreakpoint>, |
| 175 | } | 166 | } |
| 176 | 167 | ||
| @@ -191,185 +182,37 @@ fn client_source(abs_path: &Path) -> dap::Source { · 14 unmodified lines | |||
| 191 | 182 | ||
| 192 | impl LocalMode { | 183 | impl LocalMode { |
| 193 | fn new( | 184 | fn new( |
| 194 | debug_adapters: Arc<DapRegistry>, | ||
| 195 | session_id: SessionId, | 185 | session_id: SessionId, |
| 196 | parent_session: Option<Entity<Session>>, | 186 | parent_session: Option<Entity<Session>>, |
| 197 | breakpoint_store: Entity<BreakpointStore>, | 187 | breakpoint_store: Entity<BreakpointStore>, |
| 198 | config: DebugAdapterConfig, | 188 | config: DebugTaskDefinition, |
| 199 | delegate: DapAdapterDelegate, | 189 | binary: DebugAdapterBinary, |
| 200 | messages_tx: futures::channel::mpsc::UnboundedSender<Message>, | 190 | messages_tx: futures::channel::mpsc::UnboundedSender<Message>, |
| 201 | cx: AsyncApp, | 191 | cx: AsyncApp, |
| 202 | ) -> Task<Result<Self>> { | 192 | ) -> Task<Result<Self>> { |
| 203 | Self::new_inner( | 193 | Self::new_inner( |
| 204 | debug_adapters, | ||
| 205 | session_id, | 194 | session_id, |
| 206 | parent_session, | 195 | parent_session, |
| 207 | breakpoint_store, | 196 | breakpoint_store, |
| 208 | config, | 197 | config, |
| 209 | delegate, | 198 | binary, |
| 210 | messages_tx, | 199 | messages_tx, |
| 211 | async |_, _| {}, | 200 | async |_, _| {}, |
| 212 | cx, | 201 | cx, |
| 213 | ) | 202 | ) |
| 214 | } | 203 | } |
| 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 | } | ||
| 266 | 204 | ||
| 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 | } | ||
| 358 | fn new_inner( | 205 | fn new_inner( |
| 359 | registry: Arc<DapRegistry>, | ||
| 360 | session_id: SessionId, | 206 | session_id: SessionId, |
| 361 | parent_session: Option<Entity<Session>>, | 207 | parent_session: Option<Entity<Session>>, |
| 362 | breakpoint_store: Entity<BreakpointStore>, | 208 | breakpoint_store: Entity<BreakpointStore>, |
| 363 | config: DebugAdapterConfig, | 209 | config: DebugTaskDefinition, |
| 364 | delegate: DapAdapterDelegate, | 210 | binary: DebugAdapterBinary, |
| 365 | messages_tx: futures::channel::mpsc::UnboundedSender<Message>, | 211 | messages_tx: futures::channel::mpsc::UnboundedSender<Message>, |
| 366 | on_initialized: impl AsyncFnOnce(&mut LocalMode, AsyncApp) + 'static, | 212 | on_initialized: impl AsyncFnOnce(&mut LocalMode, AsyncApp) + 'static, |
| 367 | cx: AsyncApp, | 213 | cx: AsyncApp, |
| 368 | ) -> Task<Result<Self>> { | 214 | ) -> Task<Result<Self>> { |
| 369 | cx.spawn(async move |cx| { | 215 | cx.spawn(async move |cx| { |
| 370 | let (adapter, binary) = | ||
| 371 | Self::get_adapter_binary(®istry, &config, &delegate, cx).await?; | ||
| 372 | |||
| 373 | let message_handler = Box::new(move |message| { | 216 | let message_handler = Box::new(move |message| { |
| 374 | messages_tx.unbounded_send(message).ok(); | 217 | messages_tx.unbounded_send(message).ok(); |
| 375 | }); | 218 | }); |
| @@ -380,13 +223,12 @@ impl LocalMode { · 4 unmodified lines | |||
| 380 | .flatten() | 223 | .flatten() |
| 381 | { | 224 | { |
| 382 | client | 225 | client |
| 383 | .reconnect(session_id, binary, message_handler, cx.clone()) | 226 | .reconnect(session_id, binary.clone(), message_handler, cx.clone()) |
| 384 | .await? | 227 | .await? |
| 385 | } else { | 228 | } else { |
| 386 | DebugAdapterClient::start( | 229 | DebugAdapterClient::start( |
| 387 | session_id, | 230 | session_id, |
| 388 | adapter.name(), | 231 | binary.clone(), |
| 389 | binary, | ||
| 390 | message_handler, | 232 | message_handler, |
| 391 | cx.clone(), | 233 | cx.clone(), |
| 392 | ) | 234 | ) |
| @@ -397,10 +239,10 @@ impl LocalMode { · 4 unmodified lines | |||
| 397 | 239 | ||
| 398 | let mut session = Self { | 240 | let mut session = Self { |
| 399 | client, | 241 | client, |
| 400 | adapter, | ||
| 401 | breakpoint_store, | 242 | breakpoint_store, |
| 402 | tmp_breakpoint: None, | 243 | tmp_breakpoint: None, |
| 403 | config: config.clone(), | 244 | definition: config, |
| 245 | binary, | ||
| 404 | }; | 246 | }; |
| 405 | 247 | ||
| 406 | on_initialized(&mut session, cx.clone()).await; | 248 | on_initialized(&mut session, cx.clone()).await; |
| @@ -533,55 +375,12 @@ impl LocalMode { · 126 unmodified lines | |||
| 533 | }) | 375 | }) |
| 534 | } | 376 | } |
| 535 | 377 | ||
| 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 | |||
| 579 | pub fn label(&self) -> String { | 378 | pub fn label(&self) -> String { |
| 580 | self.config.label.clone() | 379 | self.definition.label.clone() |
| 581 | } | 380 | } |
| 582 | 381 | ||
| 583 | fn request_initialization(&self, cx: &App) -> Task<Result<Capabilities>> { | 382 | 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(); |
| 585 | 384 | ||
| 586 | self.request(Initialize { adapter_id }, cx.background_executor().clone()) | 385 | self.request(Initialize { adapter_id }, cx.background_executor().clone()) |
| 587 | } | 386 | } |
| @@ -592,36 +391,26 @@ impl LocalMode { · 4 unmodified lines | |||
| 592 | initialized_rx: oneshot::Receiver<()>, | 391 | initialized_rx: oneshot::Receiver<()>, |
| 593 | cx: &App, | 392 | cx: &App, |
| 594 | ) -> Task<Result<()>> { | 393 | ) -> Task<Result<()>> { |
| 595 | let (mut raw, is_launch) = match &self.config.request { | 394 | let mut raw = self.binary.request_args.clone(); |
| 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 | }; | ||
| 615 | 395 | ||
| 616 | merge_json_value_into( | 396 | merge_json_value_into( |
| 617 | self.config.initialize_args.clone().unwrap_or(json!({})), | 397 | self.definition.initialize_args.clone().unwrap_or(json!({})), |
| 618 | &mut raw, | 398 | &mut raw.configuration, |
| 619 | ); | 399 | ); |
| 620 | // Of relevance: https://github.com/microsoft/vscode/issues/4902#issuecomment-368583522 | 400 | // Of relevance: https://github.com/microsoft/vscode/issues/4902#issuecomment-368583522 |
| 621 | let launch = if is_launch { | 401 | let launch = match raw.request { |
| 622 | self.request(Launch { raw }, cx.background_executor().clone()) | 402 | dap::StartDebuggingRequestArgumentsRequest::Launch => self.request( |
| 623 | } else { | 403 | Launch { |
| 624 | self.request(Attach { raw }, cx.background_executor().clone()) | 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 | ), | ||
| 625 | }; | 414 | }; |
| 626 | 415 | ||
| 627 | let configuration_done_supported = ConfigurationDone::is_supported(capabilities); | 416 | let configuration_done_supported = ConfigurationDone::is_supported(capabilities); |
| @@ -656,12 +445,13 @@ impl LocalMode { · 28 unmodified lines | |||
| 656 | })? | 445 | })? |
| 657 | .await | 446 | .await |
| 658 | .ok(); | 447 | .ok(); |
| 659 | if configuration_done_supported { | 448 | let ret = if configuration_done_supported { |
| 660 | this.request(ConfigurationDone {}, cx.background_executor().clone()) | 449 | this.request(ConfigurationDone {}, cx.background_executor().clone()) |
| 661 | } else { | 450 | } else { |
| 662 | Task::ready(Ok(())) | 451 | Task::ready(Ok(())) |
| 663 | } | 452 | } |
| 664 | .await | 453 | .await; |
| 454 | ret | ||
| 665 | } | 455 | } |
| 666 | }); | 456 | }); |
| 667 | 457 | ||
| @@ -909,68 +699,22 @@ impl Session { · 241 unmodified lines | |||
| 909 | breakpoint_store: Entity<BreakpointStore>, | 699 | breakpoint_store: Entity<BreakpointStore>, |
| 910 | session_id: SessionId, | 700 | session_id: SessionId, |
| 911 | parent_session: Option<Entity<Session>>, | 701 | parent_session: Option<Entity<Session>>, |
| 912 | delegate: DapAdapterDelegate, | 702 | binary: DebugAdapterBinary, |
| 913 | config: DebugAdapterConfig, | 703 | config: DebugTaskDefinition, |
| 914 | start_debugging_requests_tx: futures::channel::mpsc::UnboundedSender<(SessionId, Message)>, | 704 | start_debugging_requests_tx: futures::channel::mpsc::UnboundedSender<(SessionId, Message)>, |
| 915 | initialized_tx: oneshot::Sender<()>, | 705 | initialized_tx: oneshot::Sender<()>, |
| 916 | debug_adapters: Arc<DapRegistry>, | ||
| 917 | cx: &mut App, | 706 | cx: &mut App, |
| 918 | ) -> Task<Result<Entity<Self>>> { | 707 | ) -> Task<Result<Entity<Self>>> { |
| 919 | let (message_tx, message_rx) = futures::channel::mpsc::unbounded(); | 708 | let (message_tx, message_rx) = futures::channel::mpsc::unbounded(); |
| 920 | 709 | ||
| 921 | cx.spawn(async move |cx| { | 710 | cx.spawn(async move |cx| { |
| 922 | let mode = LocalMode::new( | 711 | 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( | ||
| 966 | session_id, | 712 | session_id, |
| 967 | parent_session.clone(), | 713 | parent_session.clone(), |
| 968 | breakpoint_store.clone(), | 714 | breakpoint_store.clone(), |
| 969 | config.clone(), | 715 | config.clone(), |
| 970 | delegate, | 716 | binary, |
| 971 | message_tx, | 717 | message_tx, |
| 972 | caps, | ||
| 973 | fails, | ||
| 974 | cx.clone(), | 718 | cx.clone(), |
| 975 | ) | 719 | ) |
| 976 | .await?; | 720 | .await?; |
| @@ -1047,16 +791,23 @@ impl Session { · 70 unmodified lines | |||
| 1047 | &self.capabilities | 791 | &self.capabilities |
| 1048 | } | 792 | } |
| 1049 | 793 | ||
| 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 | |||
| 1050 | pub fn adapter_name(&self) -> SharedString { | 801 | pub fn adapter_name(&self) -> SharedString { |
| 1051 | match &self.mode { | 802 | match &self.mode { |
| 1052 | Mode::Local(local_mode) => local_mode.adapter.name().into(), | 803 | Mode::Local(local_mode) => local_mode.definition.adapter.clone().into(), |
| 1053 | Mode::Remote(remote_mode) => remote_mode._adapter_name.clone(), | 804 | Mode::Remote(remote_mode) => remote_mode._adapter_name.clone(), |
| 1054 | } | 805 | } |
| 1055 | } | 806 | } |
| 1056 | 807 | ||
| 1057 | pub fn configuration(&self) -> Option<DebugAdapterConfig> { | 808 | pub fn configuration(&self) -> Option<DebugTaskDefinition> { |
| 1058 | if let Mode::Local(local_mode) = &self.mode { | 809 | if let Mode::Local(local_mode) = &self.mode { |
| 1059 | Some(local_mode.config.clone()) | 810 | Some(local_mode.definition.clone()) |
| 1060 | } else { | 811 | } else { |
| 1061 | None | 812 | None |
| 1062 | } | 813 | } |
| @@ -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 | } | ||
| @@ -25,6 +25,7 @@ mod environment; · 24 unmodified lines | |||
| 25 | use buffer_diff::BufferDiff; | 25 | use buffer_diff::BufferDiff; |
| 26 | pub use environment::{EnvironmentErrorMessage, ProjectEnvironmentEvent}; | 26 | pub use environment::{EnvironmentErrorMessage, ProjectEnvironmentEvent}; |
| 27 | use git_store::{Repository, RepositoryId}; | 27 | use git_store::{Repository, RepositoryId}; |
| 28 | use task::DebugTaskDefinition; | ||
| 28 | pub mod search_history; | 29 | pub mod search_history; |
| 29 | mod yarn; | 30 | mod yarn; |
| 30 | 31 | ||
| @@ -38,7 +39,7 @@ use client::{ · 7 unmodified lines | |||
| 38 | }; | 39 | }; |
| 39 | use clock::ReplicaId; | 40 | use clock::ReplicaId; |
| 40 | 41 | ||
| 41 | use dap::{DapRegistry, DebugAdapterConfig, client::DebugAdapterClient}; | 42 | use dap::{DapRegistry, client::DebugAdapterClient}; |
| 42 | 43 | ||
| 43 | use collections::{BTreeSet, HashMap, HashSet}; | 44 | use collections::{BTreeSet, HashMap, HashSet}; |
| 44 | use debounced_delay::DebouncedDelay; | 45 | use debounced_delay::DebouncedDelay; |
| @@ -106,7 +107,7 @@ use terminals::Terminals; · 61 unmodified lines | |||
| 106 | use text::{Anchor, BufferId}; | 107 | use text::{Anchor, BufferId}; |
| 107 | use toolchain_store::EmptyToolchainStore; | 108 | use toolchain_store::EmptyToolchainStore; |
| 108 | use util::{ | 109 | use util::{ |
| 109 | ResultExt as _, maybe, | 110 | ResultExt as _, |
| 110 | paths::{SanitizedPath, compare_paths}, | 111 | paths::{SanitizedPath, compare_paths}, |
| 111 | }; | 112 | }; |
| 112 | use worktree::{CreatedEntry, Snapshot, Traversal}; | 113 | use worktree::{CreatedEntry, Snapshot, Traversal}; |
| @@ -870,11 +871,9 @@ impl Project { · 757 unmodified lines | |||
| 870 | node.clone(), | 871 | node.clone(), |
| 871 | fs.clone(), | 872 | fs.clone(), |
| 872 | languages.clone(), | 873 | languages.clone(), |
| 873 | debug_adapters.clone(), | ||
| 874 | environment.clone(), | 874 | environment.clone(), |
| 875 | toolchain_store.read(cx).as_language_toolchain_store(), | 875 | toolchain_store.read(cx).as_language_toolchain_store(), |
| 876 | breakpoint_store.clone(), | 876 | breakpoint_store.clone(), |
| 877 | worktree_store.clone(), | ||
| 878 | cx, | 877 | cx, |
| 879 | ) | 878 | ) |
| 880 | }); | 879 | }); |
| @@ -1458,64 +1457,46 @@ impl Project { · 577 unmodified lines | |||
| 1458 | } | 1457 | } |
| 1459 | } | 1458 | } |
| 1460 | 1459 | ||
| 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 | |||
| 1467 | pub fn start_debug_session( | 1460 | pub fn start_debug_session( |
| 1468 | &mut self, | 1461 | &mut self, |
| 1469 | config: DebugAdapterConfig, | 1462 | config: DebugTaskDefinition, |
| 1470 | cx: &mut Context<Self>, | 1463 | cx: &mut Context<Self>, |
| 1471 | ) -> Task<Result<Entity<Session>>> { | 1464 | ) -> Task<Result<Entity<Session>>> { |
| 1472 | let worktree = maybe!({ self.worktrees(cx).next() }); | 1465 | let Some(worktree) = self.worktrees(cx).next() else { |
| 1473 | |||
| 1474 | let Some(worktree) = &worktree else { | ||
| 1475 | return Task::ready(Err(anyhow!("Failed to find a worktree"))); | 1466 | return Task::ready(Err(anyhow!("Failed to find a worktree"))); |
| 1476 | }; | 1467 | }; |
| 1477 | 1468 | ||
| 1478 | self.dap_store | 1469 | let Some(adapter) = self.debug_adapters.adapter(&config.adapter) else { |
| 1479 | .update(cx, |dap_store, cx| { | 1470 | return Task::ready(Err(anyhow!("Failed to find a debug adapter"))); |
| 1480 | dap_store.new_session(config, worktree, None, cx) | 1471 | }; |
| 1481 | }) | ||
| 1482 | .1 | ||
| 1483 | } | ||
| 1484 | 1472 | ||
| 1485 | #[cfg(any(test, feature = "test-support"))] | 1473 | let user_installed_path = ProjectSettings::get_global(cx) |
| 1486 | pub fn fake_debug_session( | 1474 | .dap |
| 1487 | &mut self, | 1475 | .get(&adapter.name()) |
| 1488 | request: task::DebugRequestType, | 1476 | .and_then(|s| s.binary.as_ref().map(PathBuf::from)); |
| 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; | ||
| 1495 | 1477 | ||
| 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 | })?; | ||
| 1497 | 1484 | ||
| 1498 | let Some(worktree) = &worktree else { | 1485 | let binary = adapter |
| 1499 | return Task::ready(Err(anyhow!("Failed to find a worktree"))); | 1486 | .get_binary(&delegate, &config, user_installed_path, cx) |
| 1500 | }; | 1487 | .await?; |
| 1501 | let config = DebugAdapterConfig { | 1488 | |
| 1502 | label: "test config".into(), | 1489 | let ret = this |
| 1503 | adapter: FakeAdapter::ADAPTER_NAME.into(), | 1490 | .update(cx, |project, cx| { |
| 1504 | request: DebugRequestDisposition::UserConfigured(request), | 1491 | project.dap_store.update(cx, |dap_store, cx| { |
| 1505 | initialize_args: None, | 1492 | dap_store.new_session(binary, config, None, cx) |
| 1506 | tcp_connection: None, | 1493 | }) |
| 1507 | locator: None, | 1494 | })? |
| 1508 | stop_on_entry: None, | 1495 | .1 |
| 1509 | }; | 1496 | .await; |
| 1510 | let caps = caps.unwrap_or(Capabilities { | 1497 | ret |
| 1511 | supports_step_back: Some(false), | ||
| 1512 | ..Default::default() | ||
| 1513 | }); | 1498 | }); |
| 1514 | self.dap_store | 1499 | result |
| 1515 | .update(cx, |dap_store, cx| { | ||
| 1516 | dap_store.new_fake_session(config, worktree, None, caps, fails, cx) | ||
| 1517 | }) | ||
| 1518 | .1 | ||
| 1519 | } | 1500 | } |
| 1520 | 1501 | ||
| 1521 | #[cfg(any(test, feature = "test-support"))] | 1502 | #[cfg(any(test, feature = "test-support"))] |
| @@ -39,7 +39,7 @@ use std::{env, mem, num::NonZeroU32, ops::Range, str::FromStr, sync::OnceLock, t · 38 unmodified lines | |||
| 39 | use task::{ResolvedTask, TaskContext}; | 39 | use task::{ResolvedTask, TaskContext}; |
| 40 | use unindent::Unindent as _; | 40 | use unindent::Unindent as _; |
| 41 | use util::{ | 41 | use util::{ |
| 42 | TryFutureExt as _, assert_set_eq, path, | 42 | TryFutureExt as _, assert_set_eq, maybe, path, |
| 43 | paths::PathMatcher, | 43 | paths::PathMatcher, |
| 44 | separator, | 44 | separator, |
| 45 | test::{TempTree, marked_text_offsets}, | 45 | test::{TempTree, marked_text_offsets}, |
| @@ -72,7 +72,7 @@ impl HeadlessProject { · 71 unmodified lines | |||
| 72 | http_client, | 72 | http_client, |
| 73 | node_runtime, | 73 | node_runtime, |
| 74 | languages, | 74 | languages, |
| 75 | debug_adapters, | 75 | debug_adapters: _debug_adapters, |
| 76 | extension_host_proxy: proxy, | 76 | extension_host_proxy: proxy, |
| 77 | }: HeadlessAppState, | 77 | }: HeadlessAppState, |
| 78 | cx: &mut Context<Self>, | 78 | cx: &mut Context<Self>, |
| @@ -112,11 +112,9 @@ impl HeadlessProject { · 33 unmodified lines | |||
| 112 | node_runtime.clone(), | 112 | node_runtime.clone(), |
| 113 | fs.clone(), | 113 | fs.clone(), |
| 114 | languages.clone(), | 114 | languages.clone(), |
| 115 | debug_adapters.clone(), | ||
| 116 | environment.clone(), | 115 | environment.clone(), |
| 117 | toolchain_store.read(cx).as_language_toolchain_store(), | 116 | toolchain_store.read(cx).as_language_toolchain_store(), |
| 118 | breakpoint_store.clone(), | 117 | breakpoint_store.clone(), |
| 119 | worktree_store.clone(), | ||
| 120 | cx, | 118 | cx, |
| 121 | ) | 119 | ) |
| 122 | }); | 120 | }); |
| @@ -104,7 +104,7 @@ impl ResolvedTask { · 103 unmodified lines | |||
| 104 | } | 104 | } |
| 105 | 105 | ||
| 106 | /// Get the configuration for the debug adapter that should be used for this task. | 106 | /// 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> { |
| 108 | match self.original_task.task_type.clone() { | 108 | match self.original_task.task_type.clone() { |
| 109 | TaskType::Debug(debug_args) if self.resolved.is_some() => { | 109 | TaskType::Debug(debug_args) if self.resolved.is_some() => { |
| 110 | let resolved = self | 110 | let resolved = self |
| @@ -127,10 +127,10 @@ impl ResolvedTask { · 16 unmodified lines | |||
| 127 | }) | 127 | }) |
| 128 | .collect(); | 128 | .collect(); |
| 129 | 129 | ||
| 130 | Some(DebugAdapterConfig { | 130 | Some(DebugTaskDefinition { |
| 131 | label: resolved.label.clone(), | 131 | label: resolved.label.clone(), |
| 132 | adapter: debug_args.adapter.clone(), | 132 | adapter: debug_args.adapter.clone(), |
| 133 | request: DebugRequestDisposition::UserConfigured(match debug_args.request { | 133 | request: match debug_args.request { |
| 134 | crate::task_template::DebugArgsRequest::Launch => { | 134 | crate::task_template::DebugArgsRequest::Launch => { |
| 135 | DebugRequestType::Launch(LaunchConfig { | 135 | DebugRequestType::Launch(LaunchConfig { |
| 136 | program: resolved.command.clone(), | 136 | program: resolved.command.clone(), |
| @@ -141,7 +141,7 @@ impl ResolvedTask { · 4 unmodified lines | |||
| 141 | crate::task_template::DebugArgsRequest::Attach(attach_config) => { | 141 | crate::task_template::DebugArgsRequest::Attach(attach_config) => { |
| 142 | DebugRequestType::Attach(attach_config) | 142 | DebugRequestType::Attach(attach_config) |
| 143 | } | 143 | } |
| 144 | }), | 144 | }, |
| 145 | initialize_args: debug_args.initialize_args, | 145 | initialize_args: debug_args.initialize_args, |
| 146 | tcp_connection: debug_args.tcp_connection, | 146 | tcp_connection: debug_args.tcp_connection, |
| 147 | locator: debug_args.locator.clone(), | 147 | locator: debug_args.locator.clone(), |
| @@ -361,9 +361,8 @@ impl PickerDelegate for TasksModalDelegate { · 360 unmodified lines | |||
| 361 | 361 | ||
| 362 | match task.task_type() { | 362 | match task.task_type() { |
| 363 | TaskType::Debug(config) if config.locator.is_none() => { | 363 | TaskType::Debug(config) if config.locator.is_none() => { |
| 364 | let Some(config): Option<DebugTaskDefinition> = task | 364 | let Some(config): Option<DebugTaskDefinition> = |
| 365 | .resolved_debug_adapter_config() | 365 | task.resolved_debug_adapter_config() |
| 366 | .and_then(|config| config.try_into().ok()) | ||
| 367 | else { | 366 | else { |
| 368 | return; | 367 | return; |
| 369 | }; | 368 | }; |
| @@ -382,7 +381,7 @@ impl PickerDelegate for TasksModalDelegate { · 12 unmodified lines | |||
| 382 | .update(cx, |workspace, cx| { | 381 | .update(cx, |workspace, cx| { |
| 383 | workspace.project().update(cx, |project, cx| { | 382 | workspace.project().update(cx, |project, cx| { |
| 384 | project | 383 | project |
| 385 | .start_debug_session(config.into(), cx) | 384 | .start_debug_session(config, cx) |
| 386 | .detach_and_log_err(cx); | 385 | .detach_and_log_err(cx); |
| 387 | }); | 386 | }); |
| 388 | }) | 387 | }) |
| @@ -96,7 +96,7 @@ use std::{ · 95 unmodified lines | |||
| 96 | sync::{Arc, LazyLock, Weak, atomic::AtomicUsize}, | 96 | sync::{Arc, LazyLock, Weak, atomic::AtomicUsize}, |
| 97 | time::Duration, | 97 | time::Duration, |
| 98 | }; | 98 | }; |
| 99 | use task::{DebugAdapterConfig, SpawnInTerminal, TaskId}; | 99 | use task::{DebugTaskDefinition, SpawnInTerminal, TaskId}; |
| 100 | use theme::{ActiveTheme, SystemAppearance, ThemeSettings}; | 100 | use theme::{ActiveTheme, SystemAppearance, ThemeSettings}; |
| 101 | pub use toolbar::{Toolbar, ToolbarItemEvent, ToolbarItemLocation, ToolbarItemView}; | 101 | pub use toolbar::{Toolbar, ToolbarItemEvent, ToolbarItemLocation, ToolbarItemView}; |
| 102 | pub use ui; | 102 | pub use ui; |
| @@ -858,7 +858,7 @@ pub struct Workspace { · 755 unmodified lines | |||
| 858 | serialized_ssh_project: Option<SerializedSshProject>, | 858 | serialized_ssh_project: Option<SerializedSshProject>, |
| 859 | _items_serializer: Task<Result<()>>, | 859 | _items_serializer: Task<Result<()>>, |
| 860 | session_id: Option<String>, | 860 | session_id: Option<String>, |
| 861 | debug_task_queue: HashMap<task::TaskId, DebugAdapterConfig>, | 861 | debug_task_queue: HashMap<task::TaskId, DebugTaskDefinition>, |
| 862 | } | 862 | } |
| 863 | 863 | ||
| 864 | impl EventEmitter<Event> for Workspace {} | 864 | impl EventEmitter<Event> for Workspace {} |