Tidy up DAP initialization (#28730)
To make DAP work over SSH we want to create the binary at the project level (so we can wrap it in an `ssh` invocation transparently). This means not pushing the adapter down into the session, and resolving more information ahead-of-time. Co-authored-by: Anthony Eid <hello@anthonyeid.me> Co-authored-by: Piotr <piotr@zed.dev> Release Notes: - N/A --------- Co-authored-by: Anthony Eid <hello@anthonyeid.me> Co-authored-by: Piotr <piotr@zed.dev> Co-authored-by: Piotr Osiewicz <24362066+osiewicz@users.noreply.github.com> Co-authored-by: Anthony <anthony@zed.dev>
This commit is contained in:
parent
6f0951ff77
commit
aef78dcffd
@ -3,13 +3,13 @@ use anyhow::{Context as _, Ok, Result, anyhow};
|
||||
use async_compression::futures::bufread::GzipDecoder;
|
||||
use async_tar::Archive;
|
||||
use async_trait::async_trait;
|
||||
use dap_types::StartDebuggingRequestArguments;
|
||||
use futures::io::BufReader;
|
||||
use gpui::{AsyncApp, SharedString};
|
||||
pub use http_client::{HttpClient, github::latest_github_release};
|
||||
use language::LanguageToolchainStore;
|
||||
use node_runtime::NodeRuntime;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use serde_json::Value;
|
||||
use settings::WorktreeId;
|
||||
use smol::{self, fs::File, lock::Mutex};
|
||||
use std::{
|
||||
@ -22,7 +22,7 @@ use std::{
|
||||
path::PathBuf,
|
||||
sync::Arc,
|
||||
};
|
||||
use task::{DebugAdapterConfig, DebugTaskDefinition};
|
||||
use task::DebugTaskDefinition;
|
||||
use util::ResultExt;
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||
@ -93,13 +93,15 @@ pub struct TcpArguments {
|
||||
pub port: u16,
|
||||
pub timeout: Option<u64>,
|
||||
}
|
||||
#[derive(Default, Debug, Clone)]
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct DebugAdapterBinary {
|
||||
pub adapter_name: DebugAdapterName,
|
||||
pub command: String,
|
||||
pub arguments: Option<Vec<OsString>>,
|
||||
pub envs: Option<HashMap<String, String>>,
|
||||
pub cwd: Option<PathBuf>,
|
||||
pub connection: Option<TcpArguments>,
|
||||
pub request_args: StartDebuggingRequestArguments,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
@ -220,7 +222,7 @@ pub trait DebugAdapter: 'static + Send + Sync {
|
||||
async fn get_binary(
|
||||
&self,
|
||||
delegate: &dyn DapDelegate,
|
||||
config: &DebugAdapterConfig,
|
||||
config: &DebugTaskDefinition,
|
||||
user_installed_path: Option<PathBuf>,
|
||||
cx: &mut AsyncApp,
|
||||
) -> Result<DebugAdapterBinary> {
|
||||
@ -284,13 +286,10 @@ pub trait DebugAdapter: 'static + Send + Sync {
|
||||
async fn get_installed_binary(
|
||||
&self,
|
||||
delegate: &dyn DapDelegate,
|
||||
config: &DebugAdapterConfig,
|
||||
config: &DebugTaskDefinition,
|
||||
user_installed_path: Option<PathBuf>,
|
||||
cx: &mut AsyncApp,
|
||||
) -> Result<DebugAdapterBinary>;
|
||||
|
||||
/// Should return base configuration to make the debug adapter work
|
||||
fn request_args(&self, config: &DebugTaskDefinition) -> Value;
|
||||
}
|
||||
#[cfg(any(test, feature = "test-support"))]
|
||||
pub struct FakeAdapter {}
|
||||
@ -302,6 +301,31 @@ impl FakeAdapter {
|
||||
pub fn new() -> Self {
|
||||
Self {}
|
||||
}
|
||||
|
||||
fn request_args(&self, config: &DebugTaskDefinition) -> StartDebuggingRequestArguments {
|
||||
use serde_json::json;
|
||||
use task::DebugRequestType;
|
||||
|
||||
let value = json!({
|
||||
"request": match config.request {
|
||||
DebugRequestType::Launch(_) => "launch",
|
||||
DebugRequestType::Attach(_) => "attach",
|
||||
},
|
||||
"process_id": if let DebugRequestType::Attach(attach_config) = &config.request {
|
||||
attach_config.process_id
|
||||
} else {
|
||||
None
|
||||
},
|
||||
});
|
||||
let request = match config.request {
|
||||
DebugRequestType::Launch(_) => dap_types::StartDebuggingRequestArgumentsRequest::Launch,
|
||||
DebugRequestType::Attach(_) => dap_types::StartDebuggingRequestArgumentsRequest::Attach,
|
||||
};
|
||||
StartDebuggingRequestArguments {
|
||||
configuration: value,
|
||||
request,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(any(test, feature = "test-support"))]
|
||||
@ -314,16 +338,18 @@ impl DebugAdapter for FakeAdapter {
|
||||
async fn get_binary(
|
||||
&self,
|
||||
_: &dyn DapDelegate,
|
||||
_: &DebugAdapterConfig,
|
||||
config: &DebugTaskDefinition,
|
||||
_: Option<PathBuf>,
|
||||
_: &mut AsyncApp,
|
||||
) -> Result<DebugAdapterBinary> {
|
||||
Ok(DebugAdapterBinary {
|
||||
adapter_name: Self::ADAPTER_NAME.into(),
|
||||
command: "command".into(),
|
||||
arguments: None,
|
||||
connection: None,
|
||||
envs: None,
|
||||
cwd: None,
|
||||
request_args: self.request_args(config),
|
||||
})
|
||||
}
|
||||
|
||||
@ -345,27 +371,10 @@ impl DebugAdapter for FakeAdapter {
|
||||
async fn get_installed_binary(
|
||||
&self,
|
||||
_: &dyn DapDelegate,
|
||||
_: &DebugAdapterConfig,
|
||||
_: &DebugTaskDefinition,
|
||||
_: Option<PathBuf>,
|
||||
_: &mut AsyncApp,
|
||||
) -> Result<DebugAdapterBinary> {
|
||||
unimplemented!("get installed binary");
|
||||
}
|
||||
|
||||
fn request_args(&self, config: &DebugTaskDefinition) -> Value {
|
||||
use serde_json::json;
|
||||
use task::DebugRequestType;
|
||||
|
||||
json!({
|
||||
"request": match config.request {
|
||||
DebugRequestType::Launch(_) => "launch",
|
||||
DebugRequestType::Attach(_) => "attach",
|
||||
},
|
||||
"process_id": if let DebugRequestType::Attach(attach_config) = &config.request {
|
||||
attach_config.process_id
|
||||
} else {
|
||||
None
|
||||
},
|
||||
})
|
||||
}
|
||||
}
|
||||
|
@ -39,7 +39,6 @@ impl SessionId {
|
||||
/// Represents a connection to the debug adapter process, either via stdout/stdin or a socket.
|
||||
pub struct DebugAdapterClient {
|
||||
id: SessionId,
|
||||
name: DebugAdapterName,
|
||||
sequence_count: AtomicU64,
|
||||
binary: DebugAdapterBinary,
|
||||
executor: BackgroundExecutor,
|
||||
@ -51,7 +50,6 @@ pub type DapMessageHandler = Box<dyn FnMut(Message) + 'static + Send + Sync>;
|
||||
impl DebugAdapterClient {
|
||||
pub async fn start(
|
||||
id: SessionId,
|
||||
name: DebugAdapterName,
|
||||
binary: DebugAdapterBinary,
|
||||
message_handler: DapMessageHandler,
|
||||
cx: AsyncApp,
|
||||
@ -60,7 +58,6 @@ impl DebugAdapterClient {
|
||||
TransportDelegate::start(&binary, cx.clone()).await?;
|
||||
let this = Self {
|
||||
id,
|
||||
name,
|
||||
binary,
|
||||
transport_delegate,
|
||||
sequence_count: AtomicU64::new(1),
|
||||
@ -91,6 +88,7 @@ impl DebugAdapterClient {
|
||||
) -> Result<Self> {
|
||||
let binary = match self.transport_delegate.transport() {
|
||||
crate::transport::Transport::Tcp(tcp_transport) => DebugAdapterBinary {
|
||||
adapter_name: binary.adapter_name,
|
||||
command: binary.command,
|
||||
arguments: binary.arguments,
|
||||
envs: binary.envs,
|
||||
@ -100,11 +98,12 @@ impl DebugAdapterClient {
|
||||
port: tcp_transport.port,
|
||||
timeout: Some(tcp_transport.timeout),
|
||||
}),
|
||||
request_args: binary.request_args,
|
||||
},
|
||||
_ => self.binary.clone(),
|
||||
};
|
||||
|
||||
Self::start(session_id, self.name(), binary, message_handler, cx).await
|
||||
Self::start(session_id, binary, message_handler, cx).await
|
||||
}
|
||||
|
||||
async fn handle_receive_messages(
|
||||
@ -189,7 +188,17 @@ impl DebugAdapterClient {
|
||||
|
||||
let response = response??;
|
||||
match response.success {
|
||||
true => Ok(serde_json::from_value(response.body.unwrap_or_default())?),
|
||||
true => {
|
||||
if let Some(json) = response.body {
|
||||
Ok(serde_json::from_value(json)?)
|
||||
// Note: dap types configure themselves to return `None` when an empty object is received,
|
||||
// which then fails here...
|
||||
} else if let Ok(result) = serde_json::from_value(serde_json::Value::Object(Default::default())) {
|
||||
Ok(result)
|
||||
} else {
|
||||
Ok(serde_json::from_value(Default::default())?)
|
||||
}
|
||||
}
|
||||
false => Err(anyhow!("Request failed: {}", response.message.unwrap_or_default())),
|
||||
}
|
||||
}
|
||||
@ -211,7 +220,7 @@ impl DebugAdapterClient {
|
||||
}
|
||||
|
||||
pub fn name(&self) -> DebugAdapterName {
|
||||
self.name.clone()
|
||||
self.binary.adapter_name.clone()
|
||||
}
|
||||
pub fn binary(&self) -> &DebugAdapterBinary {
|
||||
&self.binary
|
||||
@ -238,14 +247,14 @@ impl DebugAdapterClient {
|
||||
}
|
||||
|
||||
#[cfg(any(test, feature = "test-support"))]
|
||||
pub async fn on_request<R: dap_types::requests::Request, F>(&self, handler: F)
|
||||
pub fn on_request<R: dap_types::requests::Request, F>(&self, handler: F)
|
||||
where
|
||||
F: 'static
|
||||
+ Send
|
||||
+ FnMut(u64, R::Arguments) -> Result<R::Response, dap_types::ErrorResponse>,
|
||||
{
|
||||
let transport = self.transport_delegate.transport().as_fake();
|
||||
transport.on_request::<R, F>(handler).await;
|
||||
transport.on_request::<R, F>(handler);
|
||||
}
|
||||
|
||||
#[cfg(any(test, feature = "test-support"))]
|
||||
@ -282,7 +291,7 @@ mod tests {
|
||||
use crate::{client::DebugAdapterClient, debugger_settings::DebuggerSettings};
|
||||
use dap_types::{
|
||||
Capabilities, InitializeRequestArguments, InitializeRequestArgumentsPathFormat,
|
||||
RunInTerminalRequestArguments,
|
||||
RunInTerminalRequestArguments, StartDebuggingRequestArguments,
|
||||
messages::Events,
|
||||
requests::{Initialize, Request, RunInTerminal},
|
||||
};
|
||||
@ -312,13 +321,17 @@ mod tests {
|
||||
|
||||
let client = DebugAdapterClient::start(
|
||||
crate::client::SessionId(1),
|
||||
DebugAdapterName("adapter".into()),
|
||||
DebugAdapterBinary {
|
||||
adapter_name: "adapter".into(),
|
||||
command: "command".into(),
|
||||
arguments: Default::default(),
|
||||
envs: Default::default(),
|
||||
connection: None,
|
||||
cwd: None,
|
||||
request_args: StartDebuggingRequestArguments {
|
||||
configuration: serde_json::Value::Null,
|
||||
request: dap_types::StartDebuggingRequestArgumentsRequest::Launch,
|
||||
},
|
||||
},
|
||||
Box::new(|_| panic!("Did not expect to hit this code path")),
|
||||
cx.to_async(),
|
||||
@ -326,14 +339,12 @@ mod tests {
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
client
|
||||
.on_request::<Initialize, _>(move |_, _| {
|
||||
client.on_request::<Initialize, _>(move |_, _| {
|
||||
Ok(dap_types::Capabilities {
|
||||
supports_configuration_done_request: Some(true),
|
||||
..Default::default()
|
||||
})
|
||||
})
|
||||
.await;
|
||||
});
|
||||
|
||||
cx.run_until_parked();
|
||||
|
||||
@ -381,13 +392,17 @@ mod tests {
|
||||
|
||||
let client = DebugAdapterClient::start(
|
||||
crate::client::SessionId(1),
|
||||
DebugAdapterName("adapter".into()),
|
||||
DebugAdapterBinary {
|
||||
adapter_name: "adapter".into(),
|
||||
command: "command".into(),
|
||||
arguments: Default::default(),
|
||||
envs: Default::default(),
|
||||
connection: None,
|
||||
cwd: None,
|
||||
request_args: StartDebuggingRequestArguments {
|
||||
configuration: serde_json::Value::Null,
|
||||
request: dap_types::StartDebuggingRequestArgumentsRequest::Launch,
|
||||
},
|
||||
},
|
||||
Box::new({
|
||||
let called_event_handler = called_event_handler.clone();
|
||||
@ -431,13 +446,17 @@ mod tests {
|
||||
|
||||
let client = DebugAdapterClient::start(
|
||||
crate::client::SessionId(1),
|
||||
DebugAdapterName("test-adapter".into()),
|
||||
DebugAdapterBinary {
|
||||
adapter_name: "test-adapter".into(),
|
||||
command: "command".into(),
|
||||
arguments: Default::default(),
|
||||
envs: Default::default(),
|
||||
connection: None,
|
||||
cwd: None,
|
||||
request_args: dap_types::StartDebuggingRequestArguments {
|
||||
configuration: serde_json::Value::Null,
|
||||
request: dap_types::StartDebuggingRequestArgumentsRequest::Launch,
|
||||
},
|
||||
},
|
||||
Box::new({
|
||||
let called_event_handler = called_event_handler.clone();
|
||||
|
@ -699,14 +699,8 @@ impl StdioTransport {
|
||||
}
|
||||
|
||||
#[cfg(any(test, feature = "test-support"))]
|
||||
type RequestHandler = Box<
|
||||
dyn Send
|
||||
+ FnMut(
|
||||
u64,
|
||||
serde_json::Value,
|
||||
Arc<Mutex<async_pipe::PipeWriter>>,
|
||||
) -> std::pin::Pin<Box<dyn std::future::Future<Output = ()> + Send>>,
|
||||
>;
|
||||
type RequestHandler =
|
||||
Box<dyn Send + FnMut(u64, serde_json::Value) -> dap_types::messages::Response>;
|
||||
|
||||
#[cfg(any(test, feature = "test-support"))]
|
||||
type ResponseHandler = Box<dyn Send + Fn(Response)>;
|
||||
@ -714,45 +708,41 @@ type ResponseHandler = Box<dyn Send + Fn(Response)>;
|
||||
#[cfg(any(test, feature = "test-support"))]
|
||||
pub struct FakeTransport {
|
||||
// for sending fake response back from adapter side
|
||||
request_handlers: Arc<Mutex<HashMap<&'static str, RequestHandler>>>,
|
||||
request_handlers: Arc<parking_lot::Mutex<HashMap<&'static str, RequestHandler>>>,
|
||||
// for reverse request responses
|
||||
response_handlers: Arc<Mutex<HashMap<&'static str, ResponseHandler>>>,
|
||||
response_handlers: Arc<parking_lot::Mutex<HashMap<&'static str, ResponseHandler>>>,
|
||||
}
|
||||
|
||||
#[cfg(any(test, feature = "test-support"))]
|
||||
impl FakeTransport {
|
||||
pub async fn on_request<R: dap_types::requests::Request, F>(&self, mut handler: F)
|
||||
pub fn on_request<R: dap_types::requests::Request, F>(&self, mut handler: F)
|
||||
where
|
||||
F: 'static + Send + FnMut(u64, R::Arguments) -> Result<R::Response, ErrorResponse>,
|
||||
{
|
||||
self.request_handlers.lock().await.insert(
|
||||
self.request_handlers.lock().insert(
|
||||
R::COMMAND,
|
||||
Box::new(
|
||||
move |seq, args, writer: Arc<Mutex<async_pipe::PipeWriter>>| {
|
||||
let response = handler(seq, serde_json::from_value(args).unwrap());
|
||||
|
||||
let message = serde_json::to_string(&Message::Response(Response {
|
||||
Box::new(move |seq, args| {
|
||||
let result = handler(seq, serde_json::from_value(args).unwrap());
|
||||
let response = match result {
|
||||
Ok(response) => Response {
|
||||
seq: seq + 1,
|
||||
request_seq: seq,
|
||||
success: response.as_ref().is_ok(),
|
||||
success: true,
|
||||
command: R::COMMAND.into(),
|
||||
body: util::maybe!({ serde_json::to_value(response.ok()?).ok() }),
|
||||
body: Some(serde_json::to_value(response).unwrap()),
|
||||
message: None,
|
||||
}))
|
||||
.unwrap();
|
||||
|
||||
let writer = writer.clone();
|
||||
|
||||
Box::pin(async move {
|
||||
let mut writer = writer.lock().await;
|
||||
writer
|
||||
.write_all(TransportDelegate::build_rpc_message(message).as_bytes())
|
||||
.await
|
||||
.unwrap();
|
||||
writer.flush().await.unwrap();
|
||||
})
|
||||
},
|
||||
),
|
||||
Err(response) => Response {
|
||||
seq: seq + 1,
|
||||
request_seq: seq,
|
||||
success: false,
|
||||
command: R::COMMAND.into(),
|
||||
body: Some(serde_json::to_value(response).unwrap()),
|
||||
message: None,
|
||||
},
|
||||
};
|
||||
response
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
@ -762,14 +752,13 @@ impl FakeTransport {
|
||||
{
|
||||
self.response_handlers
|
||||
.lock()
|
||||
.await
|
||||
.insert(R::COMMAND, Box::new(handler));
|
||||
}
|
||||
|
||||
async fn start(cx: AsyncApp) -> Result<(TransportPipe, Self)> {
|
||||
let this = Self {
|
||||
request_handlers: Arc::new(Mutex::new(HashMap::default())),
|
||||
response_handlers: Arc::new(Mutex::new(HashMap::default())),
|
||||
request_handlers: Arc::new(parking_lot::Mutex::new(HashMap::default())),
|
||||
response_handlers: Arc::new(parking_lot::Mutex::new(HashMap::default())),
|
||||
};
|
||||
use dap_types::requests::{Request, RunInTerminal, StartDebugging};
|
||||
use serde_json::json;
|
||||
@ -816,23 +805,31 @@ impl FakeTransport {
|
||||
.unwrap();
|
||||
writer.flush().await.unwrap();
|
||||
} else {
|
||||
if let Some(handle) = request_handlers
|
||||
let response = if let Some(handle) = request_handlers
|
||||
.lock()
|
||||
.await
|
||||
.get_mut(request.command.as_str())
|
||||
{
|
||||
handle(
|
||||
request.seq,
|
||||
request.arguments.unwrap_or(json!({})),
|
||||
stdout_writer.clone(),
|
||||
)
|
||||
.await;
|
||||
} else {
|
||||
log::error!(
|
||||
"No request handler for {}",
|
||||
request.command
|
||||
);
|
||||
}
|
||||
panic!("No request handler for {}", request.command);
|
||||
};
|
||||
let message =
|
||||
serde_json::to_string(&Message::Response(response))
|
||||
.unwrap();
|
||||
|
||||
let mut writer = stdout_writer.lock().await;
|
||||
|
||||
writer
|
||||
.write_all(
|
||||
TransportDelegate::build_rpc_message(message)
|
||||
.as_bytes(),
|
||||
)
|
||||
.await
|
||||
.unwrap();
|
||||
writer.flush().await.unwrap();
|
||||
}
|
||||
}
|
||||
Message::Event(event) => {
|
||||
@ -850,10 +847,8 @@ impl FakeTransport {
|
||||
writer.flush().await.unwrap();
|
||||
}
|
||||
Message::Response(response) => {
|
||||
if let Some(handle) = response_handlers
|
||||
.lock()
|
||||
.await
|
||||
.get(response.command.as_str())
|
||||
if let Some(handle) =
|
||||
response_handlers.lock().get(response.command.as_str())
|
||||
{
|
||||
handle(response);
|
||||
} else {
|
||||
|
@ -4,7 +4,7 @@ use anyhow::{Result, bail};
|
||||
use async_trait::async_trait;
|
||||
use dap::adapters::latest_github_release;
|
||||
use gpui::AsyncApp;
|
||||
use task::{DebugAdapterConfig, DebugRequestType, DebugTaskDefinition};
|
||||
use task::{DebugRequestType, DebugTaskDefinition};
|
||||
|
||||
use crate::*;
|
||||
|
||||
@ -15,6 +15,42 @@ pub(crate) struct CodeLldbDebugAdapter {
|
||||
|
||||
impl CodeLldbDebugAdapter {
|
||||
const ADAPTER_NAME: &'static str = "CodeLLDB";
|
||||
|
||||
fn request_args(&self, config: &DebugTaskDefinition) -> dap::StartDebuggingRequestArguments {
|
||||
let mut configuration = json!({
|
||||
"request": match config.request {
|
||||
DebugRequestType::Launch(_) => "launch",
|
||||
DebugRequestType::Attach(_) => "attach",
|
||||
},
|
||||
});
|
||||
let map = configuration.as_object_mut().unwrap();
|
||||
// CodeLLDB uses `name` for a terminal label.
|
||||
map.insert("name".into(), Value::String(config.label.clone()));
|
||||
let request = config.request.to_dap();
|
||||
match &config.request {
|
||||
DebugRequestType::Attach(attach) => {
|
||||
map.insert("pid".into(), attach.process_id.into());
|
||||
}
|
||||
DebugRequestType::Launch(launch) => {
|
||||
map.insert("program".into(), launch.program.clone().into());
|
||||
|
||||
if !launch.args.is_empty() {
|
||||
map.insert("args".into(), launch.args.clone().into());
|
||||
}
|
||||
|
||||
if let Some(stop_on_entry) = config.stop_on_entry {
|
||||
map.insert("stopOnEntry".into(), stop_on_entry.into());
|
||||
}
|
||||
if let Some(cwd) = launch.cwd.as_ref() {
|
||||
map.insert("cwd".into(), cwd.to_string_lossy().into_owned().into());
|
||||
}
|
||||
}
|
||||
}
|
||||
dap::StartDebuggingRequestArguments {
|
||||
request,
|
||||
configuration,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[async_trait(?Send)]
|
||||
@ -86,7 +122,7 @@ impl DebugAdapter for CodeLldbDebugAdapter {
|
||||
async fn get_installed_binary(
|
||||
&self,
|
||||
_: &dyn DapDelegate,
|
||||
_: &DebugAdapterConfig,
|
||||
config: &DebugTaskDefinition,
|
||||
_: Option<PathBuf>,
|
||||
_: &mut AsyncApp,
|
||||
) -> Result<DebugAdapterBinary> {
|
||||
@ -111,39 +147,10 @@ impl DebugAdapter for CodeLldbDebugAdapter {
|
||||
.to_string()
|
||||
.into(),
|
||||
]),
|
||||
..Default::default()
|
||||
request_args: self.request_args(config),
|
||||
adapter_name: "test".into(),
|
||||
envs: None,
|
||||
connection: None,
|
||||
})
|
||||
}
|
||||
|
||||
fn request_args(&self, config: &DebugTaskDefinition) -> Value {
|
||||
let mut args = json!({
|
||||
"request": match config.request {
|
||||
DebugRequestType::Launch(_) => "launch",
|
||||
DebugRequestType::Attach(_) => "attach",
|
||||
},
|
||||
});
|
||||
let map = args.as_object_mut().unwrap();
|
||||
// CodeLLDB uses `name` for a terminal label.
|
||||
map.insert("name".into(), Value::String(config.label.clone()));
|
||||
match &config.request {
|
||||
DebugRequestType::Attach(attach) => {
|
||||
map.insert("pid".into(), attach.process_id.into());
|
||||
}
|
||||
DebugRequestType::Launch(launch) => {
|
||||
map.insert("program".into(), launch.program.clone().into());
|
||||
|
||||
if !launch.args.is_empty() {
|
||||
map.insert("args".into(), launch.args.clone().into());
|
||||
}
|
||||
|
||||
if let Some(stop_on_entry) = config.stop_on_entry {
|
||||
map.insert("stopOnEntry".into(), stop_on_entry.into());
|
||||
}
|
||||
if let Some(cwd) = launch.cwd.as_ref() {
|
||||
map.insert("cwd".into(), cwd.to_string_lossy().into_owned().into());
|
||||
}
|
||||
}
|
||||
}
|
||||
args
|
||||
}
|
||||
}
|
||||
|
@ -12,7 +12,7 @@ use anyhow::{Result, anyhow};
|
||||
use async_trait::async_trait;
|
||||
use codelldb::CodeLldbDebugAdapter;
|
||||
use dap::{
|
||||
DapRegistry,
|
||||
DapRegistry, DebugRequestType,
|
||||
adapters::{
|
||||
self, AdapterVersion, DapDelegate, DebugAdapter, DebugAdapterBinary, DebugAdapterName,
|
||||
GithubRepo,
|
||||
@ -25,7 +25,7 @@ use lldb::LldbDebugAdapter;
|
||||
use php::PhpDebugAdapter;
|
||||
use python::PythonDebugAdapter;
|
||||
use serde_json::{Value, json};
|
||||
use task::{DebugAdapterConfig, TCPHost};
|
||||
use task::TCPHost;
|
||||
|
||||
pub fn init(registry: Arc<DapRegistry>) {
|
||||
registry.add_adapter(Arc::from(CodeLldbDebugAdapter::default()));
|
||||
@ -51,3 +51,16 @@ pub(crate) async fn configure_tcp_connection(
|
||||
|
||||
Ok((host, port, timeout))
|
||||
}
|
||||
|
||||
trait ToDap {
|
||||
fn to_dap(&self) -> dap::StartDebuggingRequestArgumentsRequest;
|
||||
}
|
||||
|
||||
impl ToDap for DebugRequestType {
|
||||
fn to_dap(&self) -> dap::StartDebuggingRequestArgumentsRequest {
|
||||
match self {
|
||||
Self::Launch(_) => dap::StartDebuggingRequestArgumentsRequest::Launch,
|
||||
Self::Attach(_) => dap::StartDebuggingRequestArgumentsRequest::Attach,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -2,8 +2,9 @@ use std::ffi::OsStr;
|
||||
|
||||
use anyhow::{Result, bail};
|
||||
use async_trait::async_trait;
|
||||
use dap::StartDebuggingRequestArguments;
|
||||
use gpui::AsyncApp;
|
||||
use task::{DebugAdapterConfig, DebugRequestType, DebugTaskDefinition};
|
||||
use task::{DebugRequestType, DebugTaskDefinition};
|
||||
|
||||
use crate::*;
|
||||
|
||||
@ -12,68 +13,8 @@ pub(crate) struct GdbDebugAdapter;
|
||||
|
||||
impl GdbDebugAdapter {
|
||||
const ADAPTER_NAME: &'static str = "GDB";
|
||||
}
|
||||
|
||||
#[async_trait(?Send)]
|
||||
impl DebugAdapter for GdbDebugAdapter {
|
||||
fn name(&self) -> DebugAdapterName {
|
||||
DebugAdapterName(Self::ADAPTER_NAME.into())
|
||||
}
|
||||
|
||||
async fn get_binary(
|
||||
&self,
|
||||
delegate: &dyn DapDelegate,
|
||||
_: &DebugAdapterConfig,
|
||||
user_installed_path: Option<std::path::PathBuf>,
|
||||
_: &mut AsyncApp,
|
||||
) -> Result<DebugAdapterBinary> {
|
||||
let user_setting_path = user_installed_path
|
||||
.filter(|p| p.exists())
|
||||
.and_then(|p| p.to_str().map(|s| s.to_string()));
|
||||
|
||||
let gdb_path = delegate
|
||||
.which(OsStr::new("gdb"))
|
||||
.and_then(|p| p.to_str().map(|s| s.to_string()))
|
||||
.ok_or(anyhow!("Could not find gdb in path"));
|
||||
|
||||
if gdb_path.is_err() && user_setting_path.is_none() {
|
||||
bail!("Could not find gdb path or it's not installed");
|
||||
}
|
||||
|
||||
let gdb_path = user_setting_path.unwrap_or(gdb_path?);
|
||||
|
||||
Ok(DebugAdapterBinary {
|
||||
command: gdb_path,
|
||||
arguments: Some(vec!["-i=dap".into()]),
|
||||
envs: None,
|
||||
cwd: None,
|
||||
connection: None,
|
||||
})
|
||||
}
|
||||
|
||||
async fn install_binary(
|
||||
&self,
|
||||
_version: AdapterVersion,
|
||||
_delegate: &dyn DapDelegate,
|
||||
) -> Result<()> {
|
||||
unimplemented!("GDB debug adapter cannot be installed by Zed (yet)")
|
||||
}
|
||||
|
||||
async fn fetch_latest_adapter_version(&self, _: &dyn DapDelegate) -> Result<AdapterVersion> {
|
||||
unimplemented!("Fetch latest GDB version not implemented (yet)")
|
||||
}
|
||||
|
||||
async fn get_installed_binary(
|
||||
&self,
|
||||
_: &dyn DapDelegate,
|
||||
_: &DebugAdapterConfig,
|
||||
_: Option<std::path::PathBuf>,
|
||||
_: &mut AsyncApp,
|
||||
) -> Result<DebugAdapterBinary> {
|
||||
unimplemented!("GDB cannot be installed by Zed (yet)")
|
||||
}
|
||||
|
||||
fn request_args(&self, config: &DebugTaskDefinition) -> Value {
|
||||
fn request_args(&self, config: &DebugTaskDefinition) -> StartDebuggingRequestArguments {
|
||||
let mut args = json!({
|
||||
"request": match config.request {
|
||||
DebugRequestType::Launch(_) => "launch",
|
||||
@ -105,6 +46,71 @@ impl DebugAdapter for GdbDebugAdapter {
|
||||
}
|
||||
}
|
||||
}
|
||||
args
|
||||
StartDebuggingRequestArguments {
|
||||
configuration: args,
|
||||
request: config.request.to_dap(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[async_trait(?Send)]
|
||||
impl DebugAdapter for GdbDebugAdapter {
|
||||
fn name(&self) -> DebugAdapterName {
|
||||
DebugAdapterName(Self::ADAPTER_NAME.into())
|
||||
}
|
||||
|
||||
async fn get_binary(
|
||||
&self,
|
||||
delegate: &dyn DapDelegate,
|
||||
config: &DebugTaskDefinition,
|
||||
user_installed_path: Option<std::path::PathBuf>,
|
||||
_: &mut AsyncApp,
|
||||
) -> Result<DebugAdapterBinary> {
|
||||
let user_setting_path = user_installed_path
|
||||
.filter(|p| p.exists())
|
||||
.and_then(|p| p.to_str().map(|s| s.to_string()));
|
||||
|
||||
let gdb_path = delegate
|
||||
.which(OsStr::new("gdb"))
|
||||
.and_then(|p| p.to_str().map(|s| s.to_string()))
|
||||
.ok_or(anyhow!("Could not find gdb in path"));
|
||||
|
||||
if gdb_path.is_err() && user_setting_path.is_none() {
|
||||
bail!("Could not find gdb path or it's not installed");
|
||||
}
|
||||
|
||||
let gdb_path = user_setting_path.unwrap_or(gdb_path?);
|
||||
|
||||
Ok(DebugAdapterBinary {
|
||||
adapter_name: Self::ADAPTER_NAME.into(),
|
||||
command: gdb_path,
|
||||
arguments: Some(vec!["-i=dap".into()]),
|
||||
envs: None,
|
||||
cwd: None,
|
||||
connection: None,
|
||||
request_args: self.request_args(config),
|
||||
})
|
||||
}
|
||||
|
||||
async fn install_binary(
|
||||
&self,
|
||||
_version: AdapterVersion,
|
||||
_delegate: &dyn DapDelegate,
|
||||
) -> Result<()> {
|
||||
unimplemented!("GDB debug adapter cannot be installed by Zed (yet)")
|
||||
}
|
||||
|
||||
async fn fetch_latest_adapter_version(&self, _: &dyn DapDelegate) -> Result<AdapterVersion> {
|
||||
unimplemented!("Fetch latest GDB version not implemented (yet)")
|
||||
}
|
||||
|
||||
async fn get_installed_binary(
|
||||
&self,
|
||||
_: &dyn DapDelegate,
|
||||
_: &DebugTaskDefinition,
|
||||
_: Option<std::path::PathBuf>,
|
||||
_: &mut AsyncApp,
|
||||
) -> Result<DebugAdapterBinary> {
|
||||
unimplemented!("GDB cannot be installed by Zed (yet)")
|
||||
}
|
||||
}
|
||||
|
@ -1,3 +1,4 @@
|
||||
use dap::StartDebuggingRequestArguments;
|
||||
use gpui::AsyncApp;
|
||||
use std::{ffi::OsStr, path::PathBuf};
|
||||
use task::DebugTaskDefinition;
|
||||
@ -9,6 +10,31 @@ pub(crate) struct GoDebugAdapter;
|
||||
|
||||
impl GoDebugAdapter {
|
||||
const ADAPTER_NAME: &'static str = "Delve";
|
||||
fn request_args(&self, config: &DebugTaskDefinition) -> StartDebuggingRequestArguments {
|
||||
let mut args = match &config.request {
|
||||
dap::DebugRequestType::Attach(attach_config) => {
|
||||
json!({
|
||||
"processId": attach_config.process_id,
|
||||
})
|
||||
}
|
||||
dap::DebugRequestType::Launch(launch_config) => json!({
|
||||
"program": launch_config.program,
|
||||
"cwd": launch_config.cwd,
|
||||
"args": launch_config.args
|
||||
}),
|
||||
};
|
||||
|
||||
let map = args.as_object_mut().unwrap();
|
||||
|
||||
if let Some(stop_on_entry) = config.stop_on_entry {
|
||||
map.insert("stopOnEntry".into(), stop_on_entry.into());
|
||||
}
|
||||
|
||||
StartDebuggingRequestArguments {
|
||||
configuration: args,
|
||||
request: config.request.to_dap(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[async_trait(?Send)]
|
||||
@ -20,7 +46,7 @@ impl DebugAdapter for GoDebugAdapter {
|
||||
async fn get_binary(
|
||||
&self,
|
||||
delegate: &dyn DapDelegate,
|
||||
config: &DebugAdapterConfig,
|
||||
config: &DebugTaskDefinition,
|
||||
user_installed_path: Option<PathBuf>,
|
||||
cx: &mut AsyncApp,
|
||||
) -> Result<DebugAdapterBinary> {
|
||||
@ -53,7 +79,7 @@ impl DebugAdapter for GoDebugAdapter {
|
||||
async fn get_installed_binary(
|
||||
&self,
|
||||
delegate: &dyn DapDelegate,
|
||||
config: &DebugAdapterConfig,
|
||||
config: &DebugTaskDefinition,
|
||||
_: Option<PathBuf>,
|
||||
_: &mut AsyncApp,
|
||||
) -> Result<DebugAdapterBinary> {
|
||||
@ -66,6 +92,7 @@ impl DebugAdapter for GoDebugAdapter {
|
||||
let (host, port, timeout) = crate::configure_tcp_connection(tcp_connection).await?;
|
||||
|
||||
Ok(DebugAdapterBinary {
|
||||
adapter_name: self.name(),
|
||||
command: delve_path,
|
||||
arguments: Some(vec![
|
||||
"dap".into(),
|
||||
@ -79,29 +106,7 @@ impl DebugAdapter for GoDebugAdapter {
|
||||
port,
|
||||
timeout,
|
||||
}),
|
||||
request_args: self.request_args(config),
|
||||
})
|
||||
}
|
||||
|
||||
fn request_args(&self, config: &DebugTaskDefinition) -> Value {
|
||||
let mut args = match &config.request {
|
||||
dap::DebugRequestType::Attach(attach_config) => {
|
||||
json!({
|
||||
"processId": attach_config.process_id,
|
||||
})
|
||||
}
|
||||
dap::DebugRequestType::Launch(launch_config) => json!({
|
||||
"program": launch_config.program,
|
||||
"cwd": launch_config.cwd,
|
||||
"args": launch_config.args
|
||||
}),
|
||||
};
|
||||
|
||||
let map = args.as_object_mut().unwrap();
|
||||
|
||||
if let Some(stop_on_entry) = config.stop_on_entry {
|
||||
map.insert("stopOnEntry".into(), stop_on_entry.into());
|
||||
}
|
||||
|
||||
args
|
||||
}
|
||||
}
|
||||
|
@ -1,4 +1,5 @@
|
||||
use adapters::latest_github_release;
|
||||
use dap::StartDebuggingRequestArguments;
|
||||
use gpui::AsyncApp;
|
||||
use std::path::PathBuf;
|
||||
use task::{DebugRequestType, DebugTaskDefinition};
|
||||
@ -12,6 +13,40 @@ impl JsDebugAdapter {
|
||||
const ADAPTER_NAME: &'static str = "JavaScript";
|
||||
const ADAPTER_NPM_NAME: &'static str = "vscode-js-debug";
|
||||
const ADAPTER_PATH: &'static str = "js-debug/src/dapDebugServer.js";
|
||||
|
||||
fn request_args(&self, config: &DebugTaskDefinition) -> StartDebuggingRequestArguments {
|
||||
let mut args = json!({
|
||||
"type": "pwa-node",
|
||||
"request": match config.request {
|
||||
DebugRequestType::Launch(_) => "launch",
|
||||
DebugRequestType::Attach(_) => "attach",
|
||||
},
|
||||
});
|
||||
let map = args.as_object_mut().unwrap();
|
||||
match &config.request {
|
||||
DebugRequestType::Attach(attach) => {
|
||||
map.insert("processId".into(), attach.process_id.into());
|
||||
}
|
||||
DebugRequestType::Launch(launch) => {
|
||||
map.insert("program".into(), launch.program.clone().into());
|
||||
|
||||
if !launch.args.is_empty() {
|
||||
map.insert("args".into(), launch.args.clone().into());
|
||||
}
|
||||
|
||||
if let Some(stop_on_entry) = config.stop_on_entry {
|
||||
map.insert("stopOnEntry".into(), stop_on_entry.into());
|
||||
}
|
||||
if let Some(cwd) = launch.cwd.as_ref() {
|
||||
map.insert("cwd".into(), cwd.to_string_lossy().into_owned().into());
|
||||
}
|
||||
}
|
||||
}
|
||||
StartDebuggingRequestArguments {
|
||||
configuration: args,
|
||||
request: config.request.to_dap(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[async_trait(?Send)]
|
||||
@ -49,7 +84,7 @@ impl DebugAdapter for JsDebugAdapter {
|
||||
async fn get_installed_binary(
|
||||
&self,
|
||||
delegate: &dyn DapDelegate,
|
||||
config: &DebugAdapterConfig,
|
||||
config: &DebugTaskDefinition,
|
||||
user_installed_path: Option<PathBuf>,
|
||||
_: &mut AsyncApp,
|
||||
) -> Result<DebugAdapterBinary> {
|
||||
@ -71,6 +106,7 @@ impl DebugAdapter for JsDebugAdapter {
|
||||
let (host, port, timeout) = crate::configure_tcp_connection(tcp_connection).await?;
|
||||
|
||||
Ok(DebugAdapterBinary {
|
||||
adapter_name: self.name(),
|
||||
command: delegate
|
||||
.node_runtime()
|
||||
.binary_path()
|
||||
@ -89,6 +125,7 @@ impl DebugAdapter for JsDebugAdapter {
|
||||
port,
|
||||
timeout,
|
||||
}),
|
||||
request_args: self.request_args(config),
|
||||
})
|
||||
}
|
||||
|
||||
@ -107,35 +144,4 @@ impl DebugAdapter for JsDebugAdapter {
|
||||
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
fn request_args(&self, config: &DebugTaskDefinition) -> Value {
|
||||
let mut args = json!({
|
||||
"type": "pwa-node",
|
||||
"request": match config.request {
|
||||
DebugRequestType::Launch(_) => "launch",
|
||||
DebugRequestType::Attach(_) => "attach",
|
||||
},
|
||||
});
|
||||
let map = args.as_object_mut().unwrap();
|
||||
match &config.request {
|
||||
DebugRequestType::Attach(attach) => {
|
||||
map.insert("processId".into(), attach.process_id.into());
|
||||
}
|
||||
DebugRequestType::Launch(launch) => {
|
||||
map.insert("program".into(), launch.program.clone().into());
|
||||
|
||||
if !launch.args.is_empty() {
|
||||
map.insert("args".into(), launch.args.clone().into());
|
||||
}
|
||||
|
||||
if let Some(stop_on_entry) = config.stop_on_entry {
|
||||
map.insert("stopOnEntry".into(), stop_on_entry.into());
|
||||
}
|
||||
if let Some(cwd) = launch.cwd.as_ref() {
|
||||
map.insert("cwd".into(), cwd.to_string_lossy().into_owned().into());
|
||||
}
|
||||
}
|
||||
}
|
||||
args
|
||||
}
|
||||
}
|
||||
|
@ -3,7 +3,7 @@ use std::{ffi::OsStr, path::PathBuf};
|
||||
use anyhow::Result;
|
||||
use async_trait::async_trait;
|
||||
use gpui::AsyncApp;
|
||||
use task::{DebugAdapterConfig, DebugRequestType, DebugTaskDefinition};
|
||||
use task::{DebugRequestType, DebugTaskDefinition};
|
||||
|
||||
use crate::*;
|
||||
|
||||
@ -12,62 +12,9 @@ pub(crate) struct LldbDebugAdapter;
|
||||
|
||||
impl LldbDebugAdapter {
|
||||
const ADAPTER_NAME: &'static str = "LLDB";
|
||||
}
|
||||
|
||||
#[async_trait(?Send)]
|
||||
impl DebugAdapter for LldbDebugAdapter {
|
||||
fn name(&self) -> DebugAdapterName {
|
||||
DebugAdapterName(Self::ADAPTER_NAME.into())
|
||||
}
|
||||
|
||||
async fn get_binary(
|
||||
&self,
|
||||
delegate: &dyn DapDelegate,
|
||||
_: &DebugAdapterConfig,
|
||||
user_installed_path: Option<PathBuf>,
|
||||
_: &mut AsyncApp,
|
||||
) -> Result<DebugAdapterBinary> {
|
||||
let lldb_dap_path = if let Some(user_installed_path) = user_installed_path {
|
||||
user_installed_path.to_string_lossy().into()
|
||||
} else {
|
||||
delegate
|
||||
.which(OsStr::new("lldb-dap"))
|
||||
.and_then(|p| p.to_str().map(|s| s.to_string()))
|
||||
.ok_or(anyhow!("Could not find lldb-dap in path"))?
|
||||
};
|
||||
|
||||
Ok(DebugAdapterBinary {
|
||||
command: lldb_dap_path,
|
||||
arguments: None,
|
||||
envs: None,
|
||||
cwd: None,
|
||||
connection: None,
|
||||
})
|
||||
}
|
||||
|
||||
async fn install_binary(
|
||||
&self,
|
||||
_version: AdapterVersion,
|
||||
_delegate: &dyn DapDelegate,
|
||||
) -> Result<()> {
|
||||
unimplemented!("LLDB debug adapter cannot be installed by Zed (yet)")
|
||||
}
|
||||
|
||||
async fn fetch_latest_adapter_version(&self, _: &dyn DapDelegate) -> Result<AdapterVersion> {
|
||||
unimplemented!("Fetch latest adapter version not implemented for lldb (yet)")
|
||||
}
|
||||
|
||||
async fn get_installed_binary(
|
||||
&self,
|
||||
_: &dyn DapDelegate,
|
||||
_: &DebugAdapterConfig,
|
||||
_: Option<PathBuf>,
|
||||
_: &mut AsyncApp,
|
||||
) -> Result<DebugAdapterBinary> {
|
||||
unimplemented!("LLDB debug adapter cannot be installed by Zed (yet)")
|
||||
}
|
||||
|
||||
fn request_args(&self, config: &DebugTaskDefinition) -> Value {
|
||||
fn request_args(&self, config: &DebugTaskDefinition) -> dap::StartDebuggingRequestArguments {
|
||||
let request = config.request.to_dap();
|
||||
let mut args = json!({
|
||||
"request": match config.request {
|
||||
DebugRequestType::Launch(_) => "launch",
|
||||
@ -94,6 +41,65 @@ impl DebugAdapter for LldbDebugAdapter {
|
||||
}
|
||||
}
|
||||
}
|
||||
args
|
||||
dap::StartDebuggingRequestArguments {
|
||||
request,
|
||||
configuration: args,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[async_trait(?Send)]
|
||||
impl DebugAdapter for LldbDebugAdapter {
|
||||
fn name(&self) -> DebugAdapterName {
|
||||
DebugAdapterName(Self::ADAPTER_NAME.into())
|
||||
}
|
||||
|
||||
async fn get_binary(
|
||||
&self,
|
||||
delegate: &dyn DapDelegate,
|
||||
config: &DebugTaskDefinition,
|
||||
user_installed_path: Option<PathBuf>,
|
||||
_: &mut AsyncApp,
|
||||
) -> Result<DebugAdapterBinary> {
|
||||
let lldb_dap_path = if let Some(user_installed_path) = user_installed_path {
|
||||
user_installed_path.to_string_lossy().into()
|
||||
} else {
|
||||
delegate
|
||||
.which(OsStr::new("lldb-dap"))
|
||||
.and_then(|p| p.to_str().map(|s| s.to_string()))
|
||||
.ok_or(anyhow!("Could not find lldb-dap in path"))?
|
||||
};
|
||||
|
||||
Ok(DebugAdapterBinary {
|
||||
adapter_name: Self::ADAPTER_NAME.into(),
|
||||
command: lldb_dap_path,
|
||||
arguments: None,
|
||||
envs: None,
|
||||
cwd: None,
|
||||
connection: None,
|
||||
request_args: self.request_args(config),
|
||||
})
|
||||
}
|
||||
|
||||
async fn install_binary(
|
||||
&self,
|
||||
_version: AdapterVersion,
|
||||
_delegate: &dyn DapDelegate,
|
||||
) -> Result<()> {
|
||||
unimplemented!("LLDB debug adapter cannot be installed by Zed (yet)")
|
||||
}
|
||||
|
||||
async fn fetch_latest_adapter_version(&self, _: &dyn DapDelegate) -> Result<AdapterVersion> {
|
||||
unimplemented!("Fetch latest adapter version not implemented for lldb (yet)")
|
||||
}
|
||||
|
||||
async fn get_installed_binary(
|
||||
&self,
|
||||
_: &dyn DapDelegate,
|
||||
_: &DebugTaskDefinition,
|
||||
_: Option<PathBuf>,
|
||||
_: &mut AsyncApp,
|
||||
) -> Result<DebugAdapterBinary> {
|
||||
unimplemented!("LLDB debug adapter cannot be installed by Zed (yet)")
|
||||
}
|
||||
}
|
||||
|
@ -13,6 +13,28 @@ impl PhpDebugAdapter {
|
||||
const ADAPTER_NAME: &'static str = "PHP";
|
||||
const ADAPTER_PACKAGE_NAME: &'static str = "vscode-php-debug";
|
||||
const ADAPTER_PATH: &'static str = "extension/out/phpDebug.js";
|
||||
|
||||
fn request_args(
|
||||
&self,
|
||||
config: &DebugTaskDefinition,
|
||||
) -> Result<dap::StartDebuggingRequestArguments> {
|
||||
match &config.request {
|
||||
dap::DebugRequestType::Attach(_) => {
|
||||
anyhow::bail!("php adapter does not support attaching")
|
||||
}
|
||||
dap::DebugRequestType::Launch(launch_config) => {
|
||||
Ok(dap::StartDebuggingRequestArguments {
|
||||
configuration: json!({
|
||||
"program": launch_config.program,
|
||||
"cwd": launch_config.cwd,
|
||||
"args": launch_config.args,
|
||||
"stopOnEntry": config.stop_on_entry.unwrap_or_default(),
|
||||
}),
|
||||
request: config.request.to_dap(),
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[async_trait(?Send)]
|
||||
@ -50,7 +72,7 @@ impl DebugAdapter for PhpDebugAdapter {
|
||||
async fn get_installed_binary(
|
||||
&self,
|
||||
delegate: &dyn DapDelegate,
|
||||
config: &DebugAdapterConfig,
|
||||
config: &DebugTaskDefinition,
|
||||
user_installed_path: Option<PathBuf>,
|
||||
_: &mut AsyncApp,
|
||||
) -> Result<DebugAdapterBinary> {
|
||||
@ -72,6 +94,7 @@ impl DebugAdapter for PhpDebugAdapter {
|
||||
let (host, port, timeout) = crate::configure_tcp_connection(tcp_connection).await?;
|
||||
|
||||
Ok(DebugAdapterBinary {
|
||||
adapter_name: self.name(),
|
||||
command: delegate
|
||||
.node_runtime()
|
||||
.binary_path()
|
||||
@ -89,6 +112,7 @@ impl DebugAdapter for PhpDebugAdapter {
|
||||
}),
|
||||
cwd: None,
|
||||
envs: None,
|
||||
request_args: self.request_args(config)?,
|
||||
})
|
||||
}
|
||||
|
||||
@ -107,21 +131,4 @@ impl DebugAdapter for PhpDebugAdapter {
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn request_args(&self, config: &DebugTaskDefinition) -> Value {
|
||||
match &config.request {
|
||||
dap::DebugRequestType::Attach(_) => {
|
||||
// php adapter does not support attaching
|
||||
json!({})
|
||||
}
|
||||
dap::DebugRequestType::Launch(launch_config) => {
|
||||
json!({
|
||||
"program": launch_config.program,
|
||||
"cwd": launch_config.cwd,
|
||||
"args": launch_config.args,
|
||||
"stopOnEntry": config.stop_on_entry.unwrap_or_default(),
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
use crate::*;
|
||||
use dap::DebugRequestType;
|
||||
use dap::{DebugRequestType, StartDebuggingRequestArguments};
|
||||
use gpui::AsyncApp;
|
||||
use std::{ffi::OsStr, path::PathBuf};
|
||||
use task::DebugTaskDefinition;
|
||||
@ -12,6 +12,38 @@ impl PythonDebugAdapter {
|
||||
const ADAPTER_PACKAGE_NAME: &'static str = "debugpy";
|
||||
const ADAPTER_PATH: &'static str = "src/debugpy/adapter";
|
||||
const LANGUAGE_NAME: &'static str = "Python";
|
||||
|
||||
fn request_args(&self, config: &DebugTaskDefinition) -> StartDebuggingRequestArguments {
|
||||
let mut args = json!({
|
||||
"request": match config.request {
|
||||
DebugRequestType::Launch(_) => "launch",
|
||||
DebugRequestType::Attach(_) => "attach",
|
||||
},
|
||||
"subProcess": true,
|
||||
"redirectOutput": true,
|
||||
});
|
||||
let map = args.as_object_mut().unwrap();
|
||||
match &config.request {
|
||||
DebugRequestType::Attach(attach) => {
|
||||
map.insert("processId".into(), attach.process_id.into());
|
||||
}
|
||||
DebugRequestType::Launch(launch) => {
|
||||
map.insert("program".into(), launch.program.clone().into());
|
||||
map.insert("args".into(), launch.args.clone().into());
|
||||
|
||||
if let Some(stop_on_entry) = config.stop_on_entry {
|
||||
map.insert("stopOnEntry".into(), stop_on_entry.into());
|
||||
}
|
||||
if let Some(cwd) = launch.cwd.as_ref() {
|
||||
map.insert("cwd".into(), cwd.to_string_lossy().into_owned().into());
|
||||
}
|
||||
}
|
||||
}
|
||||
StartDebuggingRequestArguments {
|
||||
configuration: args,
|
||||
request: config.request.to_dap(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[async_trait(?Send)]
|
||||
@ -64,7 +96,7 @@ impl DebugAdapter for PythonDebugAdapter {
|
||||
async fn get_installed_binary(
|
||||
&self,
|
||||
delegate: &dyn DapDelegate,
|
||||
config: &DebugAdapterConfig,
|
||||
config: &DebugTaskDefinition,
|
||||
user_installed_path: Option<PathBuf>,
|
||||
cx: &mut AsyncApp,
|
||||
) -> Result<DebugAdapterBinary> {
|
||||
@ -109,6 +141,7 @@ impl DebugAdapter for PythonDebugAdapter {
|
||||
};
|
||||
|
||||
Ok(DebugAdapterBinary {
|
||||
adapter_name: self.name(),
|
||||
command: python_path.ok_or(anyhow!("failed to find binary path for python"))?,
|
||||
arguments: Some(vec![
|
||||
debugpy_dir.join(Self::ADAPTER_PATH).into(),
|
||||
@ -122,35 +155,7 @@ impl DebugAdapter for PythonDebugAdapter {
|
||||
}),
|
||||
cwd: None,
|
||||
envs: None,
|
||||
request_args: self.request_args(config),
|
||||
})
|
||||
}
|
||||
|
||||
fn request_args(&self, config: &DebugTaskDefinition) -> Value {
|
||||
let mut args = json!({
|
||||
"request": match config.request {
|
||||
DebugRequestType::Launch(_) => "launch",
|
||||
DebugRequestType::Attach(_) => "attach",
|
||||
},
|
||||
"subProcess": true,
|
||||
"redirectOutput": true,
|
||||
});
|
||||
let map = args.as_object_mut().unwrap();
|
||||
match &config.request {
|
||||
DebugRequestType::Attach(attach) => {
|
||||
map.insert("processId".into(), attach.process_id.into());
|
||||
}
|
||||
DebugRequestType::Launch(launch) => {
|
||||
map.insert("program".into(), launch.program.clone().into());
|
||||
map.insert("args".into(), launch.args.clone().into());
|
||||
|
||||
if let Some(stop_on_entry) = config.stop_on_entry {
|
||||
map.insert("stopOnEntry".into(), stop_on_entry.into());
|
||||
}
|
||||
if let Some(cwd) = launch.cwd.as_ref() {
|
||||
map.insert("cwd".into(), cwd.to_string_lossy().into_owned().into());
|
||||
}
|
||||
}
|
||||
}
|
||||
args
|
||||
}
|
||||
}
|
||||
|
@ -228,10 +228,7 @@ impl PickerDelegate for AttachModalDelegate {
|
||||
let config = self.debug_config.clone();
|
||||
self.project
|
||||
.update(cx, |project, cx| {
|
||||
#[cfg(any(test, feature = "test-support"))]
|
||||
let ret = project.fake_debug_session(config.request, None, false, cx);
|
||||
#[cfg(not(any(test, feature = "test-support")))]
|
||||
let ret = project.start_debug_session(config.into(), cx);
|
||||
let ret = project.start_debug_session(config, cx);
|
||||
ret
|
||||
})
|
||||
.detach_and_log_err(cx);
|
||||
|
@ -146,7 +146,7 @@ impl NewSessionModal {
|
||||
{
|
||||
this.start_debug_session(debug_config, cx)
|
||||
} else {
|
||||
this.start_debug_session(config.into(), cx)
|
||||
this.start_debug_session(config, cx)
|
||||
}
|
||||
})?;
|
||||
let spawn_result = task.await;
|
||||
|
@ -26,18 +26,30 @@ async fn test_direct_attach_to_process(executor: BackgroundExecutor, cx: &mut Te
|
||||
let workspace = init_test_workspace(&project, cx).await;
|
||||
let cx = &mut VisualTestContext::from_window(*workspace, cx);
|
||||
|
||||
let task = project.update(cx, |project, cx| {
|
||||
project.fake_debug_session(
|
||||
dap::DebugRequestType::Attach(AttachConfig {
|
||||
let session = debugger::test::start_debug_session_with(
|
||||
&project,
|
||||
cx,
|
||||
DebugTaskDefinition {
|
||||
adapter: "fake-adapter".to_string(),
|
||||
request: dap::DebugRequestType::Attach(AttachConfig {
|
||||
process_id: Some(10),
|
||||
}),
|
||||
None,
|
||||
false,
|
||||
cx,
|
||||
)
|
||||
});
|
||||
label: "label".to_string(),
|
||||
initialize_args: None,
|
||||
tcp_connection: None,
|
||||
locator: None,
|
||||
stop_on_entry: None,
|
||||
},
|
||||
|client| {
|
||||
client.on_request::<dap::requests::Attach, _>(move |_, args| {
|
||||
assert_eq!(json!({"request": "attach", "process_id": 10}), args.raw);
|
||||
|
||||
let session = task.await.unwrap();
|
||||
Ok(())
|
||||
});
|
||||
},
|
||||
)
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
cx.run_until_parked();
|
||||
|
||||
@ -77,7 +89,15 @@ async fn test_show_attach_modal_and_select_process(
|
||||
let project = Project::test(fs, ["/project".as_ref()], cx).await;
|
||||
let workspace = init_test_workspace(&project, cx).await;
|
||||
let cx = &mut VisualTestContext::from_window(*workspace, cx);
|
||||
// Set up handlers for sessions spawned via modal.
|
||||
let _initialize_subscription =
|
||||
project::debugger::test::intercept_debug_sessions(cx, |client| {
|
||||
client.on_request::<dap::requests::Attach, _>(move |_, args| {
|
||||
assert_eq!(json!({"request": "attach", "process_id": 1}), args.raw);
|
||||
|
||||
Ok(())
|
||||
});
|
||||
});
|
||||
let attach_modal = workspace
|
||||
.update(cx, |workspace, window, cx| {
|
||||
workspace.toggle_modal(window, cx, |window, cx| {
|
||||
|
@ -3,7 +3,6 @@ use dap::requests::StackTrace;
|
||||
use gpui::{BackgroundExecutor, TestAppContext, VisualTestContext};
|
||||
use project::{FakeFs, Project};
|
||||
use serde_json::json;
|
||||
use task::LaunchConfig;
|
||||
use tests::{init_test, init_test_workspace};
|
||||
|
||||
#[gpui::test]
|
||||
@ -29,26 +28,17 @@ async fn test_handle_output_event(executor: BackgroundExecutor, cx: &mut TestApp
|
||||
})
|
||||
.unwrap();
|
||||
|
||||
let task = project.update(cx, |project, cx| {
|
||||
project.fake_debug_session(
|
||||
dap::DebugRequestType::Launch(LaunchConfig::default()),
|
||||
None,
|
||||
false,
|
||||
cx,
|
||||
)
|
||||
});
|
||||
|
||||
let session = task.await.unwrap();
|
||||
let session = debugger::test::start_debug_session(&project, cx, |_| {})
|
||||
.await
|
||||
.unwrap();
|
||||
let client = session.update(cx, |session, _| session.adapter_client().unwrap());
|
||||
|
||||
client
|
||||
.on_request::<StackTrace, _>(move |_, _| {
|
||||
client.on_request::<StackTrace, _>(move |_, _| {
|
||||
Ok(dap::StackTraceResponse {
|
||||
stack_frames: Vec::default(),
|
||||
total_frames: None,
|
||||
})
|
||||
})
|
||||
.await;
|
||||
});
|
||||
|
||||
client
|
||||
.fake_event(dap::messages::Events::Output(dap::OutputEvent {
|
||||
|
@ -1,7 +1,7 @@
|
||||
use crate::*;
|
||||
use dap::{
|
||||
ErrorResponse, RunInTerminalRequestArguments, SourceBreakpoint, StartDebuggingRequestArguments,
|
||||
StartDebuggingRequestArgumentsRequest,
|
||||
ErrorResponse, Message, RunInTerminalRequestArguments, SourceBreakpoint,
|
||||
StartDebuggingRequestArguments, StartDebuggingRequestArgumentsRequest,
|
||||
client::SessionId,
|
||||
requests::{
|
||||
Continue, Disconnect, Launch, Next, RunInTerminal, SetBreakpoints, StackTrace,
|
||||
@ -25,7 +25,6 @@ use std::{
|
||||
atomic::{AtomicBool, Ordering},
|
||||
},
|
||||
};
|
||||
use task::LaunchConfig;
|
||||
use terminal_view::{TerminalView, terminal_panel::TerminalPanel};
|
||||
use tests::{active_debug_session_panel, init_test, init_test_workspace};
|
||||
use util::path;
|
||||
@ -49,37 +48,26 @@ async fn test_basic_show_debug_panel(executor: BackgroundExecutor, cx: &mut Test
|
||||
let workspace = init_test_workspace(&project, cx).await;
|
||||
let cx = &mut VisualTestContext::from_window(*workspace, cx);
|
||||
|
||||
let task = project.update(cx, |project, cx| {
|
||||
project.fake_debug_session(
|
||||
dap::DebugRequestType::Launch(LaunchConfig::default()),
|
||||
None,
|
||||
false,
|
||||
cx,
|
||||
)
|
||||
});
|
||||
|
||||
let session = task.await.unwrap();
|
||||
let session = debugger::test::start_debug_session(&project, cx, |_| {})
|
||||
.await
|
||||
.unwrap();
|
||||
let client = session.update(cx, |session, _| session.adapter_client().unwrap());
|
||||
|
||||
client
|
||||
.on_request::<Threads, _>(move |_, _| {
|
||||
client.on_request::<Threads, _>(move |_, _| {
|
||||
Ok(dap::ThreadsResponse {
|
||||
threads: vec![dap::Thread {
|
||||
id: 1,
|
||||
name: "Thread 1".into(),
|
||||
}],
|
||||
})
|
||||
})
|
||||
.await;
|
||||
});
|
||||
|
||||
client
|
||||
.on_request::<StackTrace, _>(move |_, _| {
|
||||
client.on_request::<StackTrace, _>(move |_, _| {
|
||||
Ok(dap::StackTraceResponse {
|
||||
stack_frames: Vec::default(),
|
||||
total_frames: None,
|
||||
})
|
||||
})
|
||||
.await;
|
||||
});
|
||||
|
||||
cx.run_until_parked();
|
||||
|
||||
@ -199,37 +187,26 @@ async fn test_we_can_only_have_one_panel_per_debug_session(
|
||||
let workspace = init_test_workspace(&project, cx).await;
|
||||
let cx = &mut VisualTestContext::from_window(*workspace, cx);
|
||||
|
||||
let task = project.update(cx, |project, cx| {
|
||||
project.fake_debug_session(
|
||||
dap::DebugRequestType::Launch(LaunchConfig::default()),
|
||||
None,
|
||||
false,
|
||||
cx,
|
||||
)
|
||||
});
|
||||
|
||||
let session = task.await.unwrap();
|
||||
let session = debugger::test::start_debug_session(&project, cx, |_| {})
|
||||
.await
|
||||
.unwrap();
|
||||
let client = session.update(cx, |session, _| session.adapter_client().unwrap());
|
||||
|
||||
client
|
||||
.on_request::<Threads, _>(move |_, _| {
|
||||
client.on_request::<Threads, _>(move |_, _| {
|
||||
Ok(dap::ThreadsResponse {
|
||||
threads: vec![dap::Thread {
|
||||
id: 1,
|
||||
name: "Thread 1".into(),
|
||||
}],
|
||||
})
|
||||
})
|
||||
.await;
|
||||
});
|
||||
|
||||
client
|
||||
.on_request::<StackTrace, _>(move |_, _| {
|
||||
client.on_request::<StackTrace, _>(move |_, _| {
|
||||
Ok(dap::StackTraceResponse {
|
||||
stack_frames: Vec::default(),
|
||||
total_frames: None,
|
||||
})
|
||||
})
|
||||
.await;
|
||||
});
|
||||
|
||||
cx.run_until_parked();
|
||||
|
||||
@ -377,16 +354,9 @@ async fn test_handle_successful_run_in_terminal_reverse_request(
|
||||
let workspace = init_test_workspace(&project, cx).await;
|
||||
let cx = &mut VisualTestContext::from_window(*workspace, cx);
|
||||
|
||||
let task = project.update(cx, |project, cx| {
|
||||
project.fake_debug_session(
|
||||
dap::DebugRequestType::Launch(LaunchConfig::default()),
|
||||
None,
|
||||
false,
|
||||
cx,
|
||||
)
|
||||
});
|
||||
|
||||
let session = task.await.unwrap();
|
||||
let session = debugger::test::start_debug_session(&project, cx, |_| {})
|
||||
.await
|
||||
.unwrap();
|
||||
let client = session.update(cx, |session, _| session.adapter_client().unwrap());
|
||||
|
||||
client
|
||||
@ -474,16 +444,9 @@ async fn test_handle_error_run_in_terminal_reverse_request(
|
||||
let workspace = init_test_workspace(&project, cx).await;
|
||||
let cx = &mut VisualTestContext::from_window(*workspace, cx);
|
||||
|
||||
let task = project.update(cx, |project, cx| {
|
||||
project.fake_debug_session(
|
||||
dap::DebugRequestType::Launch(LaunchConfig::default()),
|
||||
None,
|
||||
false,
|
||||
cx,
|
||||
)
|
||||
});
|
||||
|
||||
let session = task.await.unwrap();
|
||||
let session = debugger::test::start_debug_session(&project, cx, |_| {})
|
||||
.await
|
||||
.unwrap();
|
||||
let client = session.update(cx, |session, _| session.adapter_client().unwrap());
|
||||
|
||||
client
|
||||
@ -559,28 +522,19 @@ async fn test_handle_start_debugging_reverse_request(
|
||||
let workspace = init_test_workspace(&project, cx).await;
|
||||
let cx = &mut VisualTestContext::from_window(*workspace, cx);
|
||||
|
||||
let task = project.update(cx, |project, cx| {
|
||||
project.fake_debug_session(
|
||||
dap::DebugRequestType::Launch(LaunchConfig::default()),
|
||||
None,
|
||||
false,
|
||||
cx,
|
||||
)
|
||||
});
|
||||
|
||||
let session = task.await.unwrap();
|
||||
let session = debugger::test::start_debug_session(&project, cx, |_| {})
|
||||
.await
|
||||
.unwrap();
|
||||
let client = session.update(cx, |session, _| session.adapter_client().unwrap());
|
||||
|
||||
client
|
||||
.on_request::<dap::requests::Threads, _>(move |_, _| {
|
||||
client.on_request::<dap::requests::Threads, _>(move |_, _| {
|
||||
Ok(dap::ThreadsResponse {
|
||||
threads: vec![dap::Thread {
|
||||
id: 1,
|
||||
name: "Thread 1".into(),
|
||||
}],
|
||||
})
|
||||
})
|
||||
.await;
|
||||
});
|
||||
|
||||
client
|
||||
.on_response::<StartDebugging, _>({
|
||||
@ -593,7 +547,9 @@ async fn test_handle_start_debugging_reverse_request(
|
||||
}
|
||||
})
|
||||
.await;
|
||||
|
||||
// Set up handlers for sessions spawned with reverse request too.
|
||||
let _reverse_request_subscription =
|
||||
project::debugger::test::intercept_debug_sessions(cx, |_| {});
|
||||
client
|
||||
.fake_reverse_request::<StartDebugging>(StartDebuggingRequestArguments {
|
||||
configuration: json!({}),
|
||||
@ -612,20 +568,16 @@ async fn test_handle_start_debugging_reverse_request(
|
||||
});
|
||||
let child_client = child_session.update(cx, |session, _| session.adapter_client().unwrap());
|
||||
|
||||
child_client
|
||||
.on_request::<dap::requests::Threads, _>(move |_, _| {
|
||||
child_client.on_request::<dap::requests::Threads, _>(move |_, _| {
|
||||
Ok(dap::ThreadsResponse {
|
||||
threads: vec![dap::Thread {
|
||||
id: 1,
|
||||
name: "Thread 1".into(),
|
||||
}],
|
||||
})
|
||||
})
|
||||
.await;
|
||||
});
|
||||
|
||||
child_client
|
||||
.on_request::<Disconnect, _>(move |_, _| Ok(()))
|
||||
.await;
|
||||
child_client.on_request::<Disconnect, _>(move |_, _| Ok(()));
|
||||
|
||||
child_client
|
||||
.fake_event(dap::messages::Events::Stopped(dap::StoppedEvent {
|
||||
@ -677,31 +629,24 @@ async fn test_shutdown_children_when_parent_session_shutdown(
|
||||
let workspace = init_test_workspace(&project, cx).await;
|
||||
let cx = &mut VisualTestContext::from_window(*workspace, cx);
|
||||
|
||||
let task = project.update(cx, |project, cx| {
|
||||
project.fake_debug_session(
|
||||
dap::DebugRequestType::Launch(LaunchConfig::default()),
|
||||
None,
|
||||
false,
|
||||
cx,
|
||||
)
|
||||
});
|
||||
|
||||
let parent_session = task.await.unwrap();
|
||||
let parent_session = debugger::test::start_debug_session(&project, cx, |_| {})
|
||||
.await
|
||||
.unwrap();
|
||||
let client = parent_session.update(cx, |session, _| session.adapter_client().unwrap());
|
||||
|
||||
client
|
||||
.on_request::<dap::requests::Threads, _>(move |_, _| {
|
||||
client.on_request::<dap::requests::Threads, _>(move |_, _| {
|
||||
Ok(dap::ThreadsResponse {
|
||||
threads: vec![dap::Thread {
|
||||
id: 1,
|
||||
name: "Thread 1".into(),
|
||||
}],
|
||||
})
|
||||
})
|
||||
.await;
|
||||
});
|
||||
|
||||
client.on_response::<StartDebugging, _>(move |_| {}).await;
|
||||
|
||||
// Set up handlers for sessions spawned with reverse request too.
|
||||
let _reverse_request_subscription =
|
||||
project::debugger::test::intercept_debug_sessions(cx, |_| {});
|
||||
// start first child session
|
||||
client
|
||||
.fake_reverse_request::<StartDebugging>(StartDebuggingRequestArguments {
|
||||
@ -729,9 +674,7 @@ async fn test_shutdown_children_when_parent_session_shutdown(
|
||||
let first_child_client =
|
||||
first_child_session.update(cx, |session, _| session.adapter_client().unwrap());
|
||||
|
||||
first_child_client
|
||||
.on_request::<Disconnect, _>(move |_, _| Ok(()))
|
||||
.await;
|
||||
first_child_client.on_request::<Disconnect, _>(move |_, _| Ok(()));
|
||||
|
||||
// configure second child session
|
||||
let second_child_session = dap_store.read_with(cx, |dap_store, _| {
|
||||
@ -740,9 +683,7 @@ async fn test_shutdown_children_when_parent_session_shutdown(
|
||||
let second_child_client =
|
||||
second_child_session.update(cx, |session, _| session.adapter_client().unwrap());
|
||||
|
||||
second_child_client
|
||||
.on_request::<Disconnect, _>(move |_, _| Ok(()))
|
||||
.await;
|
||||
second_child_client.on_request::<Disconnect, _>(move |_, _| Ok(()));
|
||||
|
||||
cx.run_until_parked();
|
||||
|
||||
@ -796,20 +737,15 @@ async fn test_shutdown_parent_session_if_all_children_are_shutdown(
|
||||
let workspace = init_test_workspace(&project, cx).await;
|
||||
let cx = &mut VisualTestContext::from_window(*workspace, cx);
|
||||
|
||||
let task = project.update(cx, |project, cx| {
|
||||
project.fake_debug_session(
|
||||
dap::DebugRequestType::Launch(LaunchConfig::default()),
|
||||
None,
|
||||
false,
|
||||
cx,
|
||||
)
|
||||
});
|
||||
|
||||
let parent_session = task.await.unwrap();
|
||||
let parent_session = debugger::test::start_debug_session(&project, cx, |_| {})
|
||||
.await
|
||||
.unwrap();
|
||||
let client = parent_session.update(cx, |session, _| session.adapter_client().unwrap());
|
||||
|
||||
client.on_response::<StartDebugging, _>(move |_| {}).await;
|
||||
|
||||
// Set up handlers for sessions spawned with reverse request too.
|
||||
let _reverse_request_subscription =
|
||||
project::debugger::test::intercept_debug_sessions(cx, |_| {});
|
||||
// start first child session
|
||||
client
|
||||
.fake_reverse_request::<StartDebugging>(StartDebuggingRequestArguments {
|
||||
@ -837,9 +773,7 @@ async fn test_shutdown_parent_session_if_all_children_are_shutdown(
|
||||
let first_child_client =
|
||||
first_child_session.update(cx, |session, _| session.adapter_client().unwrap());
|
||||
|
||||
first_child_client
|
||||
.on_request::<Disconnect, _>(move |_, _| Ok(()))
|
||||
.await;
|
||||
first_child_client.on_request::<Disconnect, _>(move |_, _| Ok(()));
|
||||
|
||||
// configure second child session
|
||||
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(
|
||||
let second_child_client =
|
||||
second_child_session.update(cx, |session, _| session.adapter_client().unwrap());
|
||||
|
||||
second_child_client
|
||||
.on_request::<Disconnect, _>(move |_, _| Ok(()))
|
||||
.await;
|
||||
second_child_client.on_request::<Disconnect, _>(move |_, _| Ok(()));
|
||||
|
||||
cx.run_until_parked();
|
||||
|
||||
@ -926,46 +858,39 @@ async fn test_debug_panel_item_thread_status_reset_on_failure(
|
||||
let workspace = init_test_workspace(&project, cx).await;
|
||||
let cx = &mut VisualTestContext::from_window(*workspace, cx);
|
||||
|
||||
let task = project.update(cx, |project, cx| {
|
||||
project.fake_debug_session(
|
||||
dap::DebugRequestType::Launch(LaunchConfig::default()),
|
||||
Some(dap::Capabilities {
|
||||
let session = debugger::test::start_debug_session(&project, cx, |client| {
|
||||
client.on_request::<dap::requests::Initialize, _>(move |_, _| {
|
||||
Ok(dap::Capabilities {
|
||||
supports_step_back: Some(true),
|
||||
..Default::default()
|
||||
}),
|
||||
false,
|
||||
cx,
|
||||
)
|
||||
})
|
||||
});
|
||||
})
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
let session = task.await.unwrap();
|
||||
let client = session.update(cx, |session, _| session.adapter_client().unwrap());
|
||||
const THREAD_ID_NUM: u64 = 1;
|
||||
|
||||
client
|
||||
.on_request::<dap::requests::Threads, _>(move |_, _| {
|
||||
client.on_request::<dap::requests::Threads, _>(move |_, _| {
|
||||
Ok(dap::ThreadsResponse {
|
||||
threads: vec![dap::Thread {
|
||||
id: THREAD_ID_NUM,
|
||||
name: "Thread 1".into(),
|
||||
}],
|
||||
})
|
||||
})
|
||||
.await;
|
||||
});
|
||||
|
||||
client.on_request::<Launch, _>(move |_, _| Ok(())).await;
|
||||
client.on_request::<Launch, _>(move |_, _| Ok(()));
|
||||
|
||||
client
|
||||
.on_request::<StackTrace, _>(move |_, _| {
|
||||
client.on_request::<StackTrace, _>(move |_, _| {
|
||||
Ok(dap::StackTraceResponse {
|
||||
stack_frames: Vec::default(),
|
||||
total_frames: None,
|
||||
})
|
||||
})
|
||||
.await;
|
||||
});
|
||||
|
||||
client
|
||||
.on_request::<Next, _>(move |_, _| {
|
||||
client.on_request::<Next, _>(move |_, _| {
|
||||
Err(ErrorResponse {
|
||||
error: Some(dap::Message {
|
||||
id: 1,
|
||||
@ -977,11 +902,9 @@ async fn test_debug_panel_item_thread_status_reset_on_failure(
|
||||
url_label: None,
|
||||
}),
|
||||
})
|
||||
})
|
||||
.await;
|
||||
});
|
||||
|
||||
client
|
||||
.on_request::<StepOut, _>(move |_, _| {
|
||||
client.on_request::<StepOut, _>(move |_, _| {
|
||||
Err(ErrorResponse {
|
||||
error: Some(dap::Message {
|
||||
id: 1,
|
||||
@ -993,11 +916,9 @@ async fn test_debug_panel_item_thread_status_reset_on_failure(
|
||||
url_label: None,
|
||||
}),
|
||||
})
|
||||
})
|
||||
.await;
|
||||
});
|
||||
|
||||
client
|
||||
.on_request::<StepIn, _>(move |_, _| {
|
||||
client.on_request::<StepIn, _>(move |_, _| {
|
||||
Err(ErrorResponse {
|
||||
error: Some(dap::Message {
|
||||
id: 1,
|
||||
@ -1009,11 +930,9 @@ async fn test_debug_panel_item_thread_status_reset_on_failure(
|
||||
url_label: None,
|
||||
}),
|
||||
})
|
||||
})
|
||||
.await;
|
||||
});
|
||||
|
||||
client
|
||||
.on_request::<StepBack, _>(move |_, _| {
|
||||
client.on_request::<StepBack, _>(move |_, _| {
|
||||
Err(ErrorResponse {
|
||||
error: Some(dap::Message {
|
||||
id: 1,
|
||||
@ -1025,11 +944,9 @@ async fn test_debug_panel_item_thread_status_reset_on_failure(
|
||||
url_label: None,
|
||||
}),
|
||||
})
|
||||
})
|
||||
.await;
|
||||
});
|
||||
|
||||
client
|
||||
.on_request::<Continue, _>(move |_, _| {
|
||||
client.on_request::<Continue, _>(move |_, _| {
|
||||
Err(ErrorResponse {
|
||||
error: Some(dap::Message {
|
||||
id: 1,
|
||||
@ -1041,8 +958,7 @@ async fn test_debug_panel_item_thread_status_reset_on_failure(
|
||||
url_label: None,
|
||||
}),
|
||||
})
|
||||
})
|
||||
.await;
|
||||
});
|
||||
|
||||
client
|
||||
.fake_event(dap::messages::Events::Stopped(dap::StoppedEvent {
|
||||
@ -1157,16 +1073,9 @@ async fn test_send_breakpoints_when_editor_has_been_saved(
|
||||
.update(cx, |_, _, cx| worktree.read(cx).id())
|
||||
.unwrap();
|
||||
|
||||
let task = project.update(cx, |project, cx| {
|
||||
project.fake_debug_session(
|
||||
dap::DebugRequestType::Launch(LaunchConfig::default()),
|
||||
None,
|
||||
false,
|
||||
cx,
|
||||
)
|
||||
});
|
||||
|
||||
let session = task.await.unwrap();
|
||||
let session = debugger::test::start_debug_session(&project, cx, |_| {})
|
||||
.await
|
||||
.unwrap();
|
||||
let client = session.update(cx, |session, _| session.adapter_client().unwrap());
|
||||
|
||||
let buffer = project
|
||||
@ -1186,16 +1095,14 @@ async fn test_send_breakpoints_when_editor_has_been_saved(
|
||||
)
|
||||
});
|
||||
|
||||
client.on_request::<Launch, _>(move |_, _| Ok(())).await;
|
||||
client.on_request::<Launch, _>(move |_, _| Ok(()));
|
||||
|
||||
client
|
||||
.on_request::<StackTrace, _>(move |_, _| {
|
||||
client.on_request::<StackTrace, _>(move |_, _| {
|
||||
Ok(dap::StackTraceResponse {
|
||||
stack_frames: Vec::default(),
|
||||
total_frames: None,
|
||||
})
|
||||
})
|
||||
.await;
|
||||
});
|
||||
|
||||
client
|
||||
.fake_event(dap::messages::Events::Stopped(dap::StoppedEvent {
|
||||
@ -1210,8 +1117,7 @@ async fn test_send_breakpoints_when_editor_has_been_saved(
|
||||
.await;
|
||||
|
||||
let called_set_breakpoints = Arc::new(AtomicBool::new(false));
|
||||
client
|
||||
.on_request::<SetBreakpoints, _>({
|
||||
client.on_request::<SetBreakpoints, _>({
|
||||
let called_set_breakpoints = called_set_breakpoints.clone();
|
||||
move |_, args| {
|
||||
assert_eq!(path!("/project/main.rs"), args.source.path.unwrap());
|
||||
@ -1234,8 +1140,7 @@ async fn test_send_breakpoints_when_editor_has_been_saved(
|
||||
breakpoints: Vec::default(),
|
||||
})
|
||||
}
|
||||
})
|
||||
.await;
|
||||
});
|
||||
|
||||
editor.update_in(cx, |editor, window, cx| {
|
||||
editor.move_down(&actions::MoveDown, window, cx);
|
||||
@ -1250,8 +1155,7 @@ async fn test_send_breakpoints_when_editor_has_been_saved(
|
||||
);
|
||||
|
||||
let called_set_breakpoints = Arc::new(AtomicBool::new(false));
|
||||
client
|
||||
.on_request::<SetBreakpoints, _>({
|
||||
client.on_request::<SetBreakpoints, _>({
|
||||
let called_set_breakpoints = called_set_breakpoints.clone();
|
||||
move |_, args| {
|
||||
assert_eq!(path!("/project/main.rs"), args.source.path.unwrap());
|
||||
@ -1274,8 +1178,7 @@ async fn test_send_breakpoints_when_editor_has_been_saved(
|
||||
breakpoints: Vec::default(),
|
||||
})
|
||||
}
|
||||
})
|
||||
.await;
|
||||
});
|
||||
|
||||
editor.update_in(cx, |editor, window, cx| {
|
||||
editor.move_up(&actions::MoveUp, window, cx);
|
||||
@ -1387,22 +1290,14 @@ async fn test_unsetting_breakpoints_on_clear_breakpoint_action(
|
||||
editor.toggle_breakpoint(&actions::ToggleBreakpoint, window, cx);
|
||||
});
|
||||
|
||||
let task = project.update(cx, |project, cx| {
|
||||
project.fake_debug_session(
|
||||
dap::DebugRequestType::Launch(LaunchConfig::default()),
|
||||
None,
|
||||
false,
|
||||
cx,
|
||||
)
|
||||
});
|
||||
|
||||
let session = task.await.unwrap();
|
||||
let session = debugger::test::start_debug_session(&project, cx, |_| {})
|
||||
.await
|
||||
.unwrap();
|
||||
let client = session.update(cx, |session, _| session.adapter_client().unwrap());
|
||||
|
||||
let called_set_breakpoints = Arc::new(AtomicBool::new(false));
|
||||
|
||||
client
|
||||
.on_request::<SetBreakpoints, _>({
|
||||
client.on_request::<SetBreakpoints, _>({
|
||||
let called_set_breakpoints = called_set_breakpoints.clone();
|
||||
move |_, args| {
|
||||
assert!(
|
||||
@ -1428,8 +1323,7 @@ async fn test_unsetting_breakpoints_on_clear_breakpoint_action(
|
||||
breakpoints: Vec::default(),
|
||||
})
|
||||
}
|
||||
})
|
||||
.await;
|
||||
});
|
||||
|
||||
cx.dispatch_action(crate::ClearAllBreakpoints);
|
||||
cx.run_until_parked();
|
||||
@ -1464,13 +1358,20 @@ async fn test_debug_session_is_shutdown_when_attach_and_launch_request_fails(
|
||||
let workspace = init_test_workspace(&project, cx).await;
|
||||
let cx = &mut VisualTestContext::from_window(*workspace, cx);
|
||||
|
||||
let task = project.update(cx, |project, cx| {
|
||||
project.fake_debug_session(
|
||||
dap::DebugRequestType::Launch(LaunchConfig::default()),
|
||||
None,
|
||||
true,
|
||||
cx,
|
||||
)
|
||||
let task = project::debugger::test::start_debug_session(&project, cx, |client| {
|
||||
client.on_request::<dap::requests::Initialize, _>(|_, _| {
|
||||
Err(ErrorResponse {
|
||||
error: Some(Message {
|
||||
format: "failed to launch".to_string(),
|
||||
id: 1,
|
||||
variables: None,
|
||||
send_telemetry: None,
|
||||
show_user: None,
|
||||
url: None,
|
||||
url_label: None,
|
||||
}),
|
||||
})
|
||||
});
|
||||
});
|
||||
|
||||
assert!(
|
||||
|
@ -4,15 +4,17 @@ use crate::{
|
||||
};
|
||||
use dap::{
|
||||
StoppedEvent,
|
||||
requests::{Modules, StackTrace, Threads},
|
||||
requests::{Initialize, Modules},
|
||||
};
|
||||
use gpui::{BackgroundExecutor, TestAppContext, VisualTestContext};
|
||||
use project::{FakeFs, Project};
|
||||
use project::{
|
||||
FakeFs, Project,
|
||||
debugger::{self},
|
||||
};
|
||||
use std::sync::{
|
||||
Arc,
|
||||
atomic::{AtomicBool, AtomicI32, Ordering},
|
||||
};
|
||||
use task::LaunchConfig;
|
||||
|
||||
#[gpui::test]
|
||||
async fn test_module_list(executor: BackgroundExecutor, cx: &mut TestAppContext) {
|
||||
@ -29,31 +31,19 @@ async fn test_module_list(executor: BackgroundExecutor, cx: &mut TestAppContext)
|
||||
.unwrap();
|
||||
let cx = &mut VisualTestContext::from_window(*workspace, cx);
|
||||
|
||||
let task = project.update(cx, |project, cx| {
|
||||
project.fake_debug_session(
|
||||
dap::DebugRequestType::Launch(LaunchConfig::default()),
|
||||
Some(dap::Capabilities {
|
||||
let session = debugger::test::start_debug_session(&project, cx, |client| {
|
||||
client.on_request::<Initialize, _>(move |_, _| {
|
||||
Ok(dap::Capabilities {
|
||||
supports_modules_request: Some(true),
|
||||
..Default::default()
|
||||
}),
|
||||
false,
|
||||
cx,
|
||||
)
|
||||
})
|
||||
});
|
||||
})
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
let session = task.await.unwrap();
|
||||
let client = session.update(cx, |session, _| session.adapter_client().unwrap());
|
||||
|
||||
client
|
||||
.on_request::<StackTrace, _>(move |_, args| {
|
||||
assert!(args.thread_id == 1);
|
||||
Ok(dap::StackTraceResponse {
|
||||
stack_frames: Vec::default(),
|
||||
total_frames: None,
|
||||
})
|
||||
})
|
||||
.await;
|
||||
|
||||
let called_modules = Arc::new(AtomicBool::new(false));
|
||||
let modules = vec![
|
||||
dap::Module {
|
||||
@ -82,19 +72,7 @@ async fn test_module_list(executor: BackgroundExecutor, cx: &mut TestAppContext)
|
||||
},
|
||||
];
|
||||
|
||||
client
|
||||
.on_request::<Threads, _>(move |_, _| {
|
||||
Ok(dap::ThreadsResponse {
|
||||
threads: vec![dap::Thread {
|
||||
id: 1,
|
||||
name: "Thread 1".into(),
|
||||
}],
|
||||
})
|
||||
})
|
||||
.await;
|
||||
|
||||
client
|
||||
.on_request::<Modules, _>({
|
||||
client.on_request::<Modules, _>({
|
||||
let called_modules = called_modules.clone();
|
||||
let modules_request_count = AtomicI32::new(0);
|
||||
let modules = modules.clone();
|
||||
@ -112,8 +90,7 @@ async fn test_module_list(executor: BackgroundExecutor, cx: &mut TestAppContext)
|
||||
total_modules: Some(2u64),
|
||||
})
|
||||
}
|
||||
})
|
||||
.await;
|
||||
});
|
||||
|
||||
client
|
||||
.fake_event(dap::messages::Events::Stopped(StoppedEvent {
|
||||
|
@ -5,14 +5,13 @@ use crate::{
|
||||
};
|
||||
use dap::{
|
||||
StackFrame,
|
||||
requests::{StackTrace, Threads},
|
||||
requests::{Scopes, StackTrace, Threads},
|
||||
};
|
||||
use editor::{Editor, ToPoint as _};
|
||||
use gpui::{BackgroundExecutor, TestAppContext, VisualTestContext};
|
||||
use project::{FakeFs, Project};
|
||||
use project::{FakeFs, Project, debugger};
|
||||
use serde_json::json;
|
||||
use std::sync::Arc;
|
||||
use task::LaunchConfig;
|
||||
use unindent::Unindent as _;
|
||||
use util::path;
|
||||
|
||||
@ -51,29 +50,20 @@ async fn test_fetch_initial_stack_frames_and_go_to_stack_frame(
|
||||
let project = Project::test(fs, [path!("/project").as_ref()], cx).await;
|
||||
let workspace = init_test_workspace(&project, cx).await;
|
||||
let cx = &mut VisualTestContext::from_window(*workspace, cx);
|
||||
|
||||
let task = project.update(cx, |project, cx| {
|
||||
project.fake_debug_session(
|
||||
dap::DebugRequestType::Launch(LaunchConfig::default()),
|
||||
None,
|
||||
false,
|
||||
cx,
|
||||
)
|
||||
});
|
||||
|
||||
let session = task.await.unwrap();
|
||||
let session = debugger::test::start_debug_session(&project, cx, |_| {})
|
||||
.await
|
||||
.unwrap();
|
||||
let client = session.update(cx, |session, _| session.adapter_client().unwrap());
|
||||
client.on_request::<Scopes, _>(move |_, _| Ok(dap::ScopesResponse { scopes: vec![] }));
|
||||
|
||||
client
|
||||
.on_request::<Threads, _>(move |_, _| {
|
||||
client.on_request::<Threads, _>(move |_, _| {
|
||||
Ok(dap::ThreadsResponse {
|
||||
threads: vec![dap::Thread {
|
||||
id: 1,
|
||||
name: "Thread 1".into(),
|
||||
}],
|
||||
})
|
||||
})
|
||||
.await;
|
||||
});
|
||||
|
||||
let stack_frames = vec![
|
||||
StackFrame {
|
||||
@ -122,8 +112,7 @@ async fn test_fetch_initial_stack_frames_and_go_to_stack_frame(
|
||||
},
|
||||
];
|
||||
|
||||
client
|
||||
.on_request::<StackTrace, _>({
|
||||
client.on_request::<StackTrace, _>({
|
||||
let stack_frames = Arc::new(stack_frames.clone());
|
||||
move |_, args| {
|
||||
assert_eq!(1, args.thread_id);
|
||||
@ -133,8 +122,7 @@ async fn test_fetch_initial_stack_frames_and_go_to_stack_frame(
|
||||
total_frames: None,
|
||||
})
|
||||
}
|
||||
})
|
||||
.await;
|
||||
});
|
||||
|
||||
client
|
||||
.fake_event(dap::messages::Events::Stopped(dap::StoppedEvent {
|
||||
@ -241,29 +229,21 @@ async fn test_select_stack_frame(executor: BackgroundExecutor, cx: &mut TestAppC
|
||||
});
|
||||
|
||||
let cx = &mut VisualTestContext::from_window(*workspace, cx);
|
||||
|
||||
let task = project.update(cx, |project, cx| {
|
||||
project.fake_debug_session(
|
||||
dap::DebugRequestType::Launch(LaunchConfig::default()),
|
||||
None,
|
||||
false,
|
||||
cx,
|
||||
)
|
||||
});
|
||||
|
||||
let session = task.await.unwrap();
|
||||
let session = debugger::test::start_debug_session(&project, cx, |_| {})
|
||||
.await
|
||||
.unwrap();
|
||||
let client = session.update(cx, |session, _| session.adapter_client().unwrap());
|
||||
|
||||
client
|
||||
.on_request::<Threads, _>(move |_, _| {
|
||||
client.on_request::<Threads, _>(move |_, _| {
|
||||
Ok(dap::ThreadsResponse {
|
||||
threads: vec![dap::Thread {
|
||||
id: 1,
|
||||
name: "Thread 1".into(),
|
||||
}],
|
||||
})
|
||||
})
|
||||
.await;
|
||||
});
|
||||
|
||||
client.on_request::<Scopes, _>(move |_, _| Ok(dap::ScopesResponse { scopes: vec![] }));
|
||||
|
||||
let stack_frames = vec![
|
||||
StackFrame {
|
||||
@ -312,8 +292,7 @@ async fn test_select_stack_frame(executor: BackgroundExecutor, cx: &mut TestAppC
|
||||
},
|
||||
];
|
||||
|
||||
client
|
||||
.on_request::<StackTrace, _>({
|
||||
client.on_request::<StackTrace, _>({
|
||||
let stack_frames = Arc::new(stack_frames.clone());
|
||||
move |_, args| {
|
||||
assert_eq!(1, args.thread_id);
|
||||
@ -323,8 +302,7 @@ async fn test_select_stack_frame(executor: BackgroundExecutor, cx: &mut TestAppC
|
||||
total_frames: None,
|
||||
})
|
||||
}
|
||||
})
|
||||
.await;
|
||||
});
|
||||
|
||||
client
|
||||
.fake_event(dap::messages::Events::Stopped(dap::StoppedEvent {
|
||||
@ -517,28 +495,21 @@ async fn test_collapsed_entries(executor: BackgroundExecutor, cx: &mut TestAppCo
|
||||
let workspace = init_test_workspace(&project, cx).await;
|
||||
let cx = &mut VisualTestContext::from_window(*workspace, cx);
|
||||
|
||||
let task = project.update(cx, |project, cx| {
|
||||
project.fake_debug_session(
|
||||
dap::DebugRequestType::Launch(LaunchConfig::default()),
|
||||
None,
|
||||
false,
|
||||
cx,
|
||||
)
|
||||
});
|
||||
|
||||
let session = task.await.unwrap();
|
||||
let session = debugger::test::start_debug_session(&project, cx, |_| {})
|
||||
.await
|
||||
.unwrap();
|
||||
let client = session.update(cx, |session, _| session.adapter_client().unwrap());
|
||||
|
||||
client
|
||||
.on_request::<Threads, _>(move |_, _| {
|
||||
client.on_request::<Threads, _>(move |_, _| {
|
||||
Ok(dap::ThreadsResponse {
|
||||
threads: vec![dap::Thread {
|
||||
id: 1,
|
||||
name: "Thread 1".into(),
|
||||
}],
|
||||
})
|
||||
})
|
||||
.await;
|
||||
});
|
||||
|
||||
client.on_request::<Scopes, _>(move |_, _| Ok(dap::ScopesResponse { scopes: vec![] }));
|
||||
|
||||
let stack_frames = vec![
|
||||
StackFrame {
|
||||
@ -697,8 +668,7 @@ async fn test_collapsed_entries(executor: BackgroundExecutor, cx: &mut TestAppCo
|
||||
},
|
||||
];
|
||||
|
||||
client
|
||||
.on_request::<StackTrace, _>({
|
||||
client.on_request::<StackTrace, _>({
|
||||
let stack_frames = Arc::new(stack_frames.clone());
|
||||
move |_, args| {
|
||||
assert_eq!(1, args.thread_id);
|
||||
@ -708,8 +678,7 @@ async fn test_collapsed_entries(executor: BackgroundExecutor, cx: &mut TestAppCo
|
||||
total_frames: None,
|
||||
})
|
||||
}
|
||||
})
|
||||
.await;
|
||||
});
|
||||
|
||||
client
|
||||
.fake_event(dap::messages::Events::Stopped(dap::StoppedEvent {
|
||||
|
@ -15,9 +15,8 @@ use dap::{
|
||||
};
|
||||
use gpui::{BackgroundExecutor, TestAppContext, VisualTestContext};
|
||||
use menu::{SelectFirst, SelectNext, SelectPrevious};
|
||||
use project::{FakeFs, Project};
|
||||
use project::{FakeFs, Project, debugger};
|
||||
use serde_json::json;
|
||||
use task::LaunchConfig;
|
||||
use unindent::Unindent as _;
|
||||
use util::path;
|
||||
|
||||
@ -55,29 +54,19 @@ async fn test_basic_fetch_initial_scope_and_variables(
|
||||
})
|
||||
.unwrap();
|
||||
let cx = &mut VisualTestContext::from_window(*workspace, cx);
|
||||
|
||||
let task = project.update(cx, |project, cx| {
|
||||
project.fake_debug_session(
|
||||
dap::DebugRequestType::Launch(LaunchConfig::default()),
|
||||
None,
|
||||
false,
|
||||
cx,
|
||||
)
|
||||
});
|
||||
|
||||
let session = task.await.unwrap();
|
||||
let session = debugger::test::start_debug_session(&project, cx, |_| {})
|
||||
.await
|
||||
.unwrap();
|
||||
let client = session.update(cx, |session, _| session.adapter_client().unwrap());
|
||||
|
||||
client
|
||||
.on_request::<dap::requests::Threads, _>(move |_, _| {
|
||||
client.on_request::<dap::requests::Threads, _>(move |_, _| {
|
||||
Ok(dap::ThreadsResponse {
|
||||
threads: vec![dap::Thread {
|
||||
id: 1,
|
||||
name: "Thread 1".into(),
|
||||
}],
|
||||
})
|
||||
})
|
||||
.await;
|
||||
});
|
||||
|
||||
let stack_frames = vec![StackFrame {
|
||||
id: 1,
|
||||
@ -102,8 +91,7 @@ async fn test_basic_fetch_initial_scope_and_variables(
|
||||
presentation_hint: None,
|
||||
}];
|
||||
|
||||
client
|
||||
.on_request::<StackTrace, _>({
|
||||
client.on_request::<StackTrace, _>({
|
||||
let stack_frames = Arc::new(stack_frames.clone());
|
||||
move |_, args| {
|
||||
assert_eq!(1, args.thread_id);
|
||||
@ -113,8 +101,7 @@ async fn test_basic_fetch_initial_scope_and_variables(
|
||||
total_frames: None,
|
||||
})
|
||||
}
|
||||
})
|
||||
.await;
|
||||
});
|
||||
|
||||
let scopes = vec![Scope {
|
||||
name: "Scope 1".into(),
|
||||
@ -130,8 +117,7 @@ async fn test_basic_fetch_initial_scope_and_variables(
|
||||
end_column: None,
|
||||
}];
|
||||
|
||||
client
|
||||
.on_request::<Scopes, _>({
|
||||
client.on_request::<Scopes, _>({
|
||||
let scopes = Arc::new(scopes.clone());
|
||||
move |_, args| {
|
||||
assert_eq!(1, args.frame_id);
|
||||
@ -140,8 +126,7 @@ async fn test_basic_fetch_initial_scope_and_variables(
|
||||
scopes: (*scopes).clone(),
|
||||
})
|
||||
}
|
||||
})
|
||||
.await;
|
||||
});
|
||||
|
||||
let variables = vec![
|
||||
Variable {
|
||||
@ -172,8 +157,7 @@ async fn test_basic_fetch_initial_scope_and_variables(
|
||||
},
|
||||
];
|
||||
|
||||
client
|
||||
.on_request::<Variables, _>({
|
||||
client.on_request::<Variables, _>({
|
||||
let variables = Arc::new(variables.clone());
|
||||
move |_, args| {
|
||||
assert_eq!(2, args.variables_reference);
|
||||
@ -182,8 +166,7 @@ async fn test_basic_fetch_initial_scope_and_variables(
|
||||
variables: (*variables).clone(),
|
||||
})
|
||||
}
|
||||
})
|
||||
.await;
|
||||
});
|
||||
|
||||
client
|
||||
.fake_event(dap::messages::Events::Stopped(dap::StoppedEvent {
|
||||
@ -283,39 +266,28 @@ async fn test_fetch_variables_for_multiple_scopes(
|
||||
.unwrap();
|
||||
let cx = &mut VisualTestContext::from_window(*workspace, cx);
|
||||
|
||||
let task = project.update(cx, |project, cx| {
|
||||
project.fake_debug_session(
|
||||
dap::DebugRequestType::Launch(LaunchConfig::default()),
|
||||
None,
|
||||
false,
|
||||
cx,
|
||||
)
|
||||
});
|
||||
|
||||
let session = task.await.unwrap();
|
||||
let session = debugger::test::start_debug_session(&project, cx, |_| {})
|
||||
.await
|
||||
.unwrap();
|
||||
let client = session.update(cx, |session, _| session.adapter_client().unwrap());
|
||||
|
||||
client
|
||||
.on_request::<dap::requests::Threads, _>(move |_, _| {
|
||||
client.on_request::<dap::requests::Threads, _>(move |_, _| {
|
||||
Ok(dap::ThreadsResponse {
|
||||
threads: vec![dap::Thread {
|
||||
id: 1,
|
||||
name: "Thread 1".into(),
|
||||
}],
|
||||
})
|
||||
})
|
||||
.await;
|
||||
});
|
||||
|
||||
client
|
||||
.on_request::<Initialize, _>(move |_, _| {
|
||||
client.on_request::<Initialize, _>(move |_, _| {
|
||||
Ok(dap::Capabilities {
|
||||
supports_step_back: Some(false),
|
||||
..Default::default()
|
||||
})
|
||||
})
|
||||
.await;
|
||||
});
|
||||
|
||||
client.on_request::<Launch, _>(move |_, _| Ok(())).await;
|
||||
client.on_request::<Launch, _>(move |_, _| Ok(()));
|
||||
|
||||
let stack_frames = vec![StackFrame {
|
||||
id: 1,
|
||||
@ -340,8 +312,7 @@ async fn test_fetch_variables_for_multiple_scopes(
|
||||
presentation_hint: None,
|
||||
}];
|
||||
|
||||
client
|
||||
.on_request::<StackTrace, _>({
|
||||
client.on_request::<StackTrace, _>({
|
||||
let stack_frames = Arc::new(stack_frames.clone());
|
||||
move |_, args| {
|
||||
assert_eq!(1, args.thread_id);
|
||||
@ -351,8 +322,7 @@ async fn test_fetch_variables_for_multiple_scopes(
|
||||
total_frames: None,
|
||||
})
|
||||
}
|
||||
})
|
||||
.await;
|
||||
});
|
||||
|
||||
let scopes = vec![
|
||||
Scope {
|
||||
@ -383,8 +353,7 @@ async fn test_fetch_variables_for_multiple_scopes(
|
||||
},
|
||||
];
|
||||
|
||||
client
|
||||
.on_request::<Scopes, _>({
|
||||
client.on_request::<Scopes, _>({
|
||||
let scopes = Arc::new(scopes.clone());
|
||||
move |_, args| {
|
||||
assert_eq!(1, args.frame_id);
|
||||
@ -393,8 +362,7 @@ async fn test_fetch_variables_for_multiple_scopes(
|
||||
scopes: (*scopes).clone(),
|
||||
})
|
||||
}
|
||||
})
|
||||
.await;
|
||||
});
|
||||
|
||||
let mut variables = HashMap::default();
|
||||
variables.insert(
|
||||
@ -445,16 +413,14 @@ async fn test_fetch_variables_for_multiple_scopes(
|
||||
}],
|
||||
);
|
||||
|
||||
client
|
||||
.on_request::<Variables, _>({
|
||||
client.on_request::<Variables, _>({
|
||||
let variables = Arc::new(variables.clone());
|
||||
move |_, args| {
|
||||
Ok(dap::VariablesResponse {
|
||||
variables: variables.get(&args.variables_reference).unwrap().clone(),
|
||||
})
|
||||
}
|
||||
})
|
||||
.await;
|
||||
});
|
||||
|
||||
client
|
||||
.fake_event(dap::messages::Events::Stopped(dap::StoppedEvent {
|
||||
@ -562,40 +528,28 @@ async fn test_keyboard_navigation(executor: BackgroundExecutor, cx: &mut TestApp
|
||||
})
|
||||
.unwrap();
|
||||
let cx = &mut VisualTestContext::from_window(*workspace, cx);
|
||||
|
||||
let task = project.update(cx, |project, cx| {
|
||||
project.fake_debug_session(
|
||||
dap::DebugRequestType::Launch(LaunchConfig::default()),
|
||||
None,
|
||||
false,
|
||||
cx,
|
||||
)
|
||||
});
|
||||
|
||||
let session = task.await.unwrap();
|
||||
let session = debugger::test::start_debug_session(&project, cx, |_| {})
|
||||
.await
|
||||
.unwrap();
|
||||
let client = session.update(cx, |session, _| session.adapter_client().unwrap());
|
||||
|
||||
client
|
||||
.on_request::<dap::requests::Threads, _>(move |_, _| {
|
||||
client.on_request::<dap::requests::Threads, _>(move |_, _| {
|
||||
Ok(dap::ThreadsResponse {
|
||||
threads: vec![dap::Thread {
|
||||
id: 1,
|
||||
name: "Thread 1".into(),
|
||||
}],
|
||||
})
|
||||
})
|
||||
.await;
|
||||
});
|
||||
|
||||
client
|
||||
.on_request::<Initialize, _>(move |_, _| {
|
||||
client.on_request::<Initialize, _>(move |_, _| {
|
||||
Ok(dap::Capabilities {
|
||||
supports_step_back: Some(false),
|
||||
..Default::default()
|
||||
})
|
||||
})
|
||||
.await;
|
||||
});
|
||||
|
||||
client.on_request::<Launch, _>(move |_, _| Ok(())).await;
|
||||
client.on_request::<Launch, _>(move |_, _| Ok(()));
|
||||
|
||||
let stack_frames = vec![StackFrame {
|
||||
id: 1,
|
||||
@ -620,8 +574,7 @@ async fn test_keyboard_navigation(executor: BackgroundExecutor, cx: &mut TestApp
|
||||
presentation_hint: None,
|
||||
}];
|
||||
|
||||
client
|
||||
.on_request::<StackTrace, _>({
|
||||
client.on_request::<StackTrace, _>({
|
||||
let stack_frames = Arc::new(stack_frames.clone());
|
||||
move |_, args| {
|
||||
assert_eq!(1, args.thread_id);
|
||||
@ -631,8 +584,7 @@ async fn test_keyboard_navigation(executor: BackgroundExecutor, cx: &mut TestApp
|
||||
total_frames: None,
|
||||
})
|
||||
}
|
||||
})
|
||||
.await;
|
||||
});
|
||||
|
||||
let scopes = vec![
|
||||
Scope {
|
||||
@ -663,8 +615,7 @@ async fn test_keyboard_navigation(executor: BackgroundExecutor, cx: &mut TestApp
|
||||
},
|
||||
];
|
||||
|
||||
client
|
||||
.on_request::<Scopes, _>({
|
||||
client.on_request::<Scopes, _>({
|
||||
let scopes = Arc::new(scopes.clone());
|
||||
move |_, args| {
|
||||
assert_eq!(1, args.frame_id);
|
||||
@ -673,8 +624,7 @@ async fn test_keyboard_navigation(executor: BackgroundExecutor, cx: &mut TestApp
|
||||
scopes: (*scopes).clone(),
|
||||
})
|
||||
}
|
||||
})
|
||||
.await;
|
||||
});
|
||||
|
||||
let scope1_variables = vec![
|
||||
Variable {
|
||||
@ -748,8 +698,7 @@ async fn test_keyboard_navigation(executor: BackgroundExecutor, cx: &mut TestApp
|
||||
value_location_reference: None,
|
||||
}];
|
||||
|
||||
client
|
||||
.on_request::<Variables, _>({
|
||||
client.on_request::<Variables, _>({
|
||||
let scope1_variables = Arc::new(scope1_variables.clone());
|
||||
let nested_variables = Arc::new(nested_variables.clone());
|
||||
let scope2_variables = Arc::new(scope2_variables.clone());
|
||||
@ -765,8 +714,7 @@ async fn test_keyboard_navigation(executor: BackgroundExecutor, cx: &mut TestApp
|
||||
}),
|
||||
id => unreachable!("unexpected variables reference {id}"),
|
||||
}
|
||||
})
|
||||
.await;
|
||||
});
|
||||
|
||||
client
|
||||
.fake_event(dap::messages::Events::Stopped(dap::StoppedEvent {
|
||||
@ -1365,39 +1313,28 @@ async fn test_variable_list_only_sends_requests_when_rendering(
|
||||
let workspace = init_test_workspace(&project, cx).await;
|
||||
let cx = &mut VisualTestContext::from_window(*workspace, cx);
|
||||
|
||||
let task = project.update(cx, |project, cx| {
|
||||
project.fake_debug_session(
|
||||
dap::DebugRequestType::Launch(LaunchConfig::default()),
|
||||
None,
|
||||
false,
|
||||
cx,
|
||||
)
|
||||
});
|
||||
|
||||
let session = task.await.unwrap();
|
||||
let session = debugger::test::start_debug_session(&project, cx, |_| {})
|
||||
.await
|
||||
.unwrap();
|
||||
let client = session.update(cx, |session, _| session.adapter_client().unwrap());
|
||||
|
||||
client
|
||||
.on_request::<dap::requests::Threads, _>(move |_, _| {
|
||||
client.on_request::<dap::requests::Threads, _>(move |_, _| {
|
||||
Ok(dap::ThreadsResponse {
|
||||
threads: vec![dap::Thread {
|
||||
id: 1,
|
||||
name: "Thread 1".into(),
|
||||
}],
|
||||
})
|
||||
})
|
||||
.await;
|
||||
});
|
||||
|
||||
client
|
||||
.on_request::<Initialize, _>(move |_, _| {
|
||||
client.on_request::<Initialize, _>(move |_, _| {
|
||||
Ok(dap::Capabilities {
|
||||
supports_step_back: Some(false),
|
||||
..Default::default()
|
||||
})
|
||||
})
|
||||
.await;
|
||||
});
|
||||
|
||||
client.on_request::<Launch, _>(move |_, _| Ok(())).await;
|
||||
client.on_request::<Launch, _>(move |_, _| Ok(()));
|
||||
|
||||
let stack_frames = vec![
|
||||
StackFrame {
|
||||
@ -1446,8 +1383,7 @@ async fn test_variable_list_only_sends_requests_when_rendering(
|
||||
},
|
||||
];
|
||||
|
||||
client
|
||||
.on_request::<StackTrace, _>({
|
||||
client.on_request::<StackTrace, _>({
|
||||
let stack_frames = Arc::new(stack_frames.clone());
|
||||
move |_, args| {
|
||||
assert_eq!(1, args.thread_id);
|
||||
@ -1457,8 +1393,7 @@ async fn test_variable_list_only_sends_requests_when_rendering(
|
||||
total_frames: None,
|
||||
})
|
||||
}
|
||||
})
|
||||
.await;
|
||||
});
|
||||
|
||||
let frame_1_scopes = vec![Scope {
|
||||
name: "Frame 1 Scope 1".into(),
|
||||
@ -1476,8 +1411,7 @@ async fn test_variable_list_only_sends_requests_when_rendering(
|
||||
|
||||
let made_scopes_request = Arc::new(AtomicBool::new(false));
|
||||
|
||||
client
|
||||
.on_request::<Scopes, _>({
|
||||
client.on_request::<Scopes, _>({
|
||||
let frame_1_scopes = Arc::new(frame_1_scopes.clone());
|
||||
let made_scopes_request = made_scopes_request.clone();
|
||||
move |_, args| {
|
||||
@ -1493,8 +1427,7 @@ async fn test_variable_list_only_sends_requests_when_rendering(
|
||||
scopes: (*frame_1_scopes).clone(),
|
||||
})
|
||||
}
|
||||
})
|
||||
.await;
|
||||
});
|
||||
|
||||
let frame_1_variables = vec![
|
||||
Variable {
|
||||
@ -1525,8 +1458,7 @@ async fn test_variable_list_only_sends_requests_when_rendering(
|
||||
},
|
||||
];
|
||||
|
||||
client
|
||||
.on_request::<Variables, _>({
|
||||
client.on_request::<Variables, _>({
|
||||
let frame_1_variables = Arc::new(frame_1_variables.clone());
|
||||
move |_, args| {
|
||||
assert_eq!(2, args.variables_reference);
|
||||
@ -1535,8 +1467,7 @@ async fn test_variable_list_only_sends_requests_when_rendering(
|
||||
variables: (*frame_1_variables).clone(),
|
||||
})
|
||||
}
|
||||
})
|
||||
.await;
|
||||
});
|
||||
|
||||
cx.run_until_parked();
|
||||
|
||||
@ -1629,39 +1560,28 @@ async fn test_it_fetches_scopes_variables_when_you_select_a_stack_frame(
|
||||
.unwrap();
|
||||
let cx = &mut VisualTestContext::from_window(*workspace, cx);
|
||||
|
||||
let task = project.update(cx, |project, cx| {
|
||||
project.fake_debug_session(
|
||||
dap::DebugRequestType::Launch(LaunchConfig::default()),
|
||||
None,
|
||||
false,
|
||||
cx,
|
||||
)
|
||||
});
|
||||
|
||||
let session = task.await.unwrap();
|
||||
let session = debugger::test::start_debug_session(&project, cx, |_| {})
|
||||
.await
|
||||
.unwrap();
|
||||
let client = session.update(cx, |session, _| session.adapter_client().unwrap());
|
||||
|
||||
client
|
||||
.on_request::<dap::requests::Threads, _>(move |_, _| {
|
||||
client.on_request::<dap::requests::Threads, _>(move |_, _| {
|
||||
Ok(dap::ThreadsResponse {
|
||||
threads: vec![dap::Thread {
|
||||
id: 1,
|
||||
name: "Thread 1".into(),
|
||||
}],
|
||||
})
|
||||
})
|
||||
.await;
|
||||
});
|
||||
|
||||
client
|
||||
.on_request::<Initialize, _>(move |_, _| {
|
||||
client.on_request::<Initialize, _>(move |_, _| {
|
||||
Ok(dap::Capabilities {
|
||||
supports_step_back: Some(false),
|
||||
..Default::default()
|
||||
})
|
||||
})
|
||||
.await;
|
||||
});
|
||||
|
||||
client.on_request::<Launch, _>(move |_, _| Ok(())).await;
|
||||
client.on_request::<Launch, _>(move |_, _| Ok(()));
|
||||
|
||||
let stack_frames = vec![
|
||||
StackFrame {
|
||||
@ -1710,8 +1630,7 @@ async fn test_it_fetches_scopes_variables_when_you_select_a_stack_frame(
|
||||
},
|
||||
];
|
||||
|
||||
client
|
||||
.on_request::<StackTrace, _>({
|
||||
client.on_request::<StackTrace, _>({
|
||||
let stack_frames = Arc::new(stack_frames.clone());
|
||||
move |_, args| {
|
||||
assert_eq!(1, args.thread_id);
|
||||
@ -1721,8 +1640,7 @@ async fn test_it_fetches_scopes_variables_when_you_select_a_stack_frame(
|
||||
total_frames: None,
|
||||
})
|
||||
}
|
||||
})
|
||||
.await;
|
||||
});
|
||||
|
||||
let frame_1_scopes = vec![Scope {
|
||||
name: "Frame 1 Scope 1".into(),
|
||||
@ -1757,8 +1675,7 @@ async fn test_it_fetches_scopes_variables_when_you_select_a_stack_frame(
|
||||
let called_second_stack_frame = Arc::new(AtomicBool::new(false));
|
||||
let called_first_stack_frame = Arc::new(AtomicBool::new(false));
|
||||
|
||||
client
|
||||
.on_request::<Scopes, _>({
|
||||
client.on_request::<Scopes, _>({
|
||||
let frame_1_scopes = Arc::new(frame_1_scopes.clone());
|
||||
let frame_2_scopes = Arc::new(frame_2_scopes.clone());
|
||||
let called_first_stack_frame = called_first_stack_frame.clone();
|
||||
@ -1779,8 +1696,7 @@ async fn test_it_fetches_scopes_variables_when_you_select_a_stack_frame(
|
||||
}
|
||||
_ => panic!("Made a scopes request with an invalid frame id"),
|
||||
}
|
||||
})
|
||||
.await;
|
||||
});
|
||||
|
||||
let frame_1_variables = vec![
|
||||
Variable {
|
||||
@ -1840,8 +1756,7 @@ async fn test_it_fetches_scopes_variables_when_you_select_a_stack_frame(
|
||||
},
|
||||
];
|
||||
|
||||
client
|
||||
.on_request::<Variables, _>({
|
||||
client.on_request::<Variables, _>({
|
||||
let frame_1_variables = Arc::new(frame_1_variables.clone());
|
||||
move |_, args| {
|
||||
assert_eq!(2, args.variables_reference);
|
||||
@ -1850,8 +1765,7 @@ async fn test_it_fetches_scopes_variables_when_you_select_a_stack_frame(
|
||||
variables: (*frame_1_variables).clone(),
|
||||
})
|
||||
}
|
||||
})
|
||||
.await;
|
||||
});
|
||||
|
||||
client
|
||||
.fake_event(dap::messages::Events::Stopped(dap::StoppedEvent {
|
||||
@ -1907,8 +1821,7 @@ async fn test_it_fetches_scopes_variables_when_you_select_a_stack_frame(
|
||||
assert_eq!(frame_1_variables, variables);
|
||||
});
|
||||
|
||||
client
|
||||
.on_request::<Variables, _>({
|
||||
client.on_request::<Variables, _>({
|
||||
let frame_2_variables = Arc::new(frame_2_variables.clone());
|
||||
move |_, args| {
|
||||
assert_eq!(3, args.variables_reference);
|
||||
@ -1917,8 +1830,7 @@ async fn test_it_fetches_scopes_variables_when_you_select_a_stack_frame(
|
||||
variables: (*frame_2_variables).clone(),
|
||||
})
|
||||
}
|
||||
})
|
||||
.await;
|
||||
});
|
||||
|
||||
running_state
|
||||
.update_in(cx, |running_state, window, cx| {
|
||||
|
@ -16,3 +16,6 @@ pub mod dap_command;
|
||||
pub mod dap_store;
|
||||
mod locator_store;
|
||||
pub mod session;
|
||||
|
||||
#[cfg(any(feature = "test-support", test))]
|
||||
pub mod test;
|
||||
|
@ -3,15 +3,15 @@ use super::{
|
||||
locator_store::LocatorStore,
|
||||
session::{self, Session, SessionStateEvent},
|
||||
};
|
||||
use crate::{ProjectEnvironment, debugger, worktree_store::WorktreeStore};
|
||||
use crate::{ProjectEnvironment, debugger};
|
||||
use anyhow::{Result, anyhow};
|
||||
use async_trait::async_trait;
|
||||
use collections::HashMap;
|
||||
use dap::{
|
||||
Capabilities, CompletionItem, CompletionsArguments, DapRegistry, ErrorResponse,
|
||||
EvaluateArguments, EvaluateArgumentsContext, EvaluateResponse, RunInTerminalRequestArguments,
|
||||
Source, StartDebuggingRequestArguments,
|
||||
adapters::{DapStatus, DebugAdapterName},
|
||||
Capabilities, CompletionItem, CompletionsArguments, ErrorResponse, EvaluateArguments,
|
||||
EvaluateArgumentsContext, EvaluateResponse, RunInTerminalRequestArguments, Source,
|
||||
StartDebuggingRequestArguments,
|
||||
adapters::{DapStatus, DebugAdapterBinary, DebugAdapterName},
|
||||
client::SessionId,
|
||||
messages::Message,
|
||||
requests::{Completions, Evaluate, Request as _, RunInTerminal, StartDebugging},
|
||||
@ -42,7 +42,7 @@ use std::{
|
||||
sync::{Arc, atomic::Ordering::SeqCst},
|
||||
};
|
||||
use std::{collections::VecDeque, sync::atomic::AtomicU32};
|
||||
use task::{DebugAdapterConfig, DebugRequestDisposition};
|
||||
use task::DebugTaskDefinition;
|
||||
use util::ResultExt as _;
|
||||
use worktree::Worktree;
|
||||
|
||||
@ -78,10 +78,8 @@ pub struct LocalDapStore {
|
||||
node_runtime: NodeRuntime,
|
||||
next_session_id: AtomicU32,
|
||||
http_client: Arc<dyn HttpClient>,
|
||||
worktree_store: Entity<WorktreeStore>,
|
||||
environment: Entity<ProjectEnvironment>,
|
||||
language_registry: Arc<LanguageRegistry>,
|
||||
debug_adapters: Arc<DapRegistry>,
|
||||
toolchain_store: Arc<dyn LanguageToolchainStore>,
|
||||
locator_store: Arc<LocatorStore>,
|
||||
start_debugging_tx: futures::channel::mpsc::UnboundedSender<(SessionId, Message)>,
|
||||
@ -132,11 +130,9 @@ impl DapStore {
|
||||
node_runtime: NodeRuntime,
|
||||
fs: Arc<dyn Fs>,
|
||||
language_registry: Arc<LanguageRegistry>,
|
||||
debug_adapters: Arc<DapRegistry>,
|
||||
environment: Entity<ProjectEnvironment>,
|
||||
toolchain_store: Arc<dyn LanguageToolchainStore>,
|
||||
breakpoint_store: Entity<BreakpointStore>,
|
||||
worktree_store: Entity<WorktreeStore>,
|
||||
cx: &mut Context<Self>,
|
||||
) -> Self {
|
||||
cx.on_app_quit(Self::shutdown_sessions).detach();
|
||||
@ -170,10 +166,8 @@ impl DapStore {
|
||||
environment,
|
||||
http_client,
|
||||
node_runtime,
|
||||
worktree_store,
|
||||
toolchain_store,
|
||||
language_registry,
|
||||
debug_adapters,
|
||||
start_debugging_tx,
|
||||
_start_debugging_task,
|
||||
locator_store: Arc::from(LocatorStore::new()),
|
||||
@ -320,18 +314,12 @@ impl DapStore {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn new_session(
|
||||
&mut self,
|
||||
mut config: DebugAdapterConfig,
|
||||
worktree: &Entity<Worktree>,
|
||||
parent_session: Option<Entity<Session>>,
|
||||
cx: &mut Context<Self>,
|
||||
) -> (SessionId, Task<Result<Entity<Session>>>) {
|
||||
pub fn delegate(&self, worktree: &Entity<Worktree>, cx: &mut App) -> DapAdapterDelegate {
|
||||
let Some(local_store) = self.as_local() else {
|
||||
unimplemented!("Starting session on remote side");
|
||||
};
|
||||
|
||||
let delegate = DapAdapterDelegate::new(
|
||||
DapAdapterDelegate::new(
|
||||
local_store.fs.clone(),
|
||||
worktree.read(cx).id(),
|
||||
local_store.node_runtime.clone(),
|
||||
@ -341,7 +329,20 @@ impl DapStore {
|
||||
local_store.environment.update(cx, |env, cx| {
|
||||
env.get_worktree_environment(worktree.clone(), cx)
|
||||
}),
|
||||
);
|
||||
)
|
||||
}
|
||||
|
||||
pub fn new_session(
|
||||
&mut self,
|
||||
binary: DebugAdapterBinary,
|
||||
mut config: DebugTaskDefinition,
|
||||
parent_session: Option<Entity<Session>>,
|
||||
cx: &mut Context<Self>,
|
||||
) -> (SessionId, Task<Result<Entity<Session>>>) {
|
||||
let Some(local_store) = self.as_local() else {
|
||||
unimplemented!("Starting session on remote side");
|
||||
};
|
||||
|
||||
let session_id = local_store.next_session_id();
|
||||
|
||||
if let Some(session) = &parent_session {
|
||||
@ -352,7 +353,6 @@ impl DapStore {
|
||||
|
||||
let (initialized_tx, initialized_rx) = oneshot::channel();
|
||||
let locator_store = local_store.locator_store.clone();
|
||||
let debug_adapters = local_store.debug_adapters.clone();
|
||||
|
||||
let start_debugging_tx = local_store.start_debugging_tx.clone();
|
||||
|
||||
@ -373,86 +373,31 @@ impl DapStore {
|
||||
this.breakpoint_store.clone(),
|
||||
session_id,
|
||||
parent_session,
|
||||
delegate,
|
||||
binary,
|
||||
config,
|
||||
start_debugging_tx.clone(),
|
||||
initialized_tx,
|
||||
debug_adapters,
|
||||
cx,
|
||||
)
|
||||
})?;
|
||||
|
||||
this.update(cx, |_, cx| {
|
||||
let ret = this
|
||||
.update(cx, |_, cx| {
|
||||
create_new_session(session_id, initialized_rx, start_client_task, cx)
|
||||
})?
|
||||
.await
|
||||
.await;
|
||||
ret
|
||||
});
|
||||
|
||||
(session_id, task)
|
||||
}
|
||||
|
||||
#[cfg(any(test, feature = "test-support"))]
|
||||
pub fn new_fake_session(
|
||||
&mut self,
|
||||
config: DebugAdapterConfig,
|
||||
worktree: &Entity<Worktree>,
|
||||
parent_session: Option<Entity<Session>>,
|
||||
caps: Capabilities,
|
||||
fails: bool,
|
||||
cx: &mut Context<Self>,
|
||||
) -> (SessionId, Task<Result<Entity<Session>>>) {
|
||||
let Some(local_store) = self.as_local() else {
|
||||
unimplemented!("Starting session on remote side");
|
||||
};
|
||||
|
||||
let delegate = DapAdapterDelegate::new(
|
||||
local_store.fs.clone(),
|
||||
worktree.read(cx).id(),
|
||||
local_store.node_runtime.clone(),
|
||||
local_store.http_client.clone(),
|
||||
local_store.language_registry.clone(),
|
||||
local_store.toolchain_store.clone(),
|
||||
local_store.environment.update(cx, |env, cx| {
|
||||
env.get_worktree_environment(worktree.clone(), cx)
|
||||
}),
|
||||
);
|
||||
let session_id = local_store.next_session_id();
|
||||
|
||||
if let Some(session) = &parent_session {
|
||||
session.update(cx, |session, _| {
|
||||
session.add_child_session_id(session_id);
|
||||
});
|
||||
}
|
||||
|
||||
let (initialized_tx, initialized_rx) = oneshot::channel();
|
||||
|
||||
let start_client_task = Session::fake(
|
||||
self.breakpoint_store.clone(),
|
||||
session_id,
|
||||
parent_session,
|
||||
delegate,
|
||||
config,
|
||||
local_store.start_debugging_tx.clone(),
|
||||
initialized_tx,
|
||||
caps,
|
||||
fails,
|
||||
cx,
|
||||
);
|
||||
|
||||
let task = create_new_session(session_id, initialized_rx, start_client_task, cx);
|
||||
(session_id, task)
|
||||
}
|
||||
|
||||
fn handle_start_debugging_request(
|
||||
&mut self,
|
||||
session_id: SessionId,
|
||||
request: dap::messages::Request,
|
||||
cx: &mut Context<Self>,
|
||||
) -> Task<Result<()>> {
|
||||
let Some(local_store) = self.as_local() else {
|
||||
unreachable!("Cannot response for non-local session");
|
||||
};
|
||||
|
||||
let Some(parent_session) = self.session_by_id(session_id) else {
|
||||
return Task::ready(Err(anyhow!("Session not found")));
|
||||
};
|
||||
@ -461,41 +406,12 @@ impl DapStore {
|
||||
request.arguments.unwrap_or_default(),
|
||||
)
|
||||
.expect("To parse StartDebuggingRequestArguments");
|
||||
let worktree = local_store
|
||||
.worktree_store
|
||||
.update(cx, |this, _| this.worktrees().next())
|
||||
.expect("worktree-less project");
|
||||
let mut binary = parent_session.read(cx).binary().clone();
|
||||
let config = parent_session.read(cx).configuration().unwrap().clone();
|
||||
binary.request_args = args;
|
||||
|
||||
let Some(config) = parent_session.read(cx).configuration() else {
|
||||
unreachable!("there must be a config for local sessions");
|
||||
};
|
||||
|
||||
let debug_config = DebugAdapterConfig {
|
||||
label: config.label,
|
||||
adapter: config.adapter,
|
||||
request: DebugRequestDisposition::ReverseRequest(args),
|
||||
initialize_args: config.initialize_args.clone(),
|
||||
tcp_connection: config.tcp_connection.clone(),
|
||||
locator: None,
|
||||
stop_on_entry: config.stop_on_entry,
|
||||
};
|
||||
|
||||
#[cfg(any(test, feature = "test-support"))]
|
||||
let new_session_task = {
|
||||
let caps = parent_session.read(cx).capabilities.clone();
|
||||
self.new_fake_session(
|
||||
debug_config,
|
||||
&worktree,
|
||||
Some(parent_session.clone()),
|
||||
caps,
|
||||
false,
|
||||
cx,
|
||||
)
|
||||
.1
|
||||
};
|
||||
#[cfg(not(any(test, feature = "test-support")))]
|
||||
let new_session_task = self
|
||||
.new_session(debug_config, &worktree, Some(parent_session.clone()), cx)
|
||||
.new_session(binary, config, Some(parent_session.clone()), cx)
|
||||
.1;
|
||||
|
||||
let request_seq = request.seq;
|
||||
@ -607,13 +523,7 @@ impl DapStore {
|
||||
.map(Arc::from)
|
||||
.or_else(|| {
|
||||
self.session_by_id(session_id)
|
||||
.and_then(|session| {
|
||||
session
|
||||
.read(cx)
|
||||
.configuration()
|
||||
.and_then(|config| config.request.cwd())
|
||||
})
|
||||
.map(Arc::from)
|
||||
.and_then(|session| session.read(cx).binary().cwd.as_deref().map(Arc::from))
|
||||
});
|
||||
cx.emit(DapStoreEvent::RunInTerminal {
|
||||
session_id,
|
||||
@ -852,7 +762,7 @@ fn create_new_session(
|
||||
cx.emit(DapStoreEvent::DebugClientStarted(session_id));
|
||||
cx.notify();
|
||||
})?;
|
||||
let seq_result = {
|
||||
let seq_result = async || {
|
||||
session
|
||||
.update(cx, |session, cx| session.request_initialize(cx))?
|
||||
.await?;
|
||||
@ -863,12 +773,11 @@ fn create_new_session(
|
||||
})?
|
||||
.await
|
||||
};
|
||||
match seq_result {
|
||||
match seq_result().await {
|
||||
Ok(_) => {}
|
||||
Err(error) => {
|
||||
this.update(cx, |this, cx| {
|
||||
cx.emit(DapStoreEvent::Notification(error.to_string()));
|
||||
|
||||
this.shutdown_session(session_id, cx)
|
||||
})?
|
||||
.await
|
||||
|
@ -1,9 +1,9 @@
|
||||
use anyhow::{Result, anyhow};
|
||||
use cargo::CargoLocator;
|
||||
use collections::HashMap;
|
||||
use dap::DebugAdapterConfig;
|
||||
use gpui::SharedString;
|
||||
use locators::DapLocator;
|
||||
use task::DebugTaskDefinition;
|
||||
|
||||
mod cargo;
|
||||
mod locators;
|
||||
@ -23,7 +23,7 @@ impl LocatorStore {
|
||||
|
||||
pub(super) async fn resolve_debug_config(
|
||||
&self,
|
||||
debug_config: &mut DebugAdapterConfig,
|
||||
debug_config: &mut DebugTaskDefinition,
|
||||
) -> Result<()> {
|
||||
let Some(locator_name) = &debug_config.locator else {
|
||||
log::debug!("Attempted to resolve debug config without a locator field");
|
||||
|
@ -1,12 +1,12 @@
|
||||
use super::DapLocator;
|
||||
use anyhow::{Result, anyhow};
|
||||
use async_trait::async_trait;
|
||||
use dap::DebugAdapterConfig;
|
||||
use serde_json::{Value, json};
|
||||
use smol::{
|
||||
io::AsyncReadExt,
|
||||
process::{Command, Stdio},
|
||||
};
|
||||
use task::DebugTaskDefinition;
|
||||
use util::maybe;
|
||||
|
||||
pub(super) struct CargoLocator;
|
||||
@ -38,11 +38,9 @@ async fn find_best_executable(executables: &[String], test_name: &str) -> Option
|
||||
}
|
||||
#[async_trait]
|
||||
impl DapLocator for CargoLocator {
|
||||
async fn run_locator(&self, debug_config: &mut DebugAdapterConfig) -> Result<()> {
|
||||
async fn run_locator(&self, debug_config: &mut DebugTaskDefinition) -> Result<()> {
|
||||
let Some(launch_config) = (match &mut debug_config.request {
|
||||
task::DebugRequestDisposition::UserConfigured(task::DebugRequestType::Launch(
|
||||
launch_config,
|
||||
)) => Some(launch_config),
|
||||
task::DebugRequestType::Launch(launch_config) => Some(launch_config),
|
||||
_ => None,
|
||||
}) else {
|
||||
return Err(anyhow!("Couldn't get launch config in locator"));
|
||||
|
@ -1,8 +1,8 @@
|
||||
use anyhow::Result;
|
||||
use async_trait::async_trait;
|
||||
use dap::DebugAdapterConfig;
|
||||
use task::DebugTaskDefinition;
|
||||
|
||||
#[async_trait]
|
||||
pub(super) trait DapLocator: Send + Sync {
|
||||
async fn run_locator(&self, debug_config: &mut DebugAdapterConfig) -> Result<()>;
|
||||
async fn run_locator(&self, debug_config: &mut DebugTaskDefinition) -> Result<()>;
|
||||
}
|
||||
|
@ -1,5 +1,3 @@
|
||||
use crate::project_settings::ProjectSettings;
|
||||
|
||||
use super::breakpoint_store::{
|
||||
BreakpointStore, BreakpointStoreEvent, BreakpointUpdatedReason, SourceBreakpoint,
|
||||
};
|
||||
@ -11,22 +9,17 @@ use super::dap_command::{
|
||||
StepBackCommand, StepCommand, StepInCommand, StepOutCommand, TerminateCommand,
|
||||
TerminateThreadsCommand, ThreadsCommand, VariablesCommand,
|
||||
};
|
||||
use super::dap_store::DapAdapterDelegate;
|
||||
use anyhow::{Context as _, Result, anyhow};
|
||||
use collections::{HashMap, HashSet, IndexMap, IndexSet};
|
||||
use dap::adapters::{DebugAdapter, DebugAdapterBinary};
|
||||
use dap::adapters::DebugAdapterBinary;
|
||||
use dap::messages::Response;
|
||||
use dap::{
|
||||
Capabilities, ContinueArguments, EvaluateArgumentsContext, Module, Source, StackFrameId,
|
||||
SteppingGranularity, StoppedEvent, VariableReference,
|
||||
adapters::{DapDelegate, DapStatus},
|
||||
client::{DebugAdapterClient, SessionId},
|
||||
messages::{Events, Message},
|
||||
};
|
||||
use dap::{
|
||||
DapRegistry, DebugRequestType, ExceptionBreakpointsFilter, ExceptionFilterOptions,
|
||||
OutputEventCategory,
|
||||
};
|
||||
use dap::{ExceptionBreakpointsFilter, ExceptionFilterOptions, OutputEventCategory};
|
||||
use futures::channel::oneshot;
|
||||
use futures::{FutureExt, future::Shared};
|
||||
use gpui::{
|
||||
@ -35,11 +28,9 @@ use gpui::{
|
||||
};
|
||||
use rpc::AnyProtoClient;
|
||||
use serde_json::{Value, json};
|
||||
use settings::Settings;
|
||||
use smol::stream::StreamExt;
|
||||
use std::any::TypeId;
|
||||
use std::collections::BTreeMap;
|
||||
use std::path::PathBuf;
|
||||
use std::u64;
|
||||
use std::{
|
||||
any::Any,
|
||||
@ -48,7 +39,7 @@ use std::{
|
||||
path::Path,
|
||||
sync::Arc,
|
||||
};
|
||||
use task::{DebugAdapterConfig, DebugTaskDefinition};
|
||||
use task::DebugTaskDefinition;
|
||||
use text::{PointUtf16, ToPointUtf16};
|
||||
use util::{ResultExt, merge_json_value_into};
|
||||
|
||||
@ -168,9 +159,9 @@ enum Mode {
|
||||
#[derive(Clone)]
|
||||
pub struct LocalMode {
|
||||
client: Arc<DebugAdapterClient>,
|
||||
config: DebugAdapterConfig,
|
||||
adapter: Arc<dyn DebugAdapter>,
|
||||
breakpoint_store: Entity<BreakpointStore>,
|
||||
definition: DebugTaskDefinition,
|
||||
binary: DebugAdapterBinary,
|
||||
pub(crate) breakpoint_store: Entity<BreakpointStore>,
|
||||
tmp_breakpoint: Option<SourceBreakpoint>,
|
||||
}
|
||||
|
||||
@ -191,185 +182,37 @@ fn client_source(abs_path: &Path) -> dap::Source {
|
||||
|
||||
impl LocalMode {
|
||||
fn new(
|
||||
debug_adapters: Arc<DapRegistry>,
|
||||
session_id: SessionId,
|
||||
parent_session: Option<Entity<Session>>,
|
||||
breakpoint_store: Entity<BreakpointStore>,
|
||||
config: DebugAdapterConfig,
|
||||
delegate: DapAdapterDelegate,
|
||||
config: DebugTaskDefinition,
|
||||
binary: DebugAdapterBinary,
|
||||
messages_tx: futures::channel::mpsc::UnboundedSender<Message>,
|
||||
cx: AsyncApp,
|
||||
) -> Task<Result<Self>> {
|
||||
Self::new_inner(
|
||||
debug_adapters,
|
||||
session_id,
|
||||
parent_session,
|
||||
breakpoint_store,
|
||||
config,
|
||||
delegate,
|
||||
binary,
|
||||
messages_tx,
|
||||
async |_, _| {},
|
||||
cx,
|
||||
)
|
||||
}
|
||||
#[cfg(any(test, feature = "test-support"))]
|
||||
fn new_fake(
|
||||
session_id: SessionId,
|
||||
parent_session: Option<Entity<Session>>,
|
||||
breakpoint_store: Entity<BreakpointStore>,
|
||||
config: DebugAdapterConfig,
|
||||
delegate: DapAdapterDelegate,
|
||||
messages_tx: futures::channel::mpsc::UnboundedSender<Message>,
|
||||
caps: Capabilities,
|
||||
fail: bool,
|
||||
cx: AsyncApp,
|
||||
) -> Task<Result<Self>> {
|
||||
use task::DebugRequestDisposition;
|
||||
|
||||
let request = match config.request.clone() {
|
||||
DebugRequestDisposition::UserConfigured(request) => request,
|
||||
DebugRequestDisposition::ReverseRequest(reverse_request_args) => {
|
||||
match reverse_request_args.request {
|
||||
dap::StartDebuggingRequestArgumentsRequest::Launch => {
|
||||
DebugRequestType::Launch(task::LaunchConfig {
|
||||
program: "".to_owned(),
|
||||
cwd: None,
|
||||
args: Default::default(),
|
||||
})
|
||||
}
|
||||
dap::StartDebuggingRequestArgumentsRequest::Attach => {
|
||||
DebugRequestType::Attach(task::AttachConfig {
|
||||
process_id: Some(0),
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
let callback = async move |session: &mut LocalMode, cx: AsyncApp| {
|
||||
session
|
||||
.client
|
||||
.on_request::<dap::requests::Initialize, _>(move |_, _| Ok(caps.clone()))
|
||||
.await;
|
||||
|
||||
let paths = cx
|
||||
.update(|cx| session.breakpoint_store.read(cx).breakpoint_paths())
|
||||
.expect("Breakpoint store should exist in all tests that start debuggers");
|
||||
|
||||
session
|
||||
.client
|
||||
.on_request::<dap::requests::SetBreakpoints, _>(move |_, args| {
|
||||
let p = Arc::from(Path::new(&args.source.path.unwrap()));
|
||||
if !paths.contains(&p) {
|
||||
panic!("Sent breakpoints for path without any")
|
||||
}
|
||||
|
||||
Ok(dap::SetBreakpointsResponse {
|
||||
breakpoints: Vec::default(),
|
||||
})
|
||||
})
|
||||
.await;
|
||||
|
||||
match request {
|
||||
dap::DebugRequestType::Launch(_) => {
|
||||
if fail {
|
||||
session
|
||||
.client
|
||||
.on_request::<dap::requests::Launch, _>(move |_, _| {
|
||||
Err(dap::ErrorResponse {
|
||||
error: Some(dap::Message {
|
||||
id: 1,
|
||||
format: "error".into(),
|
||||
variables: None,
|
||||
send_telemetry: None,
|
||||
show_user: None,
|
||||
url: None,
|
||||
url_label: None,
|
||||
}),
|
||||
})
|
||||
})
|
||||
.await;
|
||||
} else {
|
||||
session
|
||||
.client
|
||||
.on_request::<dap::requests::Launch, _>(move |_, _| Ok(()))
|
||||
.await;
|
||||
}
|
||||
}
|
||||
dap::DebugRequestType::Attach(attach_config) => {
|
||||
if fail {
|
||||
session
|
||||
.client
|
||||
.on_request::<dap::requests::Attach, _>(move |_, _| {
|
||||
Err(dap::ErrorResponse {
|
||||
error: Some(dap::Message {
|
||||
id: 1,
|
||||
format: "error".into(),
|
||||
variables: None,
|
||||
send_telemetry: None,
|
||||
show_user: None,
|
||||
url: None,
|
||||
url_label: None,
|
||||
}),
|
||||
})
|
||||
})
|
||||
.await;
|
||||
} else {
|
||||
session
|
||||
.client
|
||||
.on_request::<dap::requests::Attach, _>(move |_, args| {
|
||||
assert_eq!(
|
||||
json!({"request": "attach", "process_id": attach_config.process_id.unwrap()}),
|
||||
args.raw
|
||||
);
|
||||
|
||||
Ok(())
|
||||
})
|
||||
.await;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
session
|
||||
.client
|
||||
.on_request::<dap::requests::SetExceptionBreakpoints, _>(move |_, _| {
|
||||
Ok(dap::SetExceptionBreakpointsResponse { breakpoints: None })
|
||||
})
|
||||
.await;
|
||||
|
||||
session
|
||||
.client
|
||||
.on_request::<dap::requests::Disconnect, _>(move |_, _| Ok(()))
|
||||
.await;
|
||||
session.client.fake_event(Events::Initialized(None)).await;
|
||||
};
|
||||
Self::new_inner(
|
||||
DapRegistry::fake().into(),
|
||||
session_id,
|
||||
parent_session,
|
||||
breakpoint_store,
|
||||
config,
|
||||
delegate,
|
||||
messages_tx,
|
||||
callback,
|
||||
cx,
|
||||
)
|
||||
}
|
||||
fn new_inner(
|
||||
registry: Arc<DapRegistry>,
|
||||
session_id: SessionId,
|
||||
parent_session: Option<Entity<Session>>,
|
||||
breakpoint_store: Entity<BreakpointStore>,
|
||||
config: DebugAdapterConfig,
|
||||
delegate: DapAdapterDelegate,
|
||||
config: DebugTaskDefinition,
|
||||
binary: DebugAdapterBinary,
|
||||
messages_tx: futures::channel::mpsc::UnboundedSender<Message>,
|
||||
on_initialized: impl AsyncFnOnce(&mut LocalMode, AsyncApp) + 'static,
|
||||
cx: AsyncApp,
|
||||
) -> Task<Result<Self>> {
|
||||
cx.spawn(async move |cx| {
|
||||
let (adapter, binary) =
|
||||
Self::get_adapter_binary(®istry, &config, &delegate, cx).await?;
|
||||
|
||||
let message_handler = Box::new(move |message| {
|
||||
messages_tx.unbounded_send(message).ok();
|
||||
});
|
||||
@ -380,13 +223,12 @@ impl LocalMode {
|
||||
.flatten()
|
||||
{
|
||||
client
|
||||
.reconnect(session_id, binary, message_handler, cx.clone())
|
||||
.reconnect(session_id, binary.clone(), message_handler, cx.clone())
|
||||
.await?
|
||||
} else {
|
||||
DebugAdapterClient::start(
|
||||
session_id,
|
||||
adapter.name(),
|
||||
binary,
|
||||
binary.clone(),
|
||||
message_handler,
|
||||
cx.clone(),
|
||||
)
|
||||
@ -397,10 +239,10 @@ impl LocalMode {
|
||||
|
||||
let mut session = Self {
|
||||
client,
|
||||
adapter,
|
||||
breakpoint_store,
|
||||
tmp_breakpoint: None,
|
||||
config: config.clone(),
|
||||
definition: config,
|
||||
binary,
|
||||
};
|
||||
|
||||
on_initialized(&mut session, cx.clone()).await;
|
||||
@ -533,55 +375,12 @@ impl LocalMode {
|
||||
})
|
||||
}
|
||||
|
||||
async fn get_adapter_binary(
|
||||
registry: &Arc<DapRegistry>,
|
||||
config: &DebugAdapterConfig,
|
||||
delegate: &DapAdapterDelegate,
|
||||
cx: &mut AsyncApp,
|
||||
) -> Result<(Arc<dyn DebugAdapter>, DebugAdapterBinary)> {
|
||||
let adapter = registry
|
||||
.adapter(&config.adapter)
|
||||
.ok_or_else(|| anyhow!("Debug adapter with name `{}` was not found", config.adapter))?;
|
||||
|
||||
let binary = cx.update(|cx| {
|
||||
ProjectSettings::get_global(cx)
|
||||
.dap
|
||||
.get(&adapter.name())
|
||||
.and_then(|s| s.binary.as_ref().map(PathBuf::from))
|
||||
})?;
|
||||
|
||||
let binary = match adapter.get_binary(delegate, &config, binary, cx).await {
|
||||
Err(error) => {
|
||||
delegate.update_status(
|
||||
adapter.name(),
|
||||
DapStatus::Failed {
|
||||
error: error.to_string(),
|
||||
},
|
||||
);
|
||||
|
||||
return Err(error);
|
||||
}
|
||||
Ok(mut binary) => {
|
||||
delegate.update_status(adapter.name(), DapStatus::None);
|
||||
|
||||
let shell_env = delegate.shell_env().await;
|
||||
let mut envs = binary.envs.unwrap_or_default();
|
||||
envs.extend(shell_env);
|
||||
binary.envs = Some(envs);
|
||||
|
||||
binary
|
||||
}
|
||||
};
|
||||
|
||||
Ok((adapter, binary))
|
||||
}
|
||||
|
||||
pub fn label(&self) -> String {
|
||||
self.config.label.clone()
|
||||
self.definition.label.clone()
|
||||
}
|
||||
|
||||
fn request_initialization(&self, cx: &App) -> Task<Result<Capabilities>> {
|
||||
let adapter_id = self.adapter.name().to_string();
|
||||
let adapter_id = self.binary.adapter_name.to_string();
|
||||
|
||||
self.request(Initialize { adapter_id }, cx.background_executor().clone())
|
||||
}
|
||||
@ -592,36 +391,26 @@ impl LocalMode {
|
||||
initialized_rx: oneshot::Receiver<()>,
|
||||
cx: &App,
|
||||
) -> Task<Result<()>> {
|
||||
let (mut raw, is_launch) = match &self.config.request {
|
||||
task::DebugRequestDisposition::UserConfigured(_) => {
|
||||
let Ok(raw) = DebugTaskDefinition::try_from(self.config.clone()) else {
|
||||
debug_assert!(false, "This part of code should be unreachable in practice");
|
||||
return Task::ready(Err(anyhow!(
|
||||
"Expected debug config conversion to succeed"
|
||||
)));
|
||||
};
|
||||
let is_launch = matches!(raw.request, DebugRequestType::Launch(_));
|
||||
let raw = self.adapter.request_args(&raw);
|
||||
(raw, is_launch)
|
||||
}
|
||||
task::DebugRequestDisposition::ReverseRequest(start_debugging_request_arguments) => (
|
||||
start_debugging_request_arguments.configuration.clone(),
|
||||
matches!(
|
||||
start_debugging_request_arguments.request,
|
||||
dap::StartDebuggingRequestArgumentsRequest::Launch
|
||||
),
|
||||
),
|
||||
};
|
||||
let mut raw = self.binary.request_args.clone();
|
||||
|
||||
merge_json_value_into(
|
||||
self.config.initialize_args.clone().unwrap_or(json!({})),
|
||||
&mut raw,
|
||||
self.definition.initialize_args.clone().unwrap_or(json!({})),
|
||||
&mut raw.configuration,
|
||||
);
|
||||
// Of relevance: https://github.com/microsoft/vscode/issues/4902#issuecomment-368583522
|
||||
let launch = if is_launch {
|
||||
self.request(Launch { raw }, cx.background_executor().clone())
|
||||
} else {
|
||||
self.request(Attach { raw }, cx.background_executor().clone())
|
||||
let launch = match raw.request {
|
||||
dap::StartDebuggingRequestArgumentsRequest::Launch => self.request(
|
||||
Launch {
|
||||
raw: raw.configuration,
|
||||
},
|
||||
cx.background_executor().clone(),
|
||||
),
|
||||
dap::StartDebuggingRequestArgumentsRequest::Attach => self.request(
|
||||
Attach {
|
||||
raw: raw.configuration,
|
||||
},
|
||||
cx.background_executor().clone(),
|
||||
),
|
||||
};
|
||||
|
||||
let configuration_done_supported = ConfigurationDone::is_supported(capabilities);
|
||||
@ -656,12 +445,13 @@ impl LocalMode {
|
||||
})?
|
||||
.await
|
||||
.ok();
|
||||
if configuration_done_supported {
|
||||
let ret = if configuration_done_supported {
|
||||
this.request(ConfigurationDone {}, cx.background_executor().clone())
|
||||
} else {
|
||||
Task::ready(Ok(()))
|
||||
}
|
||||
.await
|
||||
.await;
|
||||
ret
|
||||
}
|
||||
});
|
||||
|
||||
@ -909,23 +699,21 @@ impl Session {
|
||||
breakpoint_store: Entity<BreakpointStore>,
|
||||
session_id: SessionId,
|
||||
parent_session: Option<Entity<Session>>,
|
||||
delegate: DapAdapterDelegate,
|
||||
config: DebugAdapterConfig,
|
||||
binary: DebugAdapterBinary,
|
||||
config: DebugTaskDefinition,
|
||||
start_debugging_requests_tx: futures::channel::mpsc::UnboundedSender<(SessionId, Message)>,
|
||||
initialized_tx: oneshot::Sender<()>,
|
||||
debug_adapters: Arc<DapRegistry>,
|
||||
cx: &mut App,
|
||||
) -> Task<Result<Entity<Self>>> {
|
||||
let (message_tx, message_rx) = futures::channel::mpsc::unbounded();
|
||||
|
||||
cx.spawn(async move |cx| {
|
||||
let mode = LocalMode::new(
|
||||
debug_adapters,
|
||||
session_id,
|
||||
parent_session.clone(),
|
||||
breakpoint_store.clone(),
|
||||
config.clone(),
|
||||
delegate,
|
||||
binary,
|
||||
message_tx,
|
||||
cx.clone(),
|
||||
)
|
||||
@ -946,50 +734,6 @@ impl Session {
|
||||
})
|
||||
}
|
||||
|
||||
#[cfg(any(test, feature = "test-support"))]
|
||||
pub(crate) fn fake(
|
||||
breakpoint_store: Entity<BreakpointStore>,
|
||||
session_id: SessionId,
|
||||
parent_session: Option<Entity<Session>>,
|
||||
delegate: DapAdapterDelegate,
|
||||
config: DebugAdapterConfig,
|
||||
start_debugging_requests_tx: futures::channel::mpsc::UnboundedSender<(SessionId, Message)>,
|
||||
initialized_tx: oneshot::Sender<()>,
|
||||
caps: Capabilities,
|
||||
fails: bool,
|
||||
cx: &mut App,
|
||||
) -> Task<Result<Entity<Session>>> {
|
||||
let (message_tx, message_rx) = futures::channel::mpsc::unbounded();
|
||||
|
||||
cx.spawn(async move |cx| {
|
||||
let mode = LocalMode::new_fake(
|
||||
session_id,
|
||||
parent_session.clone(),
|
||||
breakpoint_store.clone(),
|
||||
config.clone(),
|
||||
delegate,
|
||||
message_tx,
|
||||
caps,
|
||||
fails,
|
||||
cx.clone(),
|
||||
)
|
||||
.await?;
|
||||
|
||||
cx.new(|cx| {
|
||||
create_local_session(
|
||||
breakpoint_store,
|
||||
session_id,
|
||||
parent_session,
|
||||
start_debugging_requests_tx,
|
||||
initialized_tx,
|
||||
message_rx,
|
||||
mode,
|
||||
cx,
|
||||
)
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
pub(crate) fn remote(
|
||||
session_id: SessionId,
|
||||
client: AnyProtoClient,
|
||||
@ -1047,16 +791,23 @@ impl Session {
|
||||
&self.capabilities
|
||||
}
|
||||
|
||||
pub fn binary(&self) -> &DebugAdapterBinary {
|
||||
let Mode::Local(local_mode) = &self.mode else {
|
||||
panic!("Session is not local");
|
||||
};
|
||||
&local_mode.binary
|
||||
}
|
||||
|
||||
pub fn adapter_name(&self) -> SharedString {
|
||||
match &self.mode {
|
||||
Mode::Local(local_mode) => local_mode.adapter.name().into(),
|
||||
Mode::Local(local_mode) => local_mode.definition.adapter.clone().into(),
|
||||
Mode::Remote(remote_mode) => remote_mode._adapter_name.clone(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn configuration(&self) -> Option<DebugAdapterConfig> {
|
||||
pub fn configuration(&self) -> Option<DebugTaskDefinition> {
|
||||
if let Mode::Local(local_mode) = &self.mode {
|
||||
Some(local_mode.config.clone())
|
||||
Some(local_mode.definition.clone())
|
||||
} else {
|
||||
None
|
||||
}
|
||||
|
98
crates/project/src/debugger/test.rs
Normal file
98
crates/project/src/debugger/test.rs
Normal file
@ -0,0 +1,98 @@
|
||||
use std::{path::Path, sync::Arc};
|
||||
|
||||
use anyhow::Result;
|
||||
use dap::{DebugRequestType, client::DebugAdapterClient};
|
||||
use gpui::{App, AppContext, Entity, Subscription, Task};
|
||||
use task::DebugTaskDefinition;
|
||||
|
||||
use crate::Project;
|
||||
|
||||
use super::session::Session;
|
||||
|
||||
pub fn intercept_debug_sessions<T: Fn(&Arc<DebugAdapterClient>) + 'static>(
|
||||
cx: &mut gpui::TestAppContext,
|
||||
configure: T,
|
||||
) -> Subscription {
|
||||
cx.update(|cx| {
|
||||
cx.observe_new::<Session>(move |session, _, cx| {
|
||||
let client = session.adapter_client().unwrap();
|
||||
register_default_handlers(session, &client, cx);
|
||||
configure(&client);
|
||||
cx.background_spawn(async move {
|
||||
client
|
||||
.fake_event(dap::messages::Events::Initialized(Some(Default::default())))
|
||||
.await
|
||||
})
|
||||
.detach();
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
pub fn start_debug_session_with<T: Fn(&Arc<DebugAdapterClient>) + 'static>(
|
||||
project: &Entity<Project>,
|
||||
cx: &mut gpui::TestAppContext,
|
||||
config: DebugTaskDefinition,
|
||||
configure: T,
|
||||
) -> Task<Result<Entity<Session>>> {
|
||||
let subscription = intercept_debug_sessions(cx, configure);
|
||||
let task = project.update(cx, |project, cx| project.start_debug_session(config, cx));
|
||||
cx.spawn(async move |_| {
|
||||
let result = task.await;
|
||||
drop(subscription);
|
||||
result
|
||||
})
|
||||
}
|
||||
|
||||
pub fn start_debug_session<T: Fn(&Arc<DebugAdapterClient>) + 'static>(
|
||||
project: &Entity<Project>,
|
||||
cx: &mut gpui::TestAppContext,
|
||||
configure: T,
|
||||
) -> Task<Result<Entity<Session>>> {
|
||||
start_debug_session_with(
|
||||
project,
|
||||
cx,
|
||||
DebugTaskDefinition {
|
||||
adapter: "fake-adapter".to_string(),
|
||||
request: DebugRequestType::Launch(Default::default()),
|
||||
label: "test".to_string(),
|
||||
initialize_args: None,
|
||||
tcp_connection: None,
|
||||
locator: None,
|
||||
stop_on_entry: None,
|
||||
},
|
||||
configure,
|
||||
)
|
||||
}
|
||||
|
||||
fn register_default_handlers(session: &Session, client: &Arc<DebugAdapterClient>, cx: &mut App) {
|
||||
client.on_request::<dap::requests::Initialize, _>(move |_, _| Ok(Default::default()));
|
||||
let paths = session
|
||||
.as_local()
|
||||
.unwrap()
|
||||
.breakpoint_store
|
||||
.read(cx)
|
||||
.breakpoint_paths();
|
||||
|
||||
client.on_request::<dap::requests::SetBreakpoints, _>(move |_, args| {
|
||||
let p = Arc::from(Path::new(&args.source.path.unwrap()));
|
||||
if !paths.contains(&p) {
|
||||
panic!("Sent breakpoints for path without any")
|
||||
}
|
||||
|
||||
Ok(dap::SetBreakpointsResponse {
|
||||
breakpoints: Vec::default(),
|
||||
})
|
||||
});
|
||||
|
||||
client.on_request::<dap::requests::Launch, _>(move |_, _| Ok(()));
|
||||
|
||||
client.on_request::<dap::requests::SetExceptionBreakpoints, _>(move |_, _| {
|
||||
Ok(dap::SetExceptionBreakpointsResponse { breakpoints: None })
|
||||
});
|
||||
|
||||
client.on_request::<dap::requests::Disconnect, _>(move |_, _| Ok(()));
|
||||
|
||||
client.on_request::<dap::requests::Threads, _>(move |_, _| {
|
||||
Ok(dap::ThreadsResponse { threads: vec![] })
|
||||
});
|
||||
}
|
@ -25,6 +25,7 @@ mod environment;
|
||||
use buffer_diff::BufferDiff;
|
||||
pub use environment::{EnvironmentErrorMessage, ProjectEnvironmentEvent};
|
||||
use git_store::{Repository, RepositoryId};
|
||||
use task::DebugTaskDefinition;
|
||||
pub mod search_history;
|
||||
mod yarn;
|
||||
|
||||
@ -38,7 +39,7 @@ use client::{
|
||||
};
|
||||
use clock::ReplicaId;
|
||||
|
||||
use dap::{DapRegistry, DebugAdapterConfig, client::DebugAdapterClient};
|
||||
use dap::{DapRegistry, client::DebugAdapterClient};
|
||||
|
||||
use collections::{BTreeSet, HashMap, HashSet};
|
||||
use debounced_delay::DebouncedDelay;
|
||||
@ -106,7 +107,7 @@ use terminals::Terminals;
|
||||
use text::{Anchor, BufferId};
|
||||
use toolchain_store::EmptyToolchainStore;
|
||||
use util::{
|
||||
ResultExt as _, maybe,
|
||||
ResultExt as _,
|
||||
paths::{SanitizedPath, compare_paths},
|
||||
};
|
||||
use worktree::{CreatedEntry, Snapshot, Traversal};
|
||||
@ -870,11 +871,9 @@ impl Project {
|
||||
node.clone(),
|
||||
fs.clone(),
|
||||
languages.clone(),
|
||||
debug_adapters.clone(),
|
||||
environment.clone(),
|
||||
toolchain_store.read(cx).as_language_toolchain_store(),
|
||||
breakpoint_store.clone(),
|
||||
worktree_store.clone(),
|
||||
cx,
|
||||
)
|
||||
});
|
||||
@ -1458,64 +1457,46 @@ impl Project {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn queue_debug_session(&mut self, config: DebugAdapterConfig, cx: &mut Context<Self>) {
|
||||
if config.locator.is_none() {
|
||||
self.start_debug_session(config, cx).detach_and_log_err(cx);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn start_debug_session(
|
||||
&mut self,
|
||||
config: DebugAdapterConfig,
|
||||
config: DebugTaskDefinition,
|
||||
cx: &mut Context<Self>,
|
||||
) -> Task<Result<Entity<Session>>> {
|
||||
let worktree = maybe!({ self.worktrees(cx).next() });
|
||||
|
||||
let Some(worktree) = &worktree else {
|
||||
let Some(worktree) = self.worktrees(cx).next() else {
|
||||
return Task::ready(Err(anyhow!("Failed to find a worktree")));
|
||||
};
|
||||
|
||||
self.dap_store
|
||||
.update(cx, |dap_store, cx| {
|
||||
dap_store.new_session(config, worktree, None, cx)
|
||||
let Some(adapter) = self.debug_adapters.adapter(&config.adapter) else {
|
||||
return Task::ready(Err(anyhow!("Failed to find a debug adapter")));
|
||||
};
|
||||
|
||||
let user_installed_path = ProjectSettings::get_global(cx)
|
||||
.dap
|
||||
.get(&adapter.name())
|
||||
.and_then(|s| s.binary.as_ref().map(PathBuf::from));
|
||||
|
||||
let result = cx.spawn(async move |this, cx| {
|
||||
let delegate = this.update(cx, |project, cx| {
|
||||
project
|
||||
.dap_store
|
||||
.update(cx, |dap_store, cx| dap_store.delegate(&worktree, cx))
|
||||
})?;
|
||||
|
||||
let binary = adapter
|
||||
.get_binary(&delegate, &config, user_installed_path, cx)
|
||||
.await?;
|
||||
|
||||
let ret = this
|
||||
.update(cx, |project, cx| {
|
||||
project.dap_store.update(cx, |dap_store, cx| {
|
||||
dap_store.new_session(binary, config, None, cx)
|
||||
})
|
||||
})?
|
||||
.1
|
||||
}
|
||||
|
||||
#[cfg(any(test, feature = "test-support"))]
|
||||
pub fn fake_debug_session(
|
||||
&mut self,
|
||||
request: task::DebugRequestType,
|
||||
caps: Option<dap::Capabilities>,
|
||||
fails: bool,
|
||||
cx: &mut Context<Self>,
|
||||
) -> Task<Result<Entity<Session>>> {
|
||||
use dap::{Capabilities, FakeAdapter};
|
||||
use task::DebugRequestDisposition;
|
||||
|
||||
let worktree = maybe!({ self.worktrees(cx).next() });
|
||||
|
||||
let Some(worktree) = &worktree else {
|
||||
return Task::ready(Err(anyhow!("Failed to find a worktree")));
|
||||
};
|
||||
let config = DebugAdapterConfig {
|
||||
label: "test config".into(),
|
||||
adapter: FakeAdapter::ADAPTER_NAME.into(),
|
||||
request: DebugRequestDisposition::UserConfigured(request),
|
||||
initialize_args: None,
|
||||
tcp_connection: None,
|
||||
locator: None,
|
||||
stop_on_entry: None,
|
||||
};
|
||||
let caps = caps.unwrap_or(Capabilities {
|
||||
supports_step_back: Some(false),
|
||||
..Default::default()
|
||||
.await;
|
||||
ret
|
||||
});
|
||||
self.dap_store
|
||||
.update(cx, |dap_store, cx| {
|
||||
dap_store.new_fake_session(config, worktree, None, caps, fails, cx)
|
||||
})
|
||||
.1
|
||||
result
|
||||
}
|
||||
|
||||
#[cfg(any(test, feature = "test-support"))]
|
||||
|
@ -39,7 +39,7 @@ use std::{env, mem, num::NonZeroU32, ops::Range, str::FromStr, sync::OnceLock, t
|
||||
use task::{ResolvedTask, TaskContext};
|
||||
use unindent::Unindent as _;
|
||||
use util::{
|
||||
TryFutureExt as _, assert_set_eq, path,
|
||||
TryFutureExt as _, assert_set_eq, maybe, path,
|
||||
paths::PathMatcher,
|
||||
separator,
|
||||
test::{TempTree, marked_text_offsets},
|
||||
|
@ -72,7 +72,7 @@ impl HeadlessProject {
|
||||
http_client,
|
||||
node_runtime,
|
||||
languages,
|
||||
debug_adapters,
|
||||
debug_adapters: _debug_adapters,
|
||||
extension_host_proxy: proxy,
|
||||
}: HeadlessAppState,
|
||||
cx: &mut Context<Self>,
|
||||
@ -112,11 +112,9 @@ impl HeadlessProject {
|
||||
node_runtime.clone(),
|
||||
fs.clone(),
|
||||
languages.clone(),
|
||||
debug_adapters.clone(),
|
||||
environment.clone(),
|
||||
toolchain_store.read(cx).as_language_toolchain_store(),
|
||||
breakpoint_store.clone(),
|
||||
worktree_store.clone(),
|
||||
cx,
|
||||
)
|
||||
});
|
||||
|
@ -104,7 +104,7 @@ impl ResolvedTask {
|
||||
}
|
||||
|
||||
/// Get the configuration for the debug adapter that should be used for this task.
|
||||
pub fn resolved_debug_adapter_config(&self) -> Option<DebugAdapterConfig> {
|
||||
pub fn resolved_debug_adapter_config(&self) -> Option<DebugTaskDefinition> {
|
||||
match self.original_task.task_type.clone() {
|
||||
TaskType::Debug(debug_args) if self.resolved.is_some() => {
|
||||
let resolved = self
|
||||
@ -127,10 +127,10 @@ impl ResolvedTask {
|
||||
})
|
||||
.collect();
|
||||
|
||||
Some(DebugAdapterConfig {
|
||||
Some(DebugTaskDefinition {
|
||||
label: resolved.label.clone(),
|
||||
adapter: debug_args.adapter.clone(),
|
||||
request: DebugRequestDisposition::UserConfigured(match debug_args.request {
|
||||
request: match debug_args.request {
|
||||
crate::task_template::DebugArgsRequest::Launch => {
|
||||
DebugRequestType::Launch(LaunchConfig {
|
||||
program: resolved.command.clone(),
|
||||
@ -141,7 +141,7 @@ impl ResolvedTask {
|
||||
crate::task_template::DebugArgsRequest::Attach(attach_config) => {
|
||||
DebugRequestType::Attach(attach_config)
|
||||
}
|
||||
}),
|
||||
},
|
||||
initialize_args: debug_args.initialize_args,
|
||||
tcp_connection: debug_args.tcp_connection,
|
||||
locator: debug_args.locator.clone(),
|
||||
|
@ -361,9 +361,8 @@ impl PickerDelegate for TasksModalDelegate {
|
||||
|
||||
match task.task_type() {
|
||||
TaskType::Debug(config) if config.locator.is_none() => {
|
||||
let Some(config): Option<DebugTaskDefinition> = task
|
||||
.resolved_debug_adapter_config()
|
||||
.and_then(|config| config.try_into().ok())
|
||||
let Some(config): Option<DebugTaskDefinition> =
|
||||
task.resolved_debug_adapter_config()
|
||||
else {
|
||||
return;
|
||||
};
|
||||
@ -382,7 +381,7 @@ impl PickerDelegate for TasksModalDelegate {
|
||||
.update(cx, |workspace, cx| {
|
||||
workspace.project().update(cx, |project, cx| {
|
||||
project
|
||||
.start_debug_session(config.into(), cx)
|
||||
.start_debug_session(config, cx)
|
||||
.detach_and_log_err(cx);
|
||||
});
|
||||
})
|
||||
|
@ -96,7 +96,7 @@ use std::{
|
||||
sync::{Arc, LazyLock, Weak, atomic::AtomicUsize},
|
||||
time::Duration,
|
||||
};
|
||||
use task::{DebugAdapterConfig, SpawnInTerminal, TaskId};
|
||||
use task::{DebugTaskDefinition, SpawnInTerminal, TaskId};
|
||||
use theme::{ActiveTheme, SystemAppearance, ThemeSettings};
|
||||
pub use toolbar::{Toolbar, ToolbarItemEvent, ToolbarItemLocation, ToolbarItemView};
|
||||
pub use ui;
|
||||
@ -858,7 +858,7 @@ pub struct Workspace {
|
||||
serialized_ssh_project: Option<SerializedSshProject>,
|
||||
_items_serializer: Task<Result<()>>,
|
||||
session_id: Option<String>,
|
||||
debug_task_queue: HashMap<task::TaskId, DebugAdapterConfig>,
|
||||
debug_task_queue: HashMap<task::TaskId, DebugTaskDefinition>,
|
||||
}
|
||||
|
||||
impl EventEmitter<Event> for Workspace {}
|
||||
|
Loading…
Reference in New Issue
Block a user