1use collections::HashMap;
2use component::ComponentId;
3use gpui::{App, Entity, WeakEntity};
4use linkme::distributed_slice;
5use std::sync::OnceLock;
6use ui::{AnyElement, Component, Window};
7use workspace::Workspace;
8
9use crate::{ActiveThread, ThreadStore};
10
11/// Function type for creating agent component previews
12pub type PreviewFn = fn(
13 WeakEntity<Workspace>,
14 Entity<ActiveThread>,
15 WeakEntity<ThreadStore>,
16 &mut Window,
17 &mut App,
18) -> Option<AnyElement>;
19
20/// Distributed slice for preview registration functions
21#[distributed_slice]
22pub static __ALL_AGENT_PREVIEWS: [fn() -> (ComponentId, PreviewFn)] = [..];
23
24/// Trait that must be implemented by components that provide agent previews.
25pub trait AgentPreview: Component {
26 /// Get the ID for this component
27 ///
28 /// Eventually this will move to the component trait.
29 fn id() -> ComponentId
30 where
31 Self: Sized,
32 {
33 ComponentId(Self::name())
34 }
35
36 /// Static method to create a preview for this component type
37 fn create_preview(
38 workspace: WeakEntity<Workspace>,
39 active_thread: Entity<ActiveThread>,
40 thread_store: WeakEntity<ThreadStore>,
41 window: &mut Window,
42 cx: &mut App,
43 ) -> Option<AnyElement>
44 where
45 Self: Sized;
46}
47
48/// Register an agent preview for the given component type
49#[macro_export]
50macro_rules! register_agent_preview {
51 ($type:ty) => {
52 #[linkme::distributed_slice($crate::ui::agent_preview::__ALL_AGENT_PREVIEWS)]
53 static __REGISTER_AGENT_PREVIEW: fn() -> (
54 component::ComponentId,
55 $crate::ui::agent_preview::PreviewFn,
56 ) = || {
57 (
58 <$type as $crate::ui::agent_preview::AgentPreview>::id(),
59 <$type as $crate::ui::agent_preview::AgentPreview>::create_preview,
60 )
61 };
62 };
63}
64
65/// Lazy initialized registry of preview functions
66static AGENT_PREVIEW_REGISTRY: OnceLock<HashMap<ComponentId, PreviewFn>> = OnceLock::new();
67
68/// Initialize the agent preview registry if needed
69fn get_or_init_registry() -> &'static HashMap<ComponentId, PreviewFn> {
70 AGENT_PREVIEW_REGISTRY.get_or_init(|| {
71 let mut map = HashMap::default();
72 for register_fn in __ALL_AGENT_PREVIEWS.iter() {
73 let (id, preview_fn) = register_fn();
74 map.insert(id, preview_fn);
75 }
76 map
77 })
78}
79
80/// Get a specific agent preview by component ID.
81pub fn get_agent_preview(
82 id: &ComponentId,
83 workspace: WeakEntity<Workspace>,
84 active_thread: Entity<ActiveThread>,
85 thread_store: WeakEntity<ThreadStore>,
86 window: &mut Window,
87 cx: &mut App,
88) -> Option<AnyElement> {
89 let registry = get_or_init_registry();
90 registry
91 .get(id)
92 .and_then(|preview_fn| preview_fn(workspace, active_thread, thread_store, window, cx))
93}
94
95/// Get all registered agent previews.
96pub fn all_agent_previews() -> Vec<ComponentId> {
97 let registry = get_or_init_registry();
98 registry.keys().cloned().collect()
99}