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}