extension_dap_adapter.rs

  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}