@@ -1,22 +1,87 @@
use anyhow::{Context as _, anyhow, bail};
use dap::{
StartDebuggingRequestArguments, StartDebuggingRequestArgumentsRequest,
- adapters::DebugTaskDefinition,
+ adapters::{
+ DebugTaskDefinition, DownloadedFileType, download_adapter_from_github,
+ latest_github_release,
+ },
};
use gpui::{AsyncApp, SharedString};
use language::LanguageName;
-use std::{collections::HashMap, ffi::OsStr, path::PathBuf};
+use std::{collections::HashMap, env::consts, ffi::OsStr, path::PathBuf, sync::OnceLock};
use util;
use crate::*;
#[derive(Default, Debug)]
-pub(crate) struct GoDebugAdapter;
+pub(crate) struct GoDebugAdapter {
+ shim_path: OnceLock<PathBuf>,
+}
impl GoDebugAdapter {
const ADAPTER_NAME: &'static str = "Delve";
- const DEFAULT_TIMEOUT_MS: u64 = 60000;
+ async fn fetch_latest_adapter_version(
+ delegate: &Arc<dyn DapDelegate>,
+ ) -> Result<AdapterVersion> {
+ let release = latest_github_release(
+ &"zed-industries/delve-shim-dap",
+ true,
+ false,
+ delegate.http_client(),
+ )
+ .await?;
+
+ let os = match consts::OS {
+ "macos" => "apple-darwin",
+ "linux" => "unknown-linux-gnu",
+ "windows" => "pc-windows-msvc",
+ other => bail!("Running on unsupported os: {other}"),
+ };
+ let suffix = if consts::OS == "windows" {
+ ".zip"
+ } else {
+ ".tar.gz"
+ };
+ let asset_name = format!("delve-shim-dap-{}-{os}{suffix}", consts::ARCH);
+ let asset = release
+ .assets
+ .iter()
+ .find(|asset| asset.name == asset_name)
+ .with_context(|| format!("no asset found matching `{asset_name:?}`"))?;
+
+ Ok(AdapterVersion {
+ tag_name: release.tag_name,
+ url: asset.browser_download_url.clone(),
+ })
+ }
+ async fn install_shim(&self, delegate: &Arc<dyn DapDelegate>) -> anyhow::Result<PathBuf> {
+ if let Some(path) = self.shim_path.get().cloned() {
+ return Ok(path);
+ }
+
+ let asset = Self::fetch_latest_adapter_version(delegate).await?;
+ let ty = if consts::OS == "windows" {
+ DownloadedFileType::Zip
+ } else {
+ DownloadedFileType::GzipTar
+ };
+ download_adapter_from_github(
+ "delve-shim-dap".into(),
+ asset.clone(),
+ ty,
+ delegate.as_ref(),
+ )
+ .await?;
+
+ let path = paths::debug_adapters_dir()
+ .join("delve-shim-dap")
+ .join(format!("delve-shim-dap{}", asset.tag_name))
+ .join("delve-shim-dap");
+ self.shim_path.set(path.clone()).ok();
+
+ Ok(path)
+ }
}
#[async_trait(?Send)]
@@ -384,16 +449,10 @@ impl DebugAdapter for GoDebugAdapter {
adapter_path.join("dlv").to_string_lossy().to_string()
};
+ let minidelve_path = self.install_shim(delegate).await?;
+ let tcp_connection = task_definition.tcp_connection.clone().unwrap_or_default();
- let mut tcp_connection = task_definition.tcp_connection.clone().unwrap_or_default();
-
- if tcp_connection.timeout.is_none()
- || tcp_connection.timeout.unwrap_or(0) < Self::DEFAULT_TIMEOUT_MS
- {
- tcp_connection.timeout = Some(Self::DEFAULT_TIMEOUT_MS);
- }
-
- let (host, port, timeout) = crate::configure_tcp_connection(tcp_connection).await?;
+ let (host, port, _) = crate::configure_tcp_connection(tcp_connection).await?;
let cwd = task_definition
.config
@@ -404,6 +463,7 @@ impl DebugAdapter for GoDebugAdapter {
let arguments = if cfg!(windows) {
vec![
+ delve_path,
"dap".into(),
"--listen".into(),
format!("{}:{}", host, port),
@@ -411,6 +471,7 @@ impl DebugAdapter for GoDebugAdapter {
]
} else {
vec![
+ delve_path,
"dap".into(),
"--listen".into(),
format!("{}:{}", host, port),
@@ -418,15 +479,11 @@ impl DebugAdapter for GoDebugAdapter {
};
Ok(DebugAdapterBinary {
- command: delve_path,
+ command: minidelve_path.to_string_lossy().into_owned(),
arguments,
cwd: Some(cwd),
envs: HashMap::default(),
- connection: Some(adapters::TcpArguments {
- host,
- port,
- timeout,
- }),
+ connection: None,
request_args: StartDebuggingRequestArguments {
configuration: task_definition.config.clone(),
request: self.validate_config(&task_definition.config)?,