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