styleable_helpers.rs

  1use proc_macro::TokenStream;
  2use proc_macro2::TokenStream as TokenStream2;
  3use quote::{format_ident, quote};
  4use syn::{
  5    parse::{Parse, ParseStream, Result},
  6    parse_macro_input,
  7};
  8
  9struct StyleableMacroInput;
 10
 11impl Parse for StyleableMacroInput {
 12    fn parse(_input: ParseStream) -> Result<Self> {
 13        Ok(StyleableMacroInput)
 14    }
 15}
 16
 17pub fn styleable_helpers(input: TokenStream) -> TokenStream {
 18    let _ = parse_macro_input!(input as StyleableMacroInput);
 19    let methods = generate_methods();
 20    let output = quote! {
 21        #(#methods)*
 22    };
 23
 24    output.into()
 25}
 26
 27fn generate_methods() -> Vec<TokenStream2> {
 28    let mut methods = Vec::new();
 29
 30    for (prefix, auto_allowed, fields) in box_prefixes() {
 31        for (suffix, length_tokens) in box_suffixes() {
 32            if auto_allowed || suffix != "auto" {
 33                let method = generate_method(prefix, suffix, &fields, length_tokens);
 34                methods.push(method);
 35            }
 36        }
 37    }
 38
 39    for (prefix, fields) in corner_prefixes() {
 40        for (suffix, radius_tokens) in corner_suffixes() {
 41            let method = generate_method(prefix, suffix, &fields, radius_tokens);
 42            methods.push(method);
 43        }
 44    }
 45
 46    for (prefix, fields) in border_prefixes() {
 47        for (suffix, width_tokens) in border_suffixes() {
 48            let method = generate_method(prefix, suffix, &fields, width_tokens);
 49            methods.push(method);
 50        }
 51    }
 52
 53    methods
 54}
 55
 56fn generate_method(
 57    prefix: &'static str,
 58    suffix: &'static str,
 59    fields: &Vec<TokenStream2>,
 60    length_tokens: TokenStream2,
 61) -> TokenStream2 {
 62    let method_name = if suffix.is_empty() {
 63        format_ident!("{}", prefix)
 64    } else {
 65        format_ident!("{}_{}", prefix, suffix)
 66    };
 67
 68    let field_assignments = fields
 69        .iter()
 70        .map(|field_tokens| {
 71            quote! {
 72                style.#field_tokens = Some(gpui::geometry::#length_tokens);
 73            }
 74        })
 75        .collect::<Vec<_>>();
 76
 77    let method = quote! {
 78        fn #method_name(mut self) -> Self where Self: std::marker::Sized {
 79            let mut style = self.declared_style();
 80            #(#field_assignments)*
 81            self
 82        }
 83    };
 84
 85    method
 86}
 87
 88fn box_prefixes() -> Vec<(&'static str, bool, Vec<TokenStream2>)> {
 89    vec![
 90        ("w", true, vec![quote! { size.width }]),
 91        ("h", true, vec![quote! { size.height }]),
 92        (
 93            "size",
 94            true,
 95            vec![quote! {size.width}, quote! {size.height}],
 96        ),
 97        ("min_w", false, vec![quote! { min_size.width }]),
 98        ("min_h", false, vec![quote! { min_size.height }]),
 99        ("max_w", false, vec![quote! { max_size.width }]),
100        ("max_h", false, vec![quote! { max_size.height }]),
101        (
102            "m",
103            true,
104            vec![
105                quote! { margin.top },
106                quote! { margin.bottom },
107                quote! { margin.left },
108                quote! { margin.right },
109            ],
110        ),
111        ("mt", true, vec![quote! { margin.top }]),
112        ("mb", true, vec![quote! { margin.bottom }]),
113        (
114            "my",
115            true,
116            vec![quote! { margin.top }, quote! { margin.bottom }],
117        ),
118        (
119            "mx",
120            true,
121            vec![quote! { margin.left }, quote! { margin.right }],
122        ),
123        ("ml", true, vec![quote! { margin.left }]),
124        ("mr", true, vec![quote! { margin.right }]),
125        (
126            "p",
127            false,
128            vec![
129                quote! { padding.top },
130                quote! { padding.bottom },
131                quote! { padding.left },
132                quote! { padding.right },
133            ],
134        ),
135        ("pt", false, vec![quote! { padding.top }]),
136        ("pb", false, vec![quote! { padding.bottom }]),
137        (
138            "px",
139            false,
140            vec![quote! { padding.left }, quote! { padding.right }],
141        ),
142        (
143            "py",
144            false,
145            vec![quote! { padding.top }, quote! { padding.bottom }],
146        ),
147        ("pl", false, vec![quote! { padding.left }]),
148        ("pr", false, vec![quote! { padding.right }]),
149        ("top", true, vec![quote! { inset.top }]),
150        ("bottom", true, vec![quote! { inset.bottom }]),
151        ("left", true, vec![quote! { inset.left }]),
152        ("right", true, vec![quote! { inset.right }]),
153        (
154            "gap",
155            false,
156            vec![quote! { gap.width }, quote! { gap.height }],
157        ),
158        ("gap_x", false, vec![quote! { gap.width }]),
159        ("gap_y", false, vec![quote! { gap.height }]),
160    ]
161}
162
163fn box_suffixes() -> Vec<(&'static str, TokenStream2)> {
164    vec![
165        ("0", quote! { pixels(0.) }),
166        ("0p5", quote! { rems(0.125) }),
167        ("1", quote! { rems(0.25) }),
168        ("1p5", quote! { rems(0.375) }),
169        ("2", quote! { rems(0.5) }),
170        ("2p5", quote! { rems(0.625) }),
171        ("3", quote! { rems(0.75) }),
172        ("3p5", quote! { rems(0.875) }),
173        ("4", quote! { rems(1.) }),
174        ("5", quote! { rems(1.25) }),
175        ("6", quote! { rems(1.5) }),
176        ("7", quote! { rems(1.75) }),
177        ("8", quote! { rems(2.0) }),
178        ("9", quote! { rems(2.25) }),
179        ("10", quote! { rems(2.5) }),
180        ("11", quote! { rems(2.75) }),
181        ("12", quote! { rems(3.) }),
182        ("16", quote! { rems(4.) }),
183        ("20", quote! { rems(5.) }),
184        ("24", quote! { rems(6.) }),
185        ("32", quote! { rems(8.) }),
186        ("40", quote! { rems(10.) }),
187        ("48", quote! { rems(12.) }),
188        ("56", quote! { rems(14.) }),
189        ("64", quote! { rems(16.) }),
190        ("72", quote! { rems(18.) }),
191        ("80", quote! { rems(20.) }),
192        ("96", quote! { rems(24.) }),
193        ("auto", quote! { auto() }),
194        ("px", quote! { pixels(1.) }),
195        ("full", quote! { relative(1.) }),
196        ("1_2", quote! { relative(0.5) }),
197        ("1_3", quote! { relative(1./3.) }),
198        ("2_3", quote! { relative(2./3.) }),
199        ("1_4", quote! { relative(0.25) }),
200        ("2_4", quote! { relative(0.5) }),
201        ("3_4", quote! { relative(0.75) }),
202        ("1_5", quote! { relative(0.2) }),
203        ("2_5", quote! { relative(0.4) }),
204        ("3_5", quote! { relative(0.6) }),
205        ("4_5", quote! { relative(0.8) }),
206        ("1_6", quote! { relative(1./6.) }),
207        ("5_6", quote! { relative(5./6.) }),
208        ("1_12", quote! { relative(1./12.) }),
209        // ("screen_50", quote! { DefiniteLength::Vh(50.0) }),
210        // ("screen_75", quote! { DefiniteLength::Vh(75.0) }),
211        // ("screen", quote! { DefiniteLength::Vh(100.0) }),
212    ]
213}
214
215fn corner_prefixes() -> Vec<(&'static str, Vec<TokenStream2>)> {
216    vec![
217        (
218            "rounded",
219            vec![
220                quote! { corner_radii.top_left },
221                quote! { corner_radii.top_right },
222                quote! { corner_radii.bottom_right },
223                quote! { corner_radii.bottom_left },
224            ],
225        ),
226        (
227            "rounded_t",
228            vec![
229                quote! { corner_radii.top_left },
230                quote! { corner_radii.top_right },
231            ],
232        ),
233        (
234            "rounded_b",
235            vec![
236                quote! { corner_radii.bottom_left },
237                quote! { corner_radii.bottom_right },
238            ],
239        ),
240        (
241            "rounded_r",
242            vec![
243                quote! { corner_radii.top_right },
244                quote! { corner_radii.bottom_right },
245            ],
246        ),
247        (
248            "rounded_l",
249            vec![
250                quote! { corner_radii.top_left },
251                quote! { corner_radii.bottom_left },
252            ],
253        ),
254        ("rounded_tl", vec![quote! { corner_radii.top_left }]),
255        ("rounded_tr", vec![quote! { corner_radii.top_right }]),
256        ("rounded_bl", vec![quote! { corner_radii.bottom_left }]),
257        ("rounded_br", vec![quote! { corner_radii.bottom_right }]),
258    ]
259}
260
261fn corner_suffixes() -> Vec<(&'static str, TokenStream2)> {
262    vec![
263        ("none", quote! { pixels(0.) }),
264        ("sm", quote! { rems(0.125) }),
265        ("md", quote! { rems(0.25) }),
266        ("lg", quote! { rems(0.5) }),
267        ("xl", quote! { rems(0.75) }),
268        ("2xl", quote! { rems(1.) }),
269        ("3xl", quote! { rems(1.5) }),
270        ("full", quote! {  pixels(9999.) }),
271    ]
272}
273
274fn border_prefixes() -> Vec<(&'static str, Vec<TokenStream2>)> {
275    vec![
276        (
277            "border",
278            vec![
279                quote! { border_widths.top },
280                quote! { border_widths.right },
281                quote! { border_widths.bottom },
282                quote! { border_widths.left },
283            ],
284        ),
285        ("border_t", vec![quote! { border_widths.top }]),
286        ("border_b", vec![quote! { border_widths.bottom }]),
287        ("border_r", vec![quote! { border_widths.right }]),
288        ("border_l", vec![quote! { border_widths.left }]),
289        (
290            "border_x",
291            vec![
292                quote! { border_widths.left },
293                quote! { border_widths.right },
294            ],
295        ),
296        (
297            "border_y",
298            vec![
299                quote! { border_widths.top },
300                quote! { border_widths.bottom },
301            ],
302        ),
303    ]
304}
305
306fn border_suffixes() -> Vec<(&'static str, TokenStream2)> {
307    vec![
308        ("", quote! { pixels(1.) }),
309        ("0", quote! { pixels(0.) }),
310        ("1", quote! { pixels(1.) }),
311        ("2", quote! { pixels(2.) }),
312        ("3", quote! { pixels(3.) }),
313        ("4", quote! { pixels(4.) }),
314        ("5", quote! { pixels(5.) }),
315        ("6", quote! { pixels(6.) }),
316        ("7", quote! { pixels(7.) }),
317        ("8", quote! { pixels(8.) }),
318        ("9", quote! { pixels(9.) }),
319        ("10", quote! { pixels(10.) }),
320        ("11", quote! { pixels(11.) }),
321        ("12", quote! { pixels(12.) }),
322        ("16", quote! { pixels(16.) }),
323        ("20", quote! { pixels(20.) }),
324        ("24", quote! { pixels(24.) }),
325        ("32", quote! { pixels(32.) }),
326    ]
327}