1use std::ffi::OsStr;
2
3use anyhow::{Result, bail};
4use async_trait::async_trait;
5use gpui::AsyncApp;
6use task::{DebugAdapterConfig, DebugRequestType, DebugTaskDefinition};
7
8use crate::*;
9
10#[derive(Default)]
11pub(crate) struct GdbDebugAdapter;
12
13impl GdbDebugAdapter {
14 const ADAPTER_NAME: &'static str = "GDB";
15}
16
17#[async_trait(?Send)]
18impl DebugAdapter for GdbDebugAdapter {
19 fn name(&self) -> DebugAdapterName {
20 DebugAdapterName(Self::ADAPTER_NAME.into())
21 }
22
23 async fn get_binary(
24 &self,
25 delegate: &dyn DapDelegate,
26 _: &DebugAdapterConfig,
27 user_installed_path: Option<std::path::PathBuf>,
28 _: &mut AsyncApp,
29 ) -> Result<DebugAdapterBinary> {
30 let user_setting_path = user_installed_path
31 .filter(|p| p.exists())
32 .and_then(|p| p.to_str().map(|s| s.to_string()));
33
34 let gdb_path = delegate
35 .which(OsStr::new("gdb"))
36 .and_then(|p| p.to_str().map(|s| s.to_string()))
37 .ok_or(anyhow!("Could not find gdb in path"));
38
39 if gdb_path.is_err() && user_setting_path.is_none() {
40 bail!("Could not find gdb path or it's not installed");
41 }
42
43 let gdb_path = user_setting_path.unwrap_or(gdb_path?);
44
45 Ok(DebugAdapterBinary {
46 command: gdb_path,
47 arguments: Some(vec!["-i=dap".into()]),
48 envs: None,
49 cwd: None,
50 connection: None,
51 })
52 }
53
54 async fn install_binary(
55 &self,
56 _version: AdapterVersion,
57 _delegate: &dyn DapDelegate,
58 ) -> Result<()> {
59 unimplemented!("GDB debug adapter cannot be installed by Zed (yet)")
60 }
61
62 async fn fetch_latest_adapter_version(&self, _: &dyn DapDelegate) -> Result<AdapterVersion> {
63 unimplemented!("Fetch latest GDB version not implemented (yet)")
64 }
65
66 async fn get_installed_binary(
67 &self,
68 _: &dyn DapDelegate,
69 _: &DebugAdapterConfig,
70 _: Option<std::path::PathBuf>,
71 _: &mut AsyncApp,
72 ) -> Result<DebugAdapterBinary> {
73 unimplemented!("GDB cannot be installed by Zed (yet)")
74 }
75
76 fn request_args(&self, config: &DebugTaskDefinition) -> Value {
77 let mut args = json!({
78 "request": match config.request {
79 DebugRequestType::Launch(_) => "launch",
80 DebugRequestType::Attach(_) => "attach",
81 },
82 });
83
84 let map = args.as_object_mut().unwrap();
85 match &config.request {
86 DebugRequestType::Attach(attach) => {
87 map.insert("pid".into(), attach.process_id.into());
88 }
89
90 DebugRequestType::Launch(launch) => {
91 map.insert("program".into(), launch.program.clone().into());
92
93 if !launch.args.is_empty() {
94 map.insert("args".into(), launch.args.clone().into());
95 }
96
97 if let Some(stop_on_entry) = config.stop_on_entry {
98 map.insert(
99 "stopAtBeginningOfMainSubprogram".into(),
100 stop_on_entry.into(),
101 );
102 }
103 if let Some(cwd) = launch.cwd.as_ref() {
104 map.insert("cwd".into(), cwd.to_string_lossy().into_owned().into());
105 }
106 }
107 }
108 args
109 }
110}