diff --git a/.zed/debug.json b/.zed/debug.json index d799c13a8e1855..b7646ee3bd7d28 100644 --- a/.zed/debug.json +++ b/.zed/debug.json @@ -5,5 +5,15 @@ "program": "$ZED_WORKTREE_ROOT/target/debug/zed", "request": "launch", "cwd": "$ZED_WORKTREE_ROOT" + }, + { + "label": "Debug Zed with GDB", + "adapter": "gdb", + "program": "$ZED_WORKTREE_ROOT/target/debug/zed", + "request": "launch", + "cwd": "$ZED_WORKTREE_ROOT", + "initialize_args": { + "stopAtBeginningOfMainSubprogram": true + } } ] diff --git a/crates/dap_adapters/src/dap_adapters.rs b/crates/dap_adapters/src/dap_adapters.rs index d905ebd0a1c8cf..b47e9ed24e31ea 100644 --- a/crates/dap_adapters/src/dap_adapters.rs +++ b/crates/dap_adapters/src/dap_adapters.rs @@ -1,4 +1,5 @@ mod custom; +mod gdb; mod go; mod javascript; mod lldb; @@ -12,6 +13,7 @@ use dap::adapters::{ self, AdapterVersion, DapDelegate, DebugAdapter, DebugAdapterBinary, DebugAdapterName, GithubRepo, }; +use gdb::GdbDebugAdapter; use go::GoDebugAdapter; use javascript::JsDebugAdapter; use lldb::LldbDebugAdapter; @@ -33,5 +35,6 @@ pub async fn build_adapter(kind: &DebugAdapterKind) -> Result Ok(Box::new(LldbDebugAdapter::new())), DebugAdapterKind::Go(host) => Ok(Box::new(GoDebugAdapter::new(host).await?)), + DebugAdapterKind::Gdb => Ok(Box::new(GdbDebugAdapter::new())), } } diff --git a/crates/dap_adapters/src/gdb.rs b/crates/dap_adapters/src/gdb.rs new file mode 100644 index 00000000000000..d87c1b0d927f3f --- /dev/null +++ b/crates/dap_adapters/src/gdb.rs @@ -0,0 +1,85 @@ +use std::ffi::OsStr; + +use anyhow::Result; +use async_trait::async_trait; +use dap::transport::{StdioTransport, Transport}; +use task::DebugAdapterConfig; + +use crate::*; + +pub(crate) struct GdbDebugAdapter {} + +impl GdbDebugAdapter { + const ADAPTER_NAME: &'static str = "gdb"; + + pub(crate) fn new() -> Self { + GdbDebugAdapter {} + } +} + +#[async_trait(?Send)] +impl DebugAdapter for GdbDebugAdapter { + fn name(&self) -> DebugAdapterName { + DebugAdapterName(Self::ADAPTER_NAME.into()) + } + + fn transport(&self) -> Box { + Box::new(StdioTransport::new()) + } + + async fn get_binary( + &self, + delegate: &dyn DapDelegate, + config: &DebugAdapterConfig, + user_installed_path: Option, + ) -> Result { + let user_setting_path = user_installed_path + .filter(|p| p.exists()) + .and_then(|p| p.to_str().map(|s| s.to_string())); + + /* GDB implements DAP natively so just need to */ + 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: config.cwd.clone(), + version: "1".into(), + }) + } + + 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 { + unimplemented!("Fetch latest GDB version not implemented (yet)") + } + + async fn get_installed_binary( + &self, + _: &dyn DapDelegate, + _: &DebugAdapterConfig, + _: Option, + ) -> Result { + unimplemented!("GDB cannot be installed by Zed (yet)") + } + + fn request_args(&self, config: &DebugAdapterConfig) -> Value { + json!({"program": config.program, "cwd": config.cwd}) + } +} diff --git a/crates/task/src/debug_format.rs b/crates/task/src/debug_format.rs index c039a987feccbf..621bd2a9482b4b 100644 --- a/crates/task/src/debug_format.rs +++ b/crates/task/src/debug_format.rs @@ -73,6 +73,8 @@ pub enum DebugAdapterKind { Go(TCPHost), /// Use lldb Lldb, + /// Use GDB's built-in DAP support + Gdb, } impl DebugAdapterKind { @@ -84,6 +86,7 @@ impl DebugAdapterKind { Self::Php(_) => "PHP", Self::Javascript(_) => "JavaScript", Self::Lldb => "LLDB", + Self::Gdb => "GDB", Self::Go(_) => "Go", } }