registry.rs

  1use anyhow::Result;
  2use async_trait::async_trait;
  3use collections::FxHashMap;
  4use gpui::{App, Global, SharedString};
  5use language::LanguageName;
  6use parking_lot::RwLock;
  7use task::{DebugRequest, DebugScenario, SpawnInTerminal, TaskTemplate};
  8
  9use crate::{
 10    adapters::{DebugAdapter, DebugAdapterName},
 11    inline_value::InlineValueProvider,
 12};
 13use std::{collections::BTreeMap, sync::Arc};
 14
 15/// Given a user build configuration, locator creates a fill-in debug target ([DebugRequest]) on behalf of the user.
 16#[async_trait]
 17pub trait DapLocator: Send + Sync {
 18    fn name(&self) -> SharedString;
 19    /// Determines whether this locator can generate debug target for given task.
 20    fn create_scenario(
 21        &self,
 22        build_config: &TaskTemplate,
 23        resolved_label: &str,
 24        adapter: DebugAdapterName,
 25    ) -> Option<DebugScenario>;
 26
 27    async fn run(&self, build_config: SpawnInTerminal) -> Result<DebugRequest>;
 28}
 29
 30#[derive(Default)]
 31struct DapRegistryState {
 32    adapters: BTreeMap<DebugAdapterName, Arc<dyn DebugAdapter>>,
 33    locators: FxHashMap<SharedString, Arc<dyn DapLocator>>,
 34    inline_value_providers: FxHashMap<String, Arc<dyn InlineValueProvider>>,
 35}
 36
 37#[derive(Clone, Default)]
 38/// Stores available debug adapters.
 39pub struct DapRegistry(Arc<RwLock<DapRegistryState>>);
 40impl Global for DapRegistry {}
 41
 42impl DapRegistry {
 43    pub fn global(cx: &mut App) -> &mut Self {
 44        let ret = cx.default_global::<Self>();
 45
 46        #[cfg(any(test, feature = "test-support"))]
 47        if ret.adapter(crate::FakeAdapter::ADAPTER_NAME).is_none() {
 48            ret.add_adapter(Arc::new(crate::FakeAdapter::new()));
 49        }
 50
 51        ret
 52    }
 53
 54    pub fn add_adapter(&self, adapter: Arc<dyn DebugAdapter>) {
 55        let name = adapter.name();
 56        let _previous_value = self.0.write().adapters.insert(name, adapter);
 57    }
 58
 59    pub fn adapter_language(&self, adapter_name: &str) -> Option<LanguageName> {
 60        self.adapter(adapter_name)
 61            .and_then(|adapter| adapter.adapter_language_name())
 62    }
 63
 64    pub fn add_locator(&self, locator: Arc<dyn DapLocator>) {
 65        let _previous_value = self.0.write().locators.insert(locator.name(), locator);
 66        debug_assert!(
 67            _previous_value.is_none(),
 68            "Attempted to insert a new debug locator when one is already registered"
 69        );
 70    }
 71
 72    pub fn add_inline_value_provider(
 73        &self,
 74        language: String,
 75        provider: Arc<dyn InlineValueProvider>,
 76    ) {
 77        let _previous_value = self
 78            .0
 79            .write()
 80            .inline_value_providers
 81            .insert(language, provider);
 82        debug_assert!(
 83            _previous_value.is_none(),
 84            "Attempted to insert a new inline value provider when one is already registered"
 85        );
 86    }
 87
 88    pub fn locators(&self) -> FxHashMap<SharedString, Arc<dyn DapLocator>> {
 89        self.0.read().locators.clone()
 90    }
 91
 92    pub fn adapter(&self, name: &str) -> Option<Arc<dyn DebugAdapter>> {
 93        self.0.read().adapters.get(name).cloned()
 94    }
 95
 96    pub fn inline_value_provider(&self, language: &str) -> Option<Arc<dyn InlineValueProvider>> {
 97        self.0.read().inline_value_providers.get(language).cloned()
 98    }
 99
100    pub fn enumerate_adapters(&self) -> Vec<DebugAdapterName> {
101        self.0.read().adapters.keys().cloned().collect()
102    }
103}