1use collections::HashMap;
2use component::ComponentId;
3use gpui::{App, Entity, WeakEntity};
4use linkme::distributed_slice;
5use std::sync::OnceLock;
6use ui::{AnyElement, Component, ComponentScope, 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 + Sized {
26 #[allow(unused)] // We can't know this is used due to the distributed slice
27 fn scope(&self) -> ComponentScope {
28 ComponentScope::Agent
29 }
30
31 /// Static method to create a preview for this component type
32 fn agent_preview(
33 workspace: WeakEntity<Workspace>,
34 active_thread: Entity<ActiveThread>,
35 thread_store: WeakEntity<ThreadStore>,
36 window: &mut Window,
37 cx: &mut App,
38 ) -> Option<AnyElement>;
39}
40
41/// Register an agent preview for the given component type
42#[macro_export]
43macro_rules! register_agent_preview {
44 ($type:ty) => {
45 #[linkme::distributed_slice($crate::ui::preview::__ALL_AGENT_PREVIEWS)]
46 static __REGISTER_AGENT_PREVIEW: fn() -> (
47 component::ComponentId,
48 $crate::ui::preview::PreviewFn,
49 ) = || {
50 (
51 <$type as component::Component>::id(),
52 <$type as $crate::ui::preview::AgentPreview>::agent_preview,
53 )
54 };
55 };
56}
57
58/// Lazy initialized registry of preview functions
59static AGENT_PREVIEW_REGISTRY: OnceLock<HashMap<ComponentId, PreviewFn>> = OnceLock::new();
60
61/// Initialize the agent preview registry if needed
62fn get_or_init_registry() -> &'static HashMap<ComponentId, PreviewFn> {
63 AGENT_PREVIEW_REGISTRY.get_or_init(|| {
64 let mut map = HashMap::default();
65 for register_fn in __ALL_AGENT_PREVIEWS.iter() {
66 let (id, preview_fn) = register_fn();
67 map.insert(id, preview_fn);
68 }
69 map
70 })
71}
72
73/// Get a specific agent preview by component ID.
74pub fn get_agent_preview(
75 id: &ComponentId,
76 workspace: WeakEntity<Workspace>,
77 active_thread: Entity<ActiveThread>,
78 thread_store: WeakEntity<ThreadStore>,
79 window: &mut Window,
80 cx: &mut App,
81) -> Option<AnyElement> {
82 let registry = get_or_init_registry();
83 registry
84 .get(id)
85 .and_then(|preview_fn| preview_fn(workspace, active_thread, thread_store, window, cx))
86}
87
88/// Get all registered agent previews.
89pub fn all_agent_previews() -> Vec<ComponentId> {
90 let registry = get_or_init_registry();
91 registry.keys().cloned().collect()
92}