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