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}