1use std::{
2 path::{Path, PathBuf},
3 str::FromStr,
4 sync::Arc,
5};
6
7use anyhow::{Context, Result};
8use async_trait::async_trait;
9use dap::adapters::{
10 DapDelegate, DebugAdapter, DebugAdapterBinary, DebugAdapterName, DebugTaskDefinition,
11};
12use extension::{Extension, WorktreeDelegate};
13use gpui::AsyncApp;
14use task::{DebugScenario, ZedDebugConfig};
15
16pub(crate) struct ExtensionDapAdapter {
17 extension: Arc<dyn Extension>,
18 debug_adapter_name: Arc<str>,
19 schema: serde_json::Value,
20}
21
22impl ExtensionDapAdapter {
23 pub(crate) fn new(
24 extension: Arc<dyn extension::Extension>,
25 debug_adapter_name: Arc<str>,
26 ) -> Result<Self> {
27 let schema = std::fs::read_to_string(extension.path_from_extension(
28 &Path::new("debug_adapter_schemas").join(debug_adapter_name.as_ref()),
29 ))
30 .with_context(|| format!("Failed to read debug adapter schema for {debug_adapter_name}"))?;
31 let schema = serde_json::Value::from_str(&schema).with_context(|| {
32 format!("Debug adapter schema for {debug_adapter_name} is not a valid JSON")
33 })?;
34 Ok(Self {
35 extension,
36 debug_adapter_name,
37 schema,
38 })
39 }
40}
41
42/// An adapter that allows an [`dap::adapters::DapDelegate`] to be used as a [`WorktreeDelegate`].
43struct WorktreeDelegateAdapter(pub Arc<dyn DapDelegate>);
44
45#[async_trait]
46impl WorktreeDelegate for WorktreeDelegateAdapter {
47 fn id(&self) -> u64 {
48 self.0.worktree_id().to_proto()
49 }
50
51 fn root_path(&self) -> String {
52 self.0.worktree_root_path().to_string_lossy().to_string()
53 }
54
55 async fn read_text_file(&self, path: PathBuf) -> Result<String> {
56 self.0.read_text_file(path).await
57 }
58
59 async fn which(&self, binary_name: String) -> Option<String> {
60 self.0
61 .which(binary_name.as_ref())
62 .await
63 .map(|path| path.to_string_lossy().to_string())
64 }
65
66 async fn shell_env(&self) -> Vec<(String, String)> {
67 self.0.shell_env().await.into_iter().collect()
68 }
69}
70
71#[async_trait(?Send)]
72impl DebugAdapter for ExtensionDapAdapter {
73 fn name(&self) -> DebugAdapterName {
74 self.debug_adapter_name.as_ref().into()
75 }
76
77 fn dap_schema(&self) -> serde_json::Value {
78 self.schema.clone()
79 }
80
81 async fn get_binary(
82 &self,
83 delegate: &Arc<dyn DapDelegate>,
84 config: &DebugTaskDefinition,
85 user_installed_path: Option<PathBuf>,
86 _cx: &mut AsyncApp,
87 ) -> Result<DebugAdapterBinary> {
88 self.extension
89 .get_dap_binary(
90 self.debug_adapter_name.clone(),
91 config.clone(),
92 user_installed_path,
93 Arc::new(WorktreeDelegateAdapter(delegate.clone())),
94 )
95 .await
96 }
97
98 fn config_from_zed_format(&self, _zed_scenario: ZedDebugConfig) -> Result<DebugScenario> {
99 Err(anyhow::anyhow!("DAP extensions are not implemented yet"))
100 }
101}