extension_context_server.rs

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