gpui_macros.rs

  1mod derive_app_context;
  2mod derive_into_element;
  3mod derive_path_static_str;
  4mod derive_render;
  5mod derive_visual_context;
  6mod register_action;
  7mod styles;
  8mod test;
  9
 10use proc_macro::TokenStream;
 11use syn::{DeriveInput, Ident};
 12
 13/// register_action! can be used to register an action with the GPUI runtime.
 14/// You should typically use `gpui::actions!` or `gpui::impl_actions!` instead,
 15/// but this can be used for fine grained customization.
 16#[proc_macro]
 17pub fn register_action(ident: TokenStream) -> TokenStream {
 18    register_action::register_action_macro(ident)
 19}
 20
 21/// #[derive(IntoElement)] is used to create a Component out of anything that implements
 22/// the `RenderOnce` trait.
 23#[proc_macro_derive(IntoElement)]
 24pub fn derive_into_element(input: TokenStream) -> TokenStream {
 25    derive_into_element::derive_into_element(input)
 26}
 27
 28#[proc_macro_derive(Render)]
 29#[doc(hidden)]
 30pub fn derive_render(input: TokenStream) -> TokenStream {
 31    derive_render::derive_render(input)
 32}
 33
 34#[proc_macro_derive(PathStaticStr)]
 35#[doc(hidden)]
 36pub fn derive_path_static_str(input: TokenStream) -> TokenStream {
 37    derive_path_static_str::derive_path_static_str(input)
 38}
 39
 40/// #[derive(AppContext)] is used to create a context out of anything that holds a `&mut App`
 41/// Note that a `#[app]` attribute is required to identify the variable holding the &mut App.
 42///
 43/// Failure to add the attribute causes a compile error:
 44///
 45/// ```compile_fail
 46/// # #[macro_use] extern crate gpui_macros;
 47/// # #[macro_use] extern crate gpui;
 48/// #[derive(AppContext)]
 49/// struct MyContext<'a> {
 50///     app: &'a mut gpui::App
 51/// }
 52/// ```
 53#[proc_macro_derive(AppContext, attributes(app))]
 54pub fn derive_app_context(input: TokenStream) -> TokenStream {
 55    derive_app_context::derive_app_context(input)
 56}
 57
 58/// #[derive(VisualContext)] is used to create a visual context out of anything that holds a `&mut Window` and
 59/// implements `AppContext`
 60/// Note that a `#[app]` and a `#[window]` attribute are required to identify the variables holding the &mut App,
 61/// and &mut Window respectively.
 62///
 63/// Failure to add both attributes causes a compile error:
 64///
 65/// ```compile_fail
 66/// # #[macro_use] extern crate gpui_macros;
 67/// # #[macro_use] extern crate gpui;
 68/// #[derive(VisualContext)]
 69/// struct MyContext<'a, 'b> {
 70///     #[app]
 71///     app: &'a mut gpui::App,
 72///     window: &'b mut gpui::Window
 73/// }
 74/// ```
 75///
 76/// ```compile_fail
 77/// # #[macro_use] extern crate gpui_macros;
 78/// # #[macro_use] extern crate gpui;
 79/// #[derive(VisualContext)]
 80/// struct MyContext<'a, 'b> {
 81///     app: &'a mut gpui::App,
 82///     #[window]
 83///     window: &'b mut gpui::Window
 84/// }
 85/// ```
 86#[proc_macro_derive(VisualContext, attributes(window, app))]
 87pub fn derive_visual_context(input: TokenStream) -> TokenStream {
 88    derive_visual_context::derive_visual_context(input)
 89}
 90
 91/// Used by GPUI to generate the style helpers.
 92#[proc_macro]
 93#[doc(hidden)]
 94pub fn style_helpers(input: TokenStream) -> TokenStream {
 95    styles::style_helpers(input)
 96}
 97
 98/// Generates methods for visibility styles.
 99#[proc_macro]
100pub fn visibility_style_methods(input: TokenStream) -> TokenStream {
101    styles::visibility_style_methods(input)
102}
103
104/// Generates methods for margin styles.
105#[proc_macro]
106pub fn margin_style_methods(input: TokenStream) -> TokenStream {
107    styles::margin_style_methods(input)
108}
109
110/// Generates methods for padding styles.
111#[proc_macro]
112pub fn padding_style_methods(input: TokenStream) -> TokenStream {
113    styles::padding_style_methods(input)
114}
115
116/// Generates methods for position styles.
117#[proc_macro]
118pub fn position_style_methods(input: TokenStream) -> TokenStream {
119    styles::position_style_methods(input)
120}
121
122/// Generates methods for overflow styles.
123#[proc_macro]
124pub fn overflow_style_methods(input: TokenStream) -> TokenStream {
125    styles::overflow_style_methods(input)
126}
127
128/// Generates methods for cursor styles.
129#[proc_macro]
130pub fn cursor_style_methods(input: TokenStream) -> TokenStream {
131    styles::cursor_style_methods(input)
132}
133
134/// Generates methods for border styles.
135#[proc_macro]
136pub fn border_style_methods(input: TokenStream) -> TokenStream {
137    styles::border_style_methods(input)
138}
139
140/// Generates methods for box shadow styles.
141#[proc_macro]
142pub fn box_shadow_style_methods(input: TokenStream) -> TokenStream {
143    styles::box_shadow_style_methods(input)
144}
145
146/// `#[gpui::test]` can be used to annotate test functions that run with GPUI support.
147///
148/// It supports both synchronous and asynchronous tests, and can provide you with
149/// as many `TestAppContext` instances as you need.
150/// The output contains a `#[test]` annotation so this can be used with any existing
151/// test harness (`cargo test` or `cargo-nextest`).
152///
153/// ```
154/// #[gpui::test]
155/// async fn test_foo(mut cx: &TestAppContext) { }
156/// ```
157///
158/// In addition to passing a TestAppContext, you can also ask for a `StdRnd` instance.
159/// this will be seeded with the `SEED` environment variable and is used internally by
160/// the ForegroundExecutor and BackgroundExecutor to run tasks deterministically in tests.
161/// Using the same `StdRng` for behavior in your test will allow you to exercise a wide
162/// variety of scenarios and interleavings just by changing the seed.
163///
164/// # Arguments
165///
166/// - `#[gpui::test]` with no arguments runs once with the seed `0` or `SEED` env var if set.
167/// - `#[gpui::test(seed = 10)]` runs once with the seed `10`.
168/// - `#[gpui::test(seeds(10, 20, 30))]` runs three times with seeds `10`, `20`, and `30`.
169/// - `#[gpui::test(iterations = 5)]` runs five times, providing as seed the values in the range `0..5`.
170/// - `#[gpui::test(retries = 3)]` runs up to four times if it fails to try and make it pass.
171/// - `#[gpui::test(on_failure = "crate::test::report_failure")]` will call the specified function after the
172///    tests fail so that you can write out more detail about the failure.
173///
174/// You can combine `iterations = ...` with `seeds(...)`:
175/// - `#[gpui::test(iterations = 5, seed = 10)]` is equivalent to `#[gpui::test(seeds(0, 1, 2, 3, 4, 10))]`.
176/// - `#[gpui::test(iterations = 5, seeds(10, 20, 30)]` is equivalent to `#[gpui::test(seeds(0, 1, 2, 3, 4, 10, 20, 30))]`.
177/// - `#[gpui::test(seeds(10, 20, 30), iterations = 5]` is equivalent to `#[gpui::test(seeds(0, 1, 2, 3, 4, 10, 20, 30))]`.
178///
179/// # Environment Variables
180///
181/// - `SEED`: sets a seed for the first run
182/// - `ITERATIONS`: forces the value of the `iterations` argument
183#[proc_macro_attribute]
184pub fn test(args: TokenStream, function: TokenStream) -> TokenStream {
185    test::test(args, function)
186}
187
188pub(crate) fn get_simple_attribute_field(ast: &DeriveInput, name: &'static str) -> Option<Ident> {
189    match &ast.data {
190        syn::Data::Struct(data_struct) => data_struct
191            .fields
192            .iter()
193            .find(|field| field.attrs.iter().any(|attr| attr.path.is_ident(name)))
194            .map(|field| field.ident.clone().unwrap()),
195        syn::Data::Enum(_) => None,
196        syn::Data::Union(_) => None,
197    }
198}