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::adapters::{DebugAdapter, DebugAdapterName};
10use std::{borrow::Cow, collections::BTreeMap, sync::Arc};
11
12/// Given a user build configuration, locator creates a fill-in debug target ([DebugScenario]) on behalf of the user.
13#[async_trait]
14pub trait DapLocator: Send + Sync {
15 fn name(&self) -> SharedString;
16 /// Determines whether this locator can generate debug target for given task.
17 async fn create_scenario(
18 &self,
19 build_config: &TaskTemplate,
20 resolved_label: &str,
21 adapter: &DebugAdapterName,
22 ) -> Option<DebugScenario>;
23
24 async fn run(&self, build_config: SpawnInTerminal) -> Result<DebugRequest>;
25}
26
27#[derive(Default)]
28struct DapRegistryState {
29 adapters: BTreeMap<DebugAdapterName, Arc<dyn DebugAdapter>>,
30 locators: FxHashMap<SharedString, Arc<dyn DapLocator>>,
31}
32
33#[derive(Clone, Default)]
34/// Stores available debug adapters.
35pub struct DapRegistry(Arc<RwLock<DapRegistryState>>);
36impl Global for DapRegistry {}
37
38impl DapRegistry {
39 pub fn global(cx: &mut App) -> &mut Self {
40 cx.default_global::<Self>()
41 }
42
43 pub fn add_adapter(&self, adapter: Arc<dyn DebugAdapter>) {
44 let name = adapter.name();
45 let _previous_value = self.0.write().adapters.insert(name, adapter);
46 }
47 pub fn add_locator(&self, locator: Arc<dyn DapLocator>) {
48 self.0.write().locators.insert(locator.name(), locator);
49 }
50
51 pub fn remove_adapter(&self, name: &str) {
52 self.0.write().adapters.remove(name);
53 }
54
55 pub fn remove_locator(&self, locator: &str) {
56 self.0.write().locators.remove(locator);
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 async fn adapter_schemas(&self) -> Vec<(SharedString, Cow<'static, serde_json::Value>)> {
65 self.0
66 .read()
67 .adapters
68 .iter()
69 .map(|(name, adapter)| (name.0.clone(), adapter.dap_schema()))
70 .collect()
71 }
72
73 pub fn locators(&self) -> FxHashMap<SharedString, Arc<dyn DapLocator>> {
74 self.0.read().locators.clone()
75 }
76
77 pub fn adapter(&self, name: &str) -> Option<Arc<dyn DebugAdapter>> {
78 self.0.read().adapters.get(name).cloned()
79 }
80
81 pub fn enumerate_adapters(&self) -> Vec<DebugAdapterName> {
82 self.0.read().adapters.keys().cloned().collect()
83 }
84}