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/// it supports both synchronous and asynchronous tests, and can provide you with
148/// as many `TestAppContext` instances as you need.
149/// The output contains a `#[test]` annotation so this can be used with any existing
150/// test harness (`cargo test` or `cargo-nextest`).
151///
152/// ```
153/// #[gpui::test]
154/// async fn test_foo(mut cx: &TestAppContext) { }
155/// ```
156///
157/// In addition to passing a TestAppContext, you can also ask for a `StdRnd` instance.
158/// this will be seeded with the `SEED` environment variable and is used internally by
159/// the ForegroundExecutor and BackgroundExecutor to run tasks deterministically in tests.
160/// Using the same `StdRng` for behavior in your test will allow you to exercise a wide
161/// variety of scenarios and interleavings just by changing the seed.
162///
163/// `#[gpui::test]` also takes three different arguments:
164/// - `#[gpui::test(iterations=10)]` will run the test ten times with a different initial SEED.
165/// - `#[gpui::test(retries=3)]` will run the test up to four times if it fails to try and make it pass.
166/// - `#[gpui::test(on_failure="crate::test::report_failure")]` will call the specified function after the
167/// tests fail so that you can write out more detail about the failure.
168#[proc_macro_attribute]
169pub fn test(args: TokenStream, function: TokenStream) -> TokenStream {
170 test::test(args, function)
171}
172
173pub(crate) fn get_simple_attribute_field(ast: &DeriveInput, name: &'static str) -> Option<Ident> {
174 match &ast.data {
175 syn::Data::Struct(data_struct) => data_struct
176 .fields
177 .iter()
178 .find(|field| field.attrs.iter().any(|attr| attr.path.is_ident(name)))
179 .map(|field| field.ident.clone().unwrap()),
180 syn::Data::Enum(_) => None,
181 syn::Data::Union(_) => None,
182 }
183}