agent: Use `inventory` for `AgentPreview` (#30740)

Marshall Bowers created

This PR updates the `AgentPreview` to use `inventory` instead of
`linkme`.

Release Notes:

- N/A

Change summary

Cargo.lock                                   | 24 -------------
Cargo.toml                                   |  1 
crates/agent/Cargo.toml                      |  2 
crates/agent/src/ui/preview/agent_preview.rs | 38 ++++++++++++---------
crates/ui/Cargo.toml                         |  5 --
crates/ui_macros/Cargo.toml                  |  1 
6 files changed, 23 insertions(+), 48 deletions(-)

Detailed changes

Cargo.lock 🔗

@@ -81,12 +81,12 @@ dependencies = [
  "http_client",
  "indexed_docs",
  "indoc",
+ "inventory",
  "itertools 0.14.0",
  "jsonschema",
  "language",
  "language_model",
  "language_model_selector",
- "linkme",
  "log",
  "lsp",
  "markdown",
@@ -8160,26 +8160,6 @@ dependencies = [
  "memchr",
 ]
 
-[[package]]
-name = "linkme"
-version = "0.3.32"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "22d227772b5999ddc0690e733f734f95ca05387e329c4084fe65678c51198ffe"
-dependencies = [
- "linkme-impl",
-]
-
-[[package]]
-name = "linkme-impl"
-version = "0.3.32"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "71a98813fa0073a317ed6a8055dcd4722a49d9b862af828ee68449adb799b6be"
-dependencies = [
- "proc-macro2",
- "quote",
- "syn 2.0.100",
-]
-
 [[package]]
 name = "linux-raw-sys"
 version = "0.4.15"
@@ -15682,7 +15662,6 @@ dependencies = [
  "gpui",
  "icons",
  "itertools 0.14.0",
- "linkme",
  "menu",
  "serde",
  "settings",
@@ -15714,7 +15693,6 @@ name = "ui_macros"
 version = "0.1.0"
 dependencies = [
  "convert_case 0.8.0",
- "linkme",
  "proc-macro2",
  "quote",
  "syn 1.0.109",

Cargo.toml 🔗

@@ -465,7 +465,6 @@ jupyter-websocket-client = {  git = "https://github.com/ConradIrwin/runtimed" ,r
 libc = "0.2"
 libsqlite3-sys = { version = "0.30.1", features = ["bundled"] }
 linkify = "0.10.0"
-linkme = "0.3.31"
 log = { version = "0.4.16", features = ["kv_unstable_serde", "serde"] }
 lsp-types = { git = "https://github.com/zed-industries/lsp-types", rev = "c9c189f1c5dd53c624a419ce35bc77ad6a908d18" }
 markup5ever_rcdom = "0.3.0"

crates/agent/Cargo.toml 🔗

@@ -47,12 +47,12 @@ heed.workspace = true
 html_to_markdown.workspace = true
 http_client.workspace = true
 indexed_docs.workspace = true
+inventory.workspace = true
 itertools.workspace = true
 jsonschema.workspace = true
 language.workspace = true
 language_model.workspace = true
 language_model_selector.workspace = true
-linkme.workspace = true
 log.workspace = true
 lsp.workspace = true
 markdown.workspace = true

crates/agent/src/ui/preview/agent_preview.rs 🔗

@@ -1,8 +1,8 @@
+use std::sync::OnceLock;
+
 use collections::HashMap;
 use component::ComponentId;
 use gpui::{App, Entity, WeakEntity};
-use linkme::distributed_slice;
-use std::sync::OnceLock;
 use ui::{AnyElement, Component, ComponentScope, Window};
 use workspace::Workspace;
 
@@ -12,9 +12,15 @@ use crate::ActiveThread;
 pub type PreviewFn =
     fn(WeakEntity<Workspace>, Entity<ActiveThread>, &mut Window, &mut App) -> Option<AnyElement>;
 
-/// Distributed slice for preview registration functions
-#[distributed_slice]
-pub static __ALL_AGENT_PREVIEWS: [fn() -> (ComponentId, PreviewFn)] = [..];
+pub struct AgentPreviewFn(fn() -> (ComponentId, PreviewFn));
+
+impl AgentPreviewFn {
+    pub const fn new(f: fn() -> (ComponentId, PreviewFn)) -> Self {
+        Self(f)
+    }
+}
+
+inventory::collect!(AgentPreviewFn);
 
 /// Trait that must be implemented by components that provide agent previews.
 pub trait AgentPreview: Component + Sized {
@@ -36,16 +42,14 @@ pub trait AgentPreview: Component + Sized {
 #[macro_export]
 macro_rules! register_agent_preview {
     ($type:ty) => {
-        #[linkme::distributed_slice($crate::ui::preview::__ALL_AGENT_PREVIEWS)]
-        static __REGISTER_AGENT_PREVIEW: fn() -> (
-            component::ComponentId,
-            $crate::ui::preview::PreviewFn,
-        ) = || {
-            (
-                <$type as component::Component>::id(),
-                <$type as $crate::ui::preview::AgentPreview>::agent_preview,
-            )
-        };
+        inventory::submit! {
+            $crate::ui::preview::AgentPreviewFn::new(|| {
+                (
+                    <$type as component::Component>::id(),
+                    <$type as $crate::ui::preview::AgentPreview>::agent_preview,
+                )
+            })
+        }
     };
 }
 
@@ -56,8 +60,8 @@ static AGENT_PREVIEW_REGISTRY: OnceLock<HashMap<ComponentId, PreviewFn>> = OnceL
 fn get_or_init_registry() -> &'static HashMap<ComponentId, PreviewFn> {
     AGENT_PREVIEW_REGISTRY.get_or_init(|| {
         let mut map = HashMap::default();
-        for register_fn in __ALL_AGENT_PREVIEWS.iter() {
-            let (id, preview_fn) = register_fn();
+        for register_fn in inventory::iter::<AgentPreviewFn>() {
+            let (id, preview_fn) = (register_fn.0)();
             map.insert(id, preview_fn);
         }
         map

crates/ui/Cargo.toml 🔗

@@ -19,7 +19,6 @@ documented.workspace = true
 gpui.workspace = true
 icons.workspace = true
 itertools.workspace = true
-linkme.workspace = true
 menu.workspace = true
 serde.workspace = true
 settings.workspace = true
@@ -37,7 +36,3 @@ windows.workspace = true
 [features]
 default = []
 stories = ["dep:story"]
-
-# cargo-machete doesn't understand that linkme is used in the component macro
-[package.metadata.cargo-machete]
-ignored = ["linkme"]

crates/ui_macros/Cargo.toml 🔗

@@ -14,7 +14,6 @@ proc-macro = true
 
 [dependencies]
 convert_case.workspace = true
-linkme.workspace = true
 proc-macro2.workspace = true
 quote.workspace = true
 syn.workspace = true