From 95590967ebddbc688fa2da13237fb319073c73ae Mon Sep 17 00:00:00 2001 From: Piotr Osiewicz <24362066+osiewicz@users.noreply.github.com> Date: Mon, 17 Feb 2025 16:51:39 +0100 Subject: [PATCH] WIP --- crates/dap/src/adapters.rs | 21 ++- crates/dap/src/client.rs | 105 ++++++++------- crates/dap/src/transport.rs | 157 ++++++++++++++++------- crates/dap_adapters/src/custom.rs | 6 +- crates/dap_adapters/src/go.rs | 6 +- crates/dap_adapters/src/javascript.rs | 6 +- crates/dap_adapters/src/lldb.rs | 6 +- crates/dap_adapters/src/php.rs | 11 +- crates/dap_adapters/src/python.rs | 6 +- crates/debugger_tools/src/dap_log.rs | 2 +- crates/project/src/debugger/dap_store.rs | 2 +- crates/project/src/debugger/session.rs | 72 ++++++++--- 12 files changed, 245 insertions(+), 155 deletions(-) diff --git a/crates/dap/src/adapters.rs b/crates/dap/src/adapters.rs index a15c1ebfc2..4758640698 100644 --- a/crates/dap/src/adapters.rs +++ b/crates/dap/src/adapters.rs @@ -1,6 +1,5 @@ #[cfg(any(test, feature = "test-support"))] use crate::transport::FakeTransport; -use crate::transport::Transport; use ::fs::Fs; use anyhow::{anyhow, Context as _, Ok, Result}; use async_compression::futures::bufread::GzipDecoder; @@ -19,9 +18,11 @@ use std::{ collections::{HashMap, HashSet}, ffi::{OsStr, OsString}, fmt::Debug, + net::Ipv4Addr, ops::Deref, path::{Path, PathBuf}, sync::Arc, + time::Duration, }; use sysinfo::{Pid, Process}; use task::DebugAdapterConfig; @@ -89,12 +90,19 @@ impl<'a> From<&'a str> for DebugAdapterName { } } +#[derive(Debug, Clone)] +pub struct TcpArguments { + pub host: Ipv4Addr, + pub port: Option, + pub timeout: Option, +} #[derive(Debug, Clone)] pub struct DebugAdapterBinary { pub command: String, pub arguments: Option>, pub envs: Option>, pub cwd: Option, + pub connection: Option, } pub struct AdapterVersion { @@ -261,8 +269,6 @@ pub trait DebugAdapter: 'static + Send + Sync { .await } - fn transport(&self) -> Arc; - async fn fetch_latest_adapter_version( &self, delegate: &dyn DapDelegate, @@ -316,10 +322,6 @@ impl DebugAdapter for FakeAdapter { DebugAdapterName(Self::ADAPTER_NAME.into()) } - fn transport(&self) -> Arc { - Arc::new(FakeTransport::new()) - } - async fn get_binary( &self, _: &dyn DapDelegate, @@ -330,6 +332,11 @@ impl DebugAdapter for FakeAdapter { Ok(DebugAdapterBinary { command: "command".into(), arguments: None, + connection: Some(TcpArguments { + host: Ipv4Addr::LOCALHOST, + port: None, + timeout: None, + }), envs: None, cwd: None, }) diff --git a/crates/dap/src/client.rs b/crates/dap/src/client.rs index 9499a83c20..cd5d755295 100644 --- a/crates/dap/src/client.rs +++ b/crates/dap/src/client.rs @@ -45,27 +45,52 @@ pub struct DebugAdapterClient { sequence_count: AtomicU64, binary: DebugAdapterBinary, executor: BackgroundExecutor, - adapter: Arc, transport_delegate: TransportDelegate, } impl DebugAdapterClient { - pub fn new( - id: DebugAdapterClientId, - adapter: Arc, - binary: DebugAdapterBinary, - cx: &AsyncApp, - ) -> Self { - let transport_delegate = TransportDelegate::new(adapter.transport()); + pub fn new(cx: &AsyncApp) -> Self {} - Self { + pub async fn start( + id: DebugAdapterClientId, + binary: DebugAdapterBinary, + message_handler: F, + cx: &mut AsyncApp, + ) -> Result<()> + where + F: FnMut(Message, &mut App) + 'static + Send + Sync + Clone, + { + let transport_delegate = TransportDelegate::new(binary.clone()); + let this = Self { id, binary, - adapter, + transport_delegate, sequence_count: AtomicU64::new(1), executor: cx.background_executor().clone(), - } + }; + let (server_rx, server_tx) = this.transport_delegate.start(&self.binary, cx).await?; + log::info!("Successfully connected to debug adapter"); + + let client_id = self.id; + + // start handling events/reverse requests + cx.update(|cx| { + cx.spawn({ + let server_tx = server_tx.clone(); + |mut cx| async move { + Self::handle_receive_messages( + client_id, + server_rx, + server_tx, + message_handler, + &mut cx, + ) + .await + } + }) + .detach_and_log_err(cx); + }) } pub async fn reconnect(&mut self, message_handler: F, cx: &mut AsyncApp) -> Result<()> @@ -95,35 +120,6 @@ impl DebugAdapterClient { .detach_and_log_err(cx); }) } - - pub async fn start(&mut self, message_handler: F, cx: &mut AsyncApp) -> Result<()> - where - F: FnMut(Message, &mut App) + 'static + Send + Sync + Clone, - { - let (server_rx, server_tx) = self.transport_delegate.start(&self.binary, cx).await?; - log::info!("Successfully connected to debug adapter"); - - let client_id = self.id; - - // start handling events/reverse requests - cx.update(|cx| { - cx.spawn({ - let server_tx = server_tx.clone(); - |mut cx| async move { - Self::handle_receive_messages( - client_id, - server_rx, - server_tx, - message_handler, - &mut cx, - ) - .await - } - }) - .detach_and_log_err(cx); - }) - } - async fn handle_receive_messages( client_id: DebugAdapterClientId, server_rx: Receiver, @@ -229,18 +225,10 @@ impl DebugAdapterClient { self.id } - pub fn adapter(&self) -> &Arc { - &self.adapter - } - pub fn binary(&self) -> &DebugAdapterBinary { &self.binary } - pub fn adapter_id(&self) -> String { - self.adapter.name().to_string() - } - /// Get the next sequence id to be used in a request pub fn next_sequence_id(&self) -> u64 { self.sequence_count.fetch_add(1, Ordering::Relaxed) @@ -335,15 +323,17 @@ mod tests { pub async fn test_initialize_client(cx: &mut TestAppContext) { init_test(cx); - let adapter = Arc::new(FakeAdapter::new()); - let mut client = DebugAdapterClient::new( crate::client::DebugAdapterClientId(1), - adapter, DebugAdapterBinary { command: "command".into(), arguments: Default::default(), envs: Default::default(), + connection: Some(TcpArguments { + host: Ipv4Addr::LOCALHOST, + port: None, + timeout: None, + }), cwd: None, }, &mut cx.to_async(), @@ -412,11 +402,15 @@ mod tests { let mut client = DebugAdapterClient::new( crate::client::DebugAdapterClientId(1), - adapter, DebugAdapterBinary { command: "command".into(), arguments: Default::default(), envs: Default::default(), + connection: Some(TCPArguments { + host: Ipv4Addr::LOCALHOST, + port: None, + path: None, + }), cwd: None, }, &mut cx.to_async(), @@ -467,11 +461,16 @@ mod tests { let mut client = DebugAdapterClient::new( crate::client::DebugAdapterClientId(1), - adapter, DebugAdapterBinary { command: "command".into(), arguments: Default::default(), envs: Default::default(), + + connection: Some(TCPArguments { + host: Ipv4Addr::LOCALHOST, + port: None, + path: None, + }), cwd: None, }, &mut cx.to_async(), diff --git a/crates/dap/src/transport.rs b/crates/dap/src/transport.rs index 2e95f639a9..911d3a2753 100644 --- a/crates/dap/src/transport.rs +++ b/crates/dap/src/transport.rs @@ -68,18 +68,88 @@ impl TransportPipe { type Requests = Arc>>>>; type LogHandlers = Arc>>; +enum Transport { + Stdio(StdioTransport), + Tcp(TcpTransport), + #[cfg(any(test, feature = "test-support"))] + Fake(FakeTransport), +} + +impl Transport { + async fn start(&self, binary: &DebugAdapterBinary, cx: &mut AsyncApp) -> Result { + match self { + Transport::Stdio(stdio_transport) => stdio_transport.start(binary, cx).await, + Transport::Tcp(tcp_transport) => tcp_transport.start(binary, cx).await, + #[cfg(any(test, feature = "test-support"))] + Transport::Fake(fake_transport) => fake_transport.start(binary, cx).await, + } + } + + fn has_adapter_logs(&self) -> bool { + match self { + Transport::Stdio(stdio_transport) => stdio_transport.has_adapter_logs(), + Transport::Tcp(tcp_transport) => tcp_transport.has_adapter_logs(), + #[cfg(any(test, feature = "test-support"))] + Transport::Fake(fake_transport) => fake_transport.has_adapter_logs(), + } + } + + async fn kill(&self) -> Result<()> { + match self { + Transport::Stdio(stdio_transport) => stdio_transport.kill().await, + Transport::Tcp(tcp_transport) => tcp_transport.kill().await, + #[cfg(any(test, feature = "test-support"))] + Transport::Fake(fake_transport) => fake_transport.kill().await, + } + } + + async fn reconnect(&self, cx: &mut AsyncApp) -> Result { + match self { + Transport::Stdio(stdio_transport) => stdio_transport.reconnect(cx).await, + Transport::Tcp(tcp_transport) => tcp_transport.reconnect(cx).await, + #[cfg(any(test, feature = "test-support"))] + Transport::Fake(fake_transport) => fake_transport.reconnect(cx).await, + } + } + + #[cfg(any(test, feature = "test-support"))] + fn as_fake(&self) -> &FakeTransport { + match self { + Transport::Fake(fake_transport) => fake_transport, + _ => panic!("Not a fake transport layer"), + } + } +} + pub(crate) struct TransportDelegate { log_handlers: LogHandlers, current_requests: Requests, pending_requests: Requests, - transport: Arc, + transport: Transport, server_tx: Arc>>>, } +impl Transport { + #[cfg(any(test, feature = "test-support"))] + fn fake(args: DebugAdapterBinary) -> Self { + let this = Self::Fake(FakeTransport::new()); + } +} + impl TransportDelegate { - pub fn new(transport: Arc) -> Self { + pub async fn new(args: DebugAdapterBinary) -> Self { Self { - transport, + transport: Transport::new(args).await, + server_tx: Default::default(), + log_handlers: Default::default(), + current_requests: Default::default(), + pending_requests: Default::default(), + } + } + #[cfg(any(test, feature = "test-support"))] + pub fn fake(args: DebugAdapterBinary) -> Self { + Self { + transport: Transport::fake(args), server_tx: Default::default(), log_handlers: Default::default(), current_requests: Default::default(), @@ -475,41 +545,14 @@ impl TransportDelegate { } } -#[async_trait(?Send)] -pub trait Transport: 'static + Send + Sync + Any { - async fn start(&self, binary: &DebugAdapterBinary, cx: &mut AsyncApp) -> Result; - - fn has_adapter_logs(&self) -> bool; - - async fn kill(&self) -> Result<()>; - - async fn reconnect(&self, _: &mut AsyncApp) -> Result { - bail!("Cannot reconnect to adapter") - } - - #[cfg(any(test, feature = "test-support"))] - fn as_fake(&self) -> &FakeTransport { - panic!("Called as_fake on a real adapter"); - } -} - pub struct TcpTransport { port: u16, host: Ipv4Addr, timeout: Option, - process: Arc>>, + process: Arc>, } impl TcpTransport { - pub fn new(host: Ipv4Addr, port: u16, timeout: Option) -> Self { - Self { - port, - host, - timeout, - process: Arc::new(Mutex::new(None)), - } - } - /// Get an open port to use with the tcp client when not supplied by debug config pub async fn port(host: &TCPHost) -> Result { if let Some(port) = host.port { @@ -521,10 +564,13 @@ impl TcpTransport { .port()) } } -} + async fn port_for_host(host: Ipv4Addr) -> Result { + Ok(TcpListener::bind(SocketAddrV4::new(host, 0)) + .await? + .local_addr()? + .port()) + } -#[async_trait(?Send)] -impl Transport for TcpTransport { async fn reconnect(&self, cx: &mut AsyncApp) -> Result { let address = SocketAddrV4::new(self.host, self.port); @@ -563,7 +609,26 @@ impl Transport for TcpTransport { )) } - async fn start(&self, binary: &DebugAdapterBinary, cx: &mut AsyncApp) -> Result { + async fn start(binary: &DebugAdapterBinary, cx: &mut AsyncApp) -> Result { + let Some(connection_args) = binary.connection.as_ref() else { + return Err(anyhow!("No connection arguments provided")); + }; + let host = connection_args.host; + let port = if let Some(port) = connection_args.port { + port + } else { + TcpListener::bind(SocketAddrV4::new(host, 0)) + .await + .with_context(|| { + format!( + "Failed to connect to debug adapter over tcp. host: {}", + host + ) + })? + .local_addr()? + .port() + }; + let mut command = util::command::new_smol_command(&binary.command); if let Some(cwd) = &binary.cwd { @@ -588,16 +653,16 @@ impl Transport for TcpTransport { .spawn() .with_context(|| "failed to start debug adapter.")?; - let address = SocketAddrV4::new(self.host, self.port); + let address = SocketAddrV4::new(host, port); - let timeout = self.timeout.unwrap_or_else(|| { + let timeout = connection_args.timeout.unwrap_or_else(|| { cx.update(|cx| DebuggerSettings::get_global(cx).timeout) .unwrap_or(2000u64) }); let (rx, tx) = select! { _ = cx.background_executor().timer(Duration::from_millis(timeout)).fuse() => { - return Err(anyhow!(format!("Connection to TCP DAP timeout {}:{}", self.host, self.port))) + return Err(anyhow!(format!("Connection to TCP DAP timeout {}:{}", host, port))) }, result = cx.spawn(|cx| async move { loop { @@ -612,8 +677,8 @@ impl Transport for TcpTransport { }; log::info!( "Debug adapter has connected to TCP server {}:{}", - self.host, - self.port + host, + port ); let stdout = process.stdout.take(); @@ -654,10 +719,7 @@ impl StdioTransport { process: Arc::new(Mutex::new(None)), } } -} -#[async_trait(?Send)] -impl Transport for StdioTransport { async fn start(&self, binary: &DebugAdapterBinary, _: &mut AsyncApp) -> Result { let mut command = util::command::new_smol_command(&binary.command); @@ -721,6 +783,10 @@ impl Transport for StdioTransport { false } + async fn reconnect(&self, _: &mut AsyncApp) -> Result { + bail!("Cannot reconnect to adapter") + } + async fn kill(&self) -> Result<()> { if let Some(mut process) = self.process.lock().await.take() { process.kill()?; @@ -803,11 +869,7 @@ impl FakeTransport { .await .insert(R::COMMAND, Box::new(handler)); } -} -#[cfg(any(test, feature = "test-support"))] -#[async_trait(?Send)] -impl Transport for FakeTransport { async fn reconnect(&self, cx: &mut AsyncApp) -> Result { self.start( &DebugAdapterBinary { @@ -815,6 +877,7 @@ impl Transport for FakeTransport { arguments: None, envs: None, cwd: None, + connection: TcpTransport::new(None, None), }, cx, ) diff --git a/crates/dap_adapters/src/custom.rs b/crates/dap_adapters/src/custom.rs index 6abec9407f..c2a8f883d3 100644 --- a/crates/dap_adapters/src/custom.rs +++ b/crates/dap_adapters/src/custom.rs @@ -1,6 +1,6 @@ use std::{ffi::OsString, path::PathBuf, sync::Arc}; -use dap::transport::{StdioTransport, TcpTransport, Transport}; +use dap::transport::{StdioTransport, TcpTransport}; use gpui::AsyncApp; use serde_json::Value; use task::DebugAdapterConfig; @@ -36,10 +36,6 @@ impl DebugAdapter for CustomDebugAdapter { DebugAdapterName(Self::ADAPTER_NAME.into()) } - fn transport(&self) -> Arc { - self.transport.clone() - } - async fn get_binary( &self, _: &dyn DapDelegate, diff --git a/crates/dap_adapters/src/go.rs b/crates/dap_adapters/src/go.rs index d19a3f2290..0a1d4703b4 100644 --- a/crates/dap_adapters/src/go.rs +++ b/crates/dap_adapters/src/go.rs @@ -1,4 +1,4 @@ -use dap::transport::{TcpTransport, Transport}; +use dap::transport::TcpTransport; use gpui::AsyncApp; use std::{ffi::OsStr, net::Ipv4Addr, path::PathBuf, sync::Arc}; @@ -28,10 +28,6 @@ impl DebugAdapter for GoDebugAdapter { DebugAdapterName(Self::ADAPTER_NAME.into()) } - fn transport(&self) -> Arc { - Arc::new(TcpTransport::new(self.host, self.port, self.timeout)) - } - async fn get_binary( &self, delegate: &dyn DapDelegate, diff --git a/crates/dap_adapters/src/javascript.rs b/crates/dap_adapters/src/javascript.rs index 7657cc9f44..b96633fefe 100644 --- a/crates/dap_adapters/src/javascript.rs +++ b/crates/dap_adapters/src/javascript.rs @@ -1,5 +1,5 @@ use adapters::latest_github_release; -use dap::transport::{TcpTransport, Transport}; +use dap::transport::TcpTransport; use gpui::AsyncApp; use regex::Regex; use std::{collections::HashMap, net::Ipv4Addr, path::PathBuf, sync::Arc}; @@ -33,10 +33,6 @@ impl DebugAdapter for JsDebugAdapter { DebugAdapterName(Self::ADAPTER_NAME.into()) } - fn transport(&self) -> Arc { - Arc::new(TcpTransport::new(self.host, self.port, self.timeout)) - } - async fn fetch_latest_adapter_version( &self, delegate: &dyn DapDelegate, diff --git a/crates/dap_adapters/src/lldb.rs b/crates/dap_adapters/src/lldb.rs index 7b5a804e0f..fbf5479129 100644 --- a/crates/dap_adapters/src/lldb.rs +++ b/crates/dap_adapters/src/lldb.rs @@ -2,7 +2,7 @@ use std::{collections::HashMap, ffi::OsStr, path::PathBuf, sync::Arc}; use anyhow::Result; use async_trait::async_trait; -use dap::transport::{StdioTransport, Transport}; +use dap::transport::StdioTransport; use gpui::AsyncApp; use sysinfo::{Pid, Process}; use task::{DebugAdapterConfig, DebugRequestType}; @@ -25,10 +25,6 @@ impl DebugAdapter for LldbDebugAdapter { DebugAdapterName(Self::ADAPTER_NAME.into()) } - fn transport(&self) -> Arc { - Arc::new(StdioTransport::new()) - } - async fn get_binary( &self, delegate: &dyn DapDelegate, diff --git a/crates/dap_adapters/src/php.rs b/crates/dap_adapters/src/php.rs index 23aa2c30ef..98d7474e6f 100644 --- a/crates/dap_adapters/src/php.rs +++ b/crates/dap_adapters/src/php.rs @@ -1,5 +1,5 @@ use adapters::latest_github_release; -use dap::transport::{TcpTransport, Transport}; +use dap::{adapters::TcpArguments, transport::TcpTransport}; use gpui::AsyncApp; use std::{net::Ipv4Addr, path::PathBuf, sync::Arc}; @@ -30,10 +30,6 @@ impl DebugAdapter for PhpDebugAdapter { DebugAdapterName(Self::ADAPTER_NAME.into()) } - fn transport(&self) -> Arc { - Arc::new(TcpTransport::new(self.host, self.port, self.timeout)) - } - async fn fetch_latest_adapter_version( &self, delegate: &dyn DapDelegate, @@ -92,6 +88,11 @@ impl DebugAdapter for PhpDebugAdapter { adapter_path.join(Self::ADAPTER_PATH).into(), format!("--server={}", self.port).into(), ]), + connection: Some(TcpArguments { + port: Some(self.port), + host: Ipv4Addr::LOCALHOST, + timeout: None, + }), cwd: config.cwd.clone(), envs: None, }) diff --git a/crates/dap_adapters/src/python.rs b/crates/dap_adapters/src/python.rs index e44cadd22e..e33f8ffbfc 100644 --- a/crates/dap_adapters/src/python.rs +++ b/crates/dap_adapters/src/python.rs @@ -1,5 +1,5 @@ use crate::*; -use dap::transport::{TcpTransport, Transport}; +use dap::transport::TcpTransport; use gpui::AsyncApp; use std::{ffi::OsStr, net::Ipv4Addr, path::PathBuf, sync::Arc}; @@ -29,10 +29,6 @@ impl DebugAdapter for PythonDebugAdapter { DebugAdapterName(Self::ADAPTER_NAME.into()) } - fn transport(&self) -> Arc { - Arc::new(TcpTransport::new(self.host, self.port, self.timeout)) - } - async fn fetch_latest_adapter_version( &self, delegate: &dyn DapDelegate, diff --git a/crates/debugger_tools/src/dap_log.rs b/crates/debugger_tools/src/dap_log.rs index 8bea2a632e..241b6d7123 100644 --- a/crates/debugger_tools/src/dap_log.rs +++ b/crates/debugger_tools/src/dap_log.rs @@ -573,7 +573,7 @@ impl DapLogView { let client = client.read(cx).adapter_client()?; Some(DapMenuItem { client_id: client.id(), - client_name: client.adapter_id(), + client_name: unimplemented!(), has_adapter_logs: client.has_adapter_logs(), selected_entry: self.current_view.map_or(LogKind::Adapter, |(_, kind)| kind), }) diff --git a/crates/project/src/debugger/dap_store.rs b/crates/project/src/debugger/dap_store.rs index e4b0258049..2fd919e647 100644 --- a/crates/project/src/debugger/dap_store.rs +++ b/crates/project/src/debugger/dap_store.rs @@ -620,7 +620,7 @@ impl DapStore { } }; - let mut client = DebugAdapterClient::new(client_id, adapter, binary, &cx); + let mut client = DebugAdapterClient::new(client_id, binary, &cx); client .start( diff --git a/crates/project/src/debugger/session.rs b/crates/project/src/debugger/session.rs index 3621d4ad68..05194c2e77 100644 --- a/crates/project/src/debugger/session.rs +++ b/crates/project/src/debugger/session.rs @@ -1,17 +1,20 @@ +use super::breakpoint_store::BreakpointStore; use super::dap_command::{ self, ContinueCommand, DapCommand, DisconnectCommand, EvaluateCommand, NextCommand, PauseCommand, RestartCommand, RestartStackFrameCommand, ScopesCommand, SetVariableValueCommand, StepBackCommand, StepCommand, StepInCommand, StepOutCommand, TerminateCommand, TerminateThreadsCommand, VariablesCommand, }; +use super::dap_store::DapAdapterDelegate; use anyhow::{anyhow, Result}; use collections::{HashMap, IndexMap}; use dap::client::{DebugAdapterClient, DebugAdapterClientId}; use dap::{ Capabilities, ContinueArguments, EvaluateArgumentsContext, Module, Source, SteppingGranularity, }; +use dap_adapters::build_adapter; use futures::{future::Shared, FutureExt}; -use gpui::{App, Context, Entity, Task}; +use gpui::{App, AppContext, Context, Entity, Task}; use rpc::AnyProtoClient; use serde_json::Value; use std::u64; @@ -142,10 +145,37 @@ impl RemoteConnection { } pub enum Mode { - Local(Arc), + Local(LocalMode), Remote(RemoteConnection), } +struct LocalMode { + client: Arc, +} + +impl LocalMode { + fn new( + breakpoint_store: Entity, + disposition: DebugAdapterConfig, + delegate: DapAdapterDelegate, + cx: &mut App, + ) -> Task> { + cx.spawn(move |cx| async move { + let adapter = build_adapter(&config.kind).await?; + + let binary = cx.update(|cx| { + let name = DebugAdapterName::from(adapter.name().as_ref()); + + ProjectSettings::get_global(cx) + .dap + .get(&name) + .and_then(|s| s.binary.as_ref().map(PathBuf::from)) + })?; + + todo!() + }) + } +} impl From for Mode { fn from(value: RemoteConnection) -> Self { Self::Remote(value) @@ -293,20 +323,30 @@ impl CompletionsQuery { } impl Session { - pub(crate) fn local(adapter: Arc, config: DebugAdapterConfig) -> Self { - let client_id = adapter.id(); - - Self { - mode: Mode::Local(adapter), - client_id, - config, - capabilities: unimplemented!(), - ignore_breakpoints: false, - requests: HashMap::default(), - modules: Vec::default(), - loaded_sources: Vec::default(), - threads: IndexMap::default(), - } + pub(crate) fn local( + breakpoints: Entity, + client_id: DebugAdapterClientId, + delegate: DapAdapterDelegate, + config: DebugAdapterConfig, + cx: &mut App, + ) -> Task>> { + cx.spawn(move |cx| async move { + let adapter = build_adapter(&config.kind).await?; + let mode = LocalMode::new(breakpoints, config, adapter, cx).await?; + cx.update(|cx| { + cx.new(|cx| Self { + mode: Mode::Local(mode), + client_id, + config, + capabilities: unimplemented!(), + ignore_breakpoints: false, + requests: HashMap::default(), + modules: Vec::default(), + loaded_sources: Vec::default(), + threads: IndexMap::default(), + }) + }) + }) } pub(crate) fn remote(