1use std::sync::Arc;
  2
  3use anyhow::Result;
  4use context_server::ContextServerCommand;
  5use extension::{
  6    ContextServerConfiguration, Extension, ExtensionContextServerProxy, ExtensionHostProxy,
  7    ProjectDelegate,
  8};
  9use gpui::{App, AsyncApp, Entity, Task};
 10
 11use crate::worktree_store::WorktreeStore;
 12
 13use super::registry::{self, ContextServerDescriptorRegistry};
 14
 15pub fn init(cx: &mut App) {
 16    let proxy = ExtensionHostProxy::default_global(cx);
 17    proxy.register_context_server_proxy(ContextServerDescriptorRegistryProxy {
 18        context_server_factory_registry: ContextServerDescriptorRegistry::default_global(cx),
 19    });
 20}
 21
 22struct ExtensionProject {
 23    worktree_ids: Vec<u64>,
 24}
 25
 26impl ProjectDelegate for ExtensionProject {
 27    fn worktree_ids(&self) -> Vec<u64> {
 28        self.worktree_ids.clone()
 29    }
 30}
 31
 32struct ContextServerDescriptor {
 33    id: Arc<str>,
 34    extension: Arc<dyn Extension>,
 35}
 36
 37fn extension_project(
 38    worktree_store: Entity<WorktreeStore>,
 39    cx: &mut AsyncApp,
 40) -> Result<Arc<ExtensionProject>> {
 41    worktree_store.update(cx, |worktree_store, cx| {
 42        Arc::new(ExtensionProject {
 43            worktree_ids: worktree_store
 44                .visible_worktrees(cx)
 45                .map(|worktree| worktree.read(cx).id().to_proto())
 46                .collect(),
 47        })
 48    })
 49}
 50
 51impl registry::ContextServerDescriptor for ContextServerDescriptor {
 52    fn command(
 53        &self,
 54        worktree_store: Entity<WorktreeStore>,
 55        cx: &AsyncApp,
 56    ) -> Task<Result<ContextServerCommand>> {
 57        let id = self.id.clone();
 58        let extension = self.extension.clone();
 59        cx.spawn(async move |cx| {
 60            let extension_project = extension_project(worktree_store, cx)?;
 61            let mut command = extension
 62                .context_server_command(id.clone(), extension_project.clone())
 63                .await?;
 64            command.command = extension.path_from_extension(&command.command);
 65
 66            log::debug!("loaded command for context server {id}: {command:?}");
 67
 68            Ok(ContextServerCommand {
 69                path: command.command,
 70                args: command.args,
 71                env: Some(command.env.into_iter().collect()),
 72                timeout: None,
 73            })
 74        })
 75    }
 76
 77    fn configuration(
 78        &self,
 79        worktree_store: Entity<WorktreeStore>,
 80        cx: &AsyncApp,
 81    ) -> Task<Result<Option<ContextServerConfiguration>>> {
 82        let id = self.id.clone();
 83        let extension = self.extension.clone();
 84        cx.spawn(async move |cx| {
 85            let extension_project = extension_project(worktree_store, cx)?;
 86            let configuration = extension
 87                .context_server_configuration(id.clone(), extension_project)
 88                .await?;
 89
 90            log::debug!("loaded configuration for context server {id}: {configuration:?}");
 91
 92            Ok(configuration)
 93        })
 94    }
 95}
 96
 97struct ContextServerDescriptorRegistryProxy {
 98    context_server_factory_registry: Entity<ContextServerDescriptorRegistry>,
 99}
100
101impl ExtensionContextServerProxy for ContextServerDescriptorRegistryProxy {
102    fn register_context_server(&self, extension: Arc<dyn Extension>, id: Arc<str>, cx: &mut App) {
103        self.context_server_factory_registry
104            .update(cx, |registry, cx| {
105                registry.register_context_server_descriptor(
106                    id.clone(),
107                    Arc::new(ContextServerDescriptor { id, extension })
108                        as Arc<dyn registry::ContextServerDescriptor>,
109                    cx,
110                )
111            });
112    }
113
114    fn unregister_context_server(&self, server_id: Arc<str>, cx: &mut App) {
115        self.context_server_factory_registry
116            .update(cx, |registry, cx| {
117                registry.unregister_context_server_descriptor_by_id(&server_id, cx)
118            });
119    }
120}