agent_preview.rs

 1use std::sync::OnceLock;
 2
 3use collections::HashMap;
 4use component::ComponentId;
 5use gpui::{App, Entity, WeakEntity};
 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
15pub struct AgentPreviewFn(fn() -> (ComponentId, PreviewFn));
16
17impl AgentPreviewFn {
18    pub const fn new(f: fn() -> (ComponentId, PreviewFn)) -> Self {
19        Self(f)
20    }
21}
22
23inventory::collect!(AgentPreviewFn);
24
25/// Trait that must be implemented by components that provide agent previews.
26pub trait AgentPreview: Component + Sized {
27    #[allow(unused)] // We can't know this is used due to the distributed slice
28    fn scope(&self) -> ComponentScope {
29        ComponentScope::Agent
30    }
31
32    /// Static method to create a preview for this component type
33    fn agent_preview(
34        workspace: WeakEntity<Workspace>,
35        active_thread: Entity<ActiveThread>,
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        inventory::submit! {
46            $crate::ui::preview::AgentPreviewFn::new(|| {
47                (
48                    <$type as component::Component>::id(),
49                    <$type as $crate::ui::preview::AgentPreview>::agent_preview,
50                )
51            })
52        }
53    };
54}
55
56/// Lazy initialized registry of preview functions
57static AGENT_PREVIEW_REGISTRY: OnceLock<HashMap<ComponentId, PreviewFn>> = OnceLock::new();
58
59/// Initialize the agent preview registry if needed
60fn get_or_init_registry() -> &'static HashMap<ComponentId, PreviewFn> {
61    AGENT_PREVIEW_REGISTRY.get_or_init(|| {
62        let mut map = HashMap::default();
63        for register_fn in inventory::iter::<AgentPreviewFn>() {
64            let (id, preview_fn) = (register_fn.0)();
65            map.insert(id, preview_fn);
66        }
67        map
68    })
69}
70
71/// Get a specific agent preview by component ID.
72pub fn get_agent_preview(
73    id: &ComponentId,
74    workspace: WeakEntity<Workspace>,
75    active_thread: Entity<ActiveThread>,
76    window: &mut Window,
77    cx: &mut App,
78) -> Option<AnyElement> {
79    let registry = get_or_init_registry();
80    registry
81        .get(id)
82        .and_then(|preview_fn| preview_fn(workspace, active_thread, window, cx))
83}
84
85/// Get all registered agent previews.
86pub fn all_agent_previews() -> Vec<ComponentId> {
87    let registry = get_or_init_registry();
88    registry.keys().cloned().collect()
89}