diff --git a/crates/dap_adapters/src/gdb.rs b/crates/dap_adapters/src/gdb.rs index 12489247c53322612ea7d7cd33fedce51bb68b26..46488cd550076ff411cc69951159c330fa60bf24 100644 --- a/crates/dap_adapters/src/gdb.rs +++ b/crates/dap_adapters/src/gdb.rs @@ -1,10 +1,9 @@ -use std::ffi::OsStr; - use anyhow::{Context as _, Result, bail}; use async_trait::async_trait; use collections::HashMap; use dap::{StartDebuggingRequestArguments, adapters::DebugTaskDefinition}; use gpui::AsyncApp; +use std::ffi::OsStr; use task::{DebugScenario, ZedDebugConfig}; use crate::*; @@ -16,6 +15,14 @@ impl GdbDebugAdapter { const ADAPTER_NAME: &'static str = "GDB"; } +/// Ensures that "-i=dap" is present in the GDB argument list. +fn ensure_dap_interface(mut gdb_args: Vec) -> Vec { + if !gdb_args.iter().any(|arg| arg.trim() == "-i=dap") { + gdb_args.insert(0, "-i=dap".to_string()); + } + gdb_args +} + #[async_trait(?Send)] impl DebugAdapter for GdbDebugAdapter { fn name(&self) -> DebugAdapterName { @@ -99,6 +106,18 @@ impl DebugAdapter for GdbDebugAdapter { "type": "string", "description": "Working directory for the debugged program. GDB will change its working directory to this directory." }, + "gdb_path": { + "type": "string", + "description": "Alternative path to the GDB executable, if the one in standard path is not desirable" + }, + "gdb_args": { + "type": "array", + "items": { + "type":"string" + }, + "description": "additional arguments given to GDB at startup, not the program debugged", + "default": [] + }, "env": { "type": "object", "description": "Environment variables for the debugged program. Each key is the name of an environment variable; each value is the value of that variable." @@ -164,21 +183,49 @@ impl DebugAdapter for GdbDebugAdapter { user_env: Option>, _: &mut AsyncApp, ) -> Result { - 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")) - .await - .and_then(|p| p.to_str().map(|s| s.to_string())) - .context("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"); - } + // Try to get gdb_path from config + let gdb_path_from_config = config + .config + .get("gdb_path") + .and_then(|v| v.as_str()) + .map(|s| s.to_string()); - let gdb_path = user_setting_path.unwrap_or(gdb_path?); + let gdb_path = if let Some(path) = gdb_path_from_config { + path + } else { + // Original logic: use user_installed_path or search in system path + 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_result = delegate + .which(OsStr::new("gdb")) + .await + .and_then(|p| p.to_str().map(|s| s.to_string())) + .context("Could not find gdb in path"); + + if gdb_path_result.is_err() && user_setting_path.is_none() { + bail!("Could not find gdb path or it's not installed"); + } + + user_setting_path.unwrap_or_else(|| gdb_path_result.unwrap()) + }; + + // Arguments: use gdb_args from config if present, else user_args, else default + let gdb_args = { + let args = config + .config + .get("gdb_args") + .and_then(|v| v.as_array()) + .map(|arr| { + arr.iter() + .filter_map(|v| v.as_str().map(|s| s.to_string())) + .collect::>() + }) + .or(user_args.clone()) + .unwrap_or_else(|| vec!["-i=dap".into()]); + ensure_dap_interface(args) + }; let mut configuration = config.config.clone(); if let Some(configuration) = configuration.as_object_mut() { @@ -187,10 +234,26 @@ impl DebugAdapter for GdbDebugAdapter { .or_insert_with(|| delegate.worktree_root_path().to_string_lossy().into()); } + let mut base_env = delegate.shell_env().await; + base_env.extend(user_env.unwrap_or_default()); + + let config_env: HashMap = config + .config + .get("env") + .and_then(|v| v.as_object()) + .map(|obj| { + obj.iter() + .filter_map(|(k, v)| v.as_str().map(|s| (k.clone(), s.to_string()))) + .collect::>() + }) + .unwrap_or_else(HashMap::default); + + base_env.extend(config_env); + Ok(DebugAdapterBinary { command: Some(gdb_path), - arguments: user_args.unwrap_or_else(|| vec!["-i=dap".into()]), - envs: user_env.unwrap_or_default(), + arguments: gdb_args, + envs: base_env, cwd: Some(delegate.worktree_root_path().to_path_buf()), connection: None, request_args: StartDebuggingRequestArguments {