use std::{path::PathBuf, sync::OnceLock}; use anyhow::{Result, bail};use async_trait::async_trait;use dap::adapters::latest_github_release;use gpui::AsyncApp;use task::{DebugRequestType, DebugTaskDefinition}; use crate::*; #[derive(Default)]pub(crate) struct CodeLldbDebugAdapter { last_known_version: OnceLock<String>,} 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)]impl DebugAdapter for CodeLldbDebugAdapter { fn name(&self) -> DebugAdapterName { DebugAdapterName(Self::ADAPTER_NAME.into()) } async fn install_binary( &self, version: AdapterVersion, delegate: &dyn DapDelegate, ) -> Result<()> { adapters::download_adapter_from_github( self.name(), version, adapters::DownloadedFileType::Vsix, delegate, ) .await?; Ok(()) } async fn fetch_latest_adapter_version( &self, delegate: &dyn DapDelegate, ) -> Result<AdapterVersion> { let release = latest_github_release("vadimcn/codelldb", true, false, delegate.http_client()).await?; let arch = match std::env::consts::ARCH { "aarch64" => "arm64", "x86_64" => "x64", _ => { return Err(anyhow!( "unsupported architecture {}", std::env::consts::ARCH )); } }; let platform = match std::env::consts::OS { "macos" => "darwin", "linux" => "linux", "windows" => "win32", _ => { return Err(anyhow!( "unsupported operating system {}", std::env::consts::OS )); } }; let asset_name = format!("codelldb-{platform}-{arch}.vsix"); let _ = self.last_known_version.set(release.tag_name.clone()); let ret = AdapterVersion { tag_name: release.tag_name, url: release .assets .iter() .find(|asset| asset.name == asset_name) .ok_or_else(|| anyhow!("no asset found matching {:?}", asset_name))? .browser_download_url .clone(), }; Ok(ret) } async fn get_installed_binary( &self, _: &dyn DapDelegate, config: &DebugTaskDefinition, _: Option<PathBuf>, _: &mut AsyncApp, ) -> Result<DebugAdapterBinary> { let Some(version) = self.last_known_version.get() else { bail!("Could not determine latest CodeLLDB version"); }; let adapter_path = paths::debug_adapters_dir().join(&Self::ADAPTER_NAME); let version_path = adapter_path.join(format!("{}_{}", Self::ADAPTER_NAME, version)); let adapter_dir = version_path.join("extension").join("adapter"); let command = adapter_dir.join("codelldb"); let command = command .to_str() .map(ToOwned::to_owned) .ok_or_else(|| anyhow!("Adapter path is expected to be valid UTF-8"))?; Ok(DebugAdapterBinary { command, cwd: Some(adapter_dir), arguments: Some(vec![ "--settings".into(), json!({"sourceLanguages": ["cpp", "rust"]}) .to_string() .into(), ]), request_args: self.request_args(config), adapter_name: "test".into(), envs: None, connection: None, }) }}
use std::{path::PathBuf, sync::OnceLock};
use anyhow::{Result, bail};
use async_trait::async_trait;
use dap::adapters::latest_github_release;
use gpui::AsyncApp;
use task::{DebugRequestType, DebugTaskDefinition};
use crate::*;
#[derive(Default)]
pub(crate) struct CodeLldbDebugAdapter {
last_known_version: OnceLock<String>,
}
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)]
impl DebugAdapter for CodeLldbDebugAdapter {
fn name(&self) -> DebugAdapterName {
DebugAdapterName(Self::ADAPTER_NAME.into())
}
async fn install_binary(
&self,
version: AdapterVersion,
delegate: &dyn DapDelegate,
) -> Result<()> {
adapters::download_adapter_from_github(
self.name(),
version,
adapters::DownloadedFileType::Vsix,
delegate,
)
.await?;
Ok(())
}
async fn fetch_latest_adapter_version(
&self,
delegate: &dyn DapDelegate,
) -> Result<AdapterVersion> {
let release =
latest_github_release("vadimcn/codelldb", true, false, delegate.http_client()).await?;
let arch = match std::env::consts::ARCH {
"aarch64" => "arm64",
"x86_64" => "x64",
_ => {
return Err(anyhow!(
"unsupported architecture {}",
std::env::consts::ARCH
));
}
};
let platform = match std::env::consts::OS {
"macos" => "darwin",
"linux" => "linux",
"windows" => "win32",
_ => {
return Err(anyhow!(
"unsupported operating system {}",
std::env::consts::OS
));
}
};
let asset_name = format!("codelldb-{platform}-{arch}.vsix");
let _ = self.last_known_version.set(release.tag_name.clone());
let ret = AdapterVersion {
tag_name: release.tag_name,
url: release
.assets
.iter()
.find(|asset| asset.name == asset_name)
.ok_or_else(|| anyhow!("no asset found matching {:?}", asset_name))?
.browser_download_url
.clone(),
};
Ok(ret)
}
async fn get_installed_binary(
&self,
_: &dyn DapDelegate,
config: &DebugTaskDefinition,
_: Option<PathBuf>,
_: &mut AsyncApp,
) -> Result<DebugAdapterBinary> {
let Some(version) = self.last_known_version.get() else {
bail!("Could not determine latest CodeLLDB version");
};
let adapter_path = paths::debug_adapters_dir().join(&Self::ADAPTER_NAME);
let version_path = adapter_path.join(format!("{}_{}", Self::ADAPTER_NAME, version));
let adapter_dir = version_path.join("extension").join("adapter");
let command = adapter_dir.join("codelldb");
let command = command
.to_str()
.map(ToOwned::to_owned)
.ok_or_else(|| anyhow!("Adapter path is expected to be valid UTF-8"))?;
Ok(DebugAdapterBinary {
command,
cwd: Some(adapter_dir),
arguments: Some(vec![
"--settings".into(),
json!({"sourceLanguages": ["cpp", "rust"]})
.to_string()
.into(),
]),
request_args: self.request_args(config),
adapter_name: "test".into(),
envs: None,
connection: None,
})
}
}