Detailed changes
@@ -3797,6 +3797,7 @@ dependencies = [
"image",
"itertools 0.10.5",
"lazy_static",
+ "linkme",
"log",
"media",
"metal",
@@ -4815,6 +4816,26 @@ version = "0.5.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0717cef1bc8b636c6e1c1bbdefc09e6322da8a9321966e8928ef80d20f7f770f"
+[[package]]
+name = "linkme"
+version = "0.3.17"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "91ed2ee9464ff9707af8e9ad834cffa4802f072caad90639c583dd3c62e6e608"
+dependencies = [
+ "linkme-impl",
+]
+
+[[package]]
+name = "linkme-impl"
+version = "0.3.17"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ba125974b109d512fccbc6c0244e7580143e460895dfd6ea7f8bbb692fd94396"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.37",
+]
+
[[package]]
name = "linux-raw-sys"
version = "0.0.42"
@@ -22,6 +22,7 @@ sqlez = { path = "../sqlez" }
async-task = "4.0.3"
backtrace = { version = "0.3", optional = true }
ctor.workspace = true
+linkme = "0.3"
derive_more.workspace = true
dhat = { version = "0.3", optional = true }
env_logger = { version = "0.9", optional = true }
@@ -200,3 +200,43 @@ macro_rules! actions {
actions!($($rest)*);
};
}
+
+/// This type must be public so that our macros can build it in other crates.
+/// But this is an implementation detail and should not be used directly.
+#[doc(hidden)]
+pub struct ActionData {
+ pub name: &'static str,
+ pub build: ActionBuilder,
+ pub type_id: TypeId,
+}
+
+/// This type must be public so that our macros can build it in other crates.
+/// But this is an implementation detail and should not be used directly.
+#[doc(hidden)]
+pub type MacroActionBuilder = fn() -> ActionData;
+
+/// This constant must be public to be accessible from other crates.
+/// But it's existence is an implementation detail and should not be used directly.
+#[doc(hidden)]
+#[linkme::distributed_slice]
+pub static __GPUI_ACTIONS: [MacroActionBuilder];
+
+fn qualify_name(action_name: &'static str) -> SharedString {
+ let mut separator_matches = action_name.rmatch_indices("::");
+ separator_matches.next().unwrap();
+ let name_start_ix = separator_matches.next().map_or(0, |(ix, _)| ix + 2);
+ // todo!() remove the 2 replacement when migration is done
+ action_name[name_start_ix..].replace("2::", "::").into()
+}
+
+pub(crate) fn load_actions_2() {
+ let mut lock = ACTION_REGISTRY.write();
+
+ for action in __GPUI_ACTIONS {
+ let action = action();
+ let name = qualify_name(action.name);
+ lock.builders_by_name.insert(name.clone(), action.build);
+ lock.names_by_type_id.insert(action.type_id, name.clone());
+ lock.all_names.push(name);
+ }
+}
@@ -49,6 +49,7 @@ pub use input::*;
pub use interactive::*;
pub use key_dispatch::*;
pub use keymap::*;
+pub use linkme;
pub use platform::*;
use private::Sealed;
pub use refineable::*;
@@ -9,6 +9,6 @@ path = "src/gpui2_macros.rs"
proc-macro = true
[dependencies]
-syn = "1.0.72"
+syn = { version = "1.0.72", features = ["full"] }
quote = "1.0.9"
proc-macro2 = "1.0.66"
@@ -18,14 +18,31 @@ use syn::{parse_macro_input, DeriveInput};
pub fn register_action(_attr: TokenStream, item: TokenStream) -> TokenStream {
let input = parse_macro_input!(item as DeriveInput);
let type_name = &input.ident;
- let ctor_fn_name = format_ident!("register_{}_builder", type_name.to_string().to_lowercase());
+
+ let static_slice_name =
+ format_ident!("__GPUI_ACTIONS_{}", type_name.to_string().to_uppercase());
+
+ let action_builder_fn_name = format_ident!(
+ "__gpui_actions_builder_{}",
+ type_name.to_string().to_lowercase()
+ );
let expanded = quote! {
#input
- #[allow(non_snake_case)]
- #[gpui::ctor]
- fn #ctor_fn_name() {
- gpui::register_action::<#type_name>()
+
+ #[doc(hidden)]
+ #[gpui::linkme::distributed_slice(gpui::__GPUI_ACTIONS)]
+ #[linkme(crate = gpui::linkme)]
+ static #static_slice_name: gpui::MacroActionBuilder = #action_builder_fn_name;
+
+ /// This is an auto generated function, do not use.
+ #[doc(hidden)]
+ fn #action_builder_fn_name() -> gpui::ActionData {
+ gpui::ActionData {
+ name: ::std::any::type_name::<#type_name>(),
+ type_id: ::std::any::TypeId::of::<#type_name>(),
+ build: <#type_name as gpui::Action>::build,
+ }
}
};