1use std::{path::PathBuf, sync::Arc};
2
3use anyhow::Result;
4use async_trait::async_trait;
5use dap::adapters::{
6 DapDelegate, DebugAdapter, DebugAdapterBinary, DebugAdapterName, DebugTaskDefinition,
7};
8use extension::{Extension, WorktreeDelegate};
9use gpui::AsyncApp;
10
11pub(crate) struct ExtensionDapAdapter {
12 extension: Arc<dyn Extension>,
13 debug_adapter_name: Arc<str>,
14}
15
16impl ExtensionDapAdapter {
17 pub(crate) fn new(
18 extension: Arc<dyn extension::Extension>,
19 debug_adapter_name: Arc<str>,
20 ) -> Self {
21 Self {
22 extension,
23 debug_adapter_name,
24 }
25 }
26}
27
28/// An adapter that allows an [`dap::adapters::DapDelegate`] to be used as a [`WorktreeDelegate`].
29struct WorktreeDelegateAdapter(pub Arc<dyn DapDelegate>);
30
31#[async_trait]
32impl WorktreeDelegate for WorktreeDelegateAdapter {
33 fn id(&self) -> u64 {
34 self.0.worktree_id().to_proto()
35 }
36
37 fn root_path(&self) -> String {
38 self.0.worktree_root_path().to_string_lossy().to_string()
39 }
40
41 async fn read_text_file(&self, path: PathBuf) -> Result<String> {
42 self.0.read_text_file(path).await
43 }
44
45 async fn which(&self, binary_name: String) -> Option<String> {
46 self.0
47 .which(binary_name.as_ref())
48 .await
49 .map(|path| path.to_string_lossy().to_string())
50 }
51
52 async fn shell_env(&self) -> Vec<(String, String)> {
53 self.0.shell_env().await.into_iter().collect()
54 }
55}
56
57#[async_trait(?Send)]
58impl DebugAdapter for ExtensionDapAdapter {
59 fn name(&self) -> DebugAdapterName {
60 self.debug_adapter_name.as_ref().into()
61 }
62
63 async fn get_binary(
64 &self,
65 delegate: &Arc<dyn DapDelegate>,
66 config: &DebugTaskDefinition,
67 user_installed_path: Option<PathBuf>,
68 _cx: &mut AsyncApp,
69 ) -> Result<DebugAdapterBinary> {
70 self.extension
71 .get_dap_binary(
72 self.debug_adapter_name.clone(),
73 config.clone(),
74 user_installed_path,
75 Arc::new(WorktreeDelegateAdapter(delegate.clone())),
76 )
77 .await
78 }
79}