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