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::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}