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 })
73 })
74 }
75
76 fn configuration(
77 &self,
78 worktree_store: Entity<WorktreeStore>,
79 cx: &AsyncApp,
80 ) -> Task<Result<Option<ContextServerConfiguration>>> {
81 let id = self.id.clone();
82 let extension = self.extension.clone();
83 cx.spawn(async move |cx| {
84 let extension_project = extension_project(worktree_store, cx)?;
85 let configuration = extension
86 .context_server_configuration(id.clone(), extension_project)
87 .await?;
88
89 log::debug!("loaded configuration for context server {id}: {configuration:?}");
90
91 Ok(configuration)
92 })
93 }
94}
95
96struct ContextServerDescriptorRegistryProxy {
97 context_server_factory_registry: Entity<ContextServerDescriptorRegistry>,
98}
99
100impl ExtensionContextServerProxy for ContextServerDescriptorRegistryProxy {
101 fn register_context_server(&self, extension: Arc<dyn Extension>, id: Arc<str>, cx: &mut App) {
102 self.context_server_factory_registry
103 .update(cx, |registry, cx| {
104 registry.register_context_server_descriptor(
105 id.clone(),
106 Arc::new(ContextServerDescriptor { id, extension })
107 as Arc<dyn registry::ContextServerDescriptor>,
108 cx,
109 )
110 });
111 }
112
113 fn unregister_context_server(&self, server_id: Arc<str>, cx: &mut App) {
114 self.context_server_factory_registry
115 .update(cx, |registry, cx| {
116 registry.unregister_context_server_descriptor_by_id(&server_id, cx)
117 });
118 }
119}