diff --git a/Cargo.lock b/Cargo.lock index 1fba36fd12..ba63f85d85 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1180,6 +1180,7 @@ dependencies = [ "etagere", "font-kit", "foreign-types", + "gpui_macros", "log", "metal", "num_cpus", @@ -1205,6 +1206,14 @@ dependencies = [ "usvg", ] +[[package]] +name = "gpui_macros" +version = "0.1.0" +dependencies = [ + "quote", + "syn", +] + [[package]] name = "hashbrown" version = "0.9.1" diff --git a/Cargo.toml b/Cargo.toml index bf2d5c8143..8109db121b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,5 +1,5 @@ [workspace] -members = ["zed", "gpui", "fsevent", "scoped_pool"] +members = ["zed", "gpui", "gpui_macros", "fsevent", "scoped_pool"] [patch.crates-io] async-task = {git = "https://github.com/zed-industries/async-task", rev = "341b57d6de98cdfd7b418567b8de2022ca993a6e"} diff --git a/gpui/Cargo.toml b/gpui/Cargo.toml index 8c7c3bf4cb..d421a5a2f3 100644 --- a/gpui/Cargo.toml +++ b/gpui/Cargo.toml @@ -8,6 +8,7 @@ version = "0.1.0" async-task = "4.0.3" ctor = "0.1" etagere = "0.2" +gpui_macros = {path = "../gpui_macros"} log = "0.4" num_cpus = "1.13" ordered-float = "2.1.1" diff --git a/gpui/src/lib.rs b/gpui/src/lib.rs index edf14bc65c..19aac02c40 100644 --- a/gpui/src/lib.rs +++ b/gpui/src/lib.rs @@ -24,6 +24,7 @@ pub mod color; pub mod json; pub mod keymap; mod platform; +pub use gpui_macros::test; pub use platform::{Event, PathPromptOptions}; pub use presenter::{ AfterLayoutContext, Axis, DebugContext, EventContext, LayoutContext, PaintContext, diff --git a/gpui_macros/Cargo.toml b/gpui_macros/Cargo.toml new file mode 100644 index 0000000000..19a8e11eb6 --- /dev/null +++ b/gpui_macros/Cargo.toml @@ -0,0 +1,11 @@ +[package] +name = "gpui_macros" +version = "0.1.0" +edition = "2018" + +[lib] +proc-macro = true + +[dependencies] +syn = "1.0" +quote = "1.0" diff --git a/gpui_macros/src/lib.rs b/gpui_macros/src/lib.rs new file mode 100644 index 0000000000..1045868777 --- /dev/null +++ b/gpui_macros/src/lib.rs @@ -0,0 +1,39 @@ +use std::mem; + +use proc_macro::TokenStream; +use quote::{format_ident, quote}; +use syn::{parse_macro_input, ItemFn}; + +#[proc_macro_attribute] +pub fn test(args: TokenStream, function: TokenStream) -> TokenStream { + assert!(args.is_empty()); + + let mut inner_fn = parse_macro_input!(function as ItemFn); + let inner_fn_name = format_ident!("_{}", inner_fn.sig.ident); + let outer_fn_name = mem::replace(&mut inner_fn.sig.ident, inner_fn_name.clone()); + let outer_fn = if inner_fn.sig.asyncness.is_some() { + quote! { + #[test] + fn #outer_fn_name() { + #inner_fn + + gpui::App::test_async((), move |ctx| async { + #inner_fn_name(ctx).await; + }); + } + } + } else { + quote! { + #[test] + fn #outer_fn_name() { + #inner_fn + + gpui::App::test((), |ctx| { + #inner_fn_name(ctx); + }); + } + } + }; + + TokenStream::from(outer_fn) +}