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}