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;
10
11/// Function type for creating agent component previews
12pub type PreviewFn =
13 fn(WeakEntity<Workspace>, Entity<ActiveThread>, &mut Window, &mut App) -> Option<AnyElement>;
14
15/// Distributed slice for preview registration functions
16#[distributed_slice]
17pub static __ALL_AGENT_PREVIEWS: [fn() -> (ComponentId, PreviewFn)] = [..];
18
19/// Trait that must be implemented by components that provide agent previews.
20pub trait AgentPreview: Component + Sized {
21 #[allow(unused)] // We can't know this is used due to the distributed slice
22 fn scope(&self) -> ComponentScope {
23 ComponentScope::Agent
24 }
25
26 /// Static method to create a preview for this component type
27 fn agent_preview(
28 workspace: WeakEntity<Workspace>,
29 active_thread: Entity<ActiveThread>,
30 window: &mut Window,
31 cx: &mut App,
32 ) -> Option<AnyElement>;
33}
34
35/// Register an agent preview for the given component type
36#[macro_export]
37macro_rules! register_agent_preview {
38 ($type:ty) => {
39 #[linkme::distributed_slice($crate::ui::preview::__ALL_AGENT_PREVIEWS)]
40 static __REGISTER_AGENT_PREVIEW: fn() -> (
41 component::ComponentId,
42 $crate::ui::preview::PreviewFn,
43 ) = || {
44 (
45 <$type as component::Component>::id(),
46 <$type as $crate::ui::preview::AgentPreview>::agent_preview,
47 )
48 };
49 };
50}
51
52/// Lazy initialized registry of preview functions
53static AGENT_PREVIEW_REGISTRY: OnceLock<HashMap<ComponentId, PreviewFn>> = OnceLock::new();
54
55/// Initialize the agent preview registry if needed
56fn get_or_init_registry() -> &'static HashMap<ComponentId, PreviewFn> {
57 AGENT_PREVIEW_REGISTRY.get_or_init(|| {
58 let mut map = HashMap::default();
59 for register_fn in __ALL_AGENT_PREVIEWS.iter() {
60 let (id, preview_fn) = register_fn();
61 map.insert(id, preview_fn);
62 }
63 map
64 })
65}
66
67/// Get a specific agent preview by component ID.
68pub fn get_agent_preview(
69 id: &ComponentId,
70 workspace: WeakEntity<Workspace>,
71 active_thread: Entity<ActiveThread>,
72 window: &mut Window,
73 cx: &mut App,
74) -> Option<AnyElement> {
75 let registry = get_or_init_registry();
76 registry
77 .get(id)
78 .and_then(|preview_fn| preview_fn(workspace, active_thread, window, cx))
79}
80
81/// Get all registered agent previews.
82pub fn all_agent_previews() -> Vec<ComponentId> {
83 let registry = get_or_init_registry();
84 registry.keys().cloned().collect()
85}