1use std::sync::Arc;
2
3use extension::{Extension, ExtensionContextServerProxy, ExtensionHostProxy, ProjectDelegate};
4use gpui::{AppContext, Model};
5
6use crate::manager::ServerCommand;
7use crate::ContextServerFactoryRegistry;
8
9struct ExtensionProject {
10 worktree_ids: Vec<u64>,
11}
12
13impl ProjectDelegate for ExtensionProject {
14 fn worktree_ids(&self) -> Vec<u64> {
15 self.worktree_ids.clone()
16 }
17}
18
19pub fn init(cx: &mut AppContext) {
20 let proxy = ExtensionHostProxy::default_global(cx);
21 proxy.register_context_server_proxy(ContextServerFactoryRegistryProxy {
22 context_server_factory_registry: ContextServerFactoryRegistry::global(cx),
23 });
24}
25
26struct ContextServerFactoryRegistryProxy {
27 context_server_factory_registry: Model<ContextServerFactoryRegistry>,
28}
29
30impl ExtensionContextServerProxy for ContextServerFactoryRegistryProxy {
31 fn register_context_server(
32 &self,
33 extension: Arc<dyn Extension>,
34 id: Arc<str>,
35 cx: &mut AppContext,
36 ) {
37 self.context_server_factory_registry
38 .update(cx, |registry, _| {
39 registry.register_server_factory(
40 id.clone(),
41 Arc::new({
42 move |project, cx| {
43 log::info!(
44 "loading command for context server {id} from extension {}",
45 extension.manifest().id
46 );
47
48 let id = id.clone();
49 let extension = extension.clone();
50 cx.spawn(|mut cx| async move {
51 let extension_project =
52 project.update(&mut cx, |project, cx| {
53 Arc::new(ExtensionProject {
54 worktree_ids: project
55 .visible_worktrees(cx)
56 .map(|worktree| worktree.read(cx).id().to_proto())
57 .collect(),
58 })
59 })?;
60
61 let command = extension
62 .context_server_command(id.clone(), extension_project)
63 .await?;
64
65 log::info!("loaded command for context server {id}: {command:?}");
66
67 Ok(ServerCommand {
68 path: command.command,
69 args: command.args,
70 env: Some(command.env.into_iter().collect()),
71 })
72 })
73 }
74 }),
75 )
76 });
77 }
78}