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