agent_preview.rs

 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}