mevy_ui/
lib.rs

1use deki::*;
2use mevy_ui_syntax::*;
3use proc_macro::TokenStream as CompilerTokens;
4
5// Macro \\
6
7    /// Provides CSS-like syntax to either edit or create bevy_ui components.
8    ///
9    /// ## Available fields
10    /// To see a full list of built-in fields, see readme of mevy_ui, here are some examples:
11    /// ```rust 
12    /// cmd.spawn(ui!((
13    ///     size: 50px 50px;
14    ///     background: #ff0000;
15    ///     box_shadow: 0px 0px 5px 5px #ff0000;
16    ///     border: 5px #00ff00;
17    /// )));
18    /// ```
19    /// The same, but 'slim':
20    /// ```rust
21    /// cmd.spawn(ui!( w:50 h:50 bg:#f00 shadow:0+0+5+5#f00 border:5#0f0 ));
22    /// ```
23    ///
24    /// ## Possible Modes
25    /// Depending on the delimiters & if there is a name defined, the function of this macro differs:
26    /// - 'Slim' Inline Tuple Mode | `ui!{ w:8 h:8 l:2 t:2 }`
27    ///     - returns a tuple of mentioned UI components
28    /// - Inline Tuple Mode | `ui!{( width: 1px; )}`:
29    ///     - returns a tuple of mentioned UI components
30    /// - Function Tuple Mode | `ui!{func_name( width: 1px; )}`: 
31    ///     - defines a function that returns a tuple of mentioned UI components
32    ///     - these can then be used as fields like this: `ui!{( func_name; )}`
33    /// - Function Edit Mode | `ui!{func_name{ width: 2px; }}`
34    ///     - defines a function, that edits mentioned UI components
35    ///     - the parameters of this function = the needed mutable components
36    ///     - using `_` will keep the original values: e.g. `border:  _ #ff0000;`
37    /// 
38    /// ## Custom Fields
39    /// Every function that returns any `Bundle` (even if it is just -> `impl Bundle`) can be used
40    /// as custom field.
41    #[proc_macro]
42    pub fn ui (tok:CompilerTokens) -> CompilerTokens {
43        let tok: TokenStream = tok.into();
44        let mut iter = tok.peek_iter();
45    
46        match iter.peek().unwrap() {
47            TokenTree::Ident(ident) if ident.to_string().chars().next().unwrap().is_lowercase() => {
48                let ident = iter.next().unwrap().unwrap_ident();
49                match iter.peek().unwrap() {
50                    TokenTree::Group(g) if g.delimiter().is_parenthesis() => {
51                        let g = iter.next().unwrap().unwrap_group();
52                        let bundle = bundle(g.stream().peek_iter(),iter.next());
53                        qt!{pub fn #ident () -> impl Bundle {#bundle}}
54                    }
55                    TokenTree::Group(g) if g.delimiter().is_brace() => {
56                        let g = iter.next().unwrap().unwrap_group();
57                        let prep = UiPrep::from_stream(g.stream(),false,|a,_|a.is_punct(';'));
58                        let (expected,edits) = prep.get_edits();
59                        let attr = expected.into_iter()
60                            .map(|(v,t)|qt!(#v: &mut #t))
61                            .collect::<Vec<_>>();
62                        qt!{pub fn #ident (#(#attr),*) {#edits}}
63                    }
64                    _ => {
65                        let aa = qt![#ident #(#iter)*];
66                        bundle_slim(aa.peek_iter(),None)
67                    }
68                }
69            }
70
71            TokenTree::Group(_) => {
72                kill!{*Some(TokenTree::Group(group)) = iter.next()}
73                match group.delimiter() {
74                    Delimiter::Parenthesis => bundle(group.stream().peek_iter(),iter.next()),
75                    Delimiter::Bracket => bundle_slim(group.stream().peek_iter(),iter.next()),
76                    _ => todo!{}
77                }
78            }
79
80            _ => bundle_slim(iter,None),
81
82        }.into()
83    }
84
85
86// EOF \\