1#[feature(proc_macro)]
6#[macro_use]
7extern crate syn;
8#[macro_use]
9extern crate quote;
10#[macro_use]
11extern crate lazy_static;
12extern crate proc_macro;
13
14use syn::Expr;
15
16use proc_macro::TokenStream;
17use proc_macro::TokenTree;
18
19use std::env;
20use std::fs;
21use std::fs::File;
22use std::fs::OpenOptions;
23use std::io::Write;
24use std::path::Path;
25use std::sync::Mutex;
26
27lazy_static! {
28 static ref CSS_COUNTER: Mutex<u32> = Mutex::new(0);
29}
30
31#[proc_macro]
71pub fn css(input: TokenStream) -> TokenStream {
72 let mut css_counter = CSS_COUNTER.lock().unwrap();
73
74 let class = format!("_css_rs_{}", css_counter);
75
76 let css_file = env::vars().find(|(key, _)| key == "OUTPUT_CSS");
77
78 if css_file.is_some() {
79 let css_file = css_file.unwrap().1;
80
81 if *css_counter == 0 {
82 if Path::new(&css_file).exists() {
83 fs::remove_file(&css_file).unwrap();
84 }
85
86 let mut css_file = OpenOptions::new()
87 .write(true)
88 .create_new(true)
89 .open(css_file)
90 .unwrap();
91
92 write_css_to_file(&mut css_file, &class, input);
93 } else {
94 let mut css_file = OpenOptions::new().append(true).open(css_file).unwrap();
95
96 write_css_to_file(&mut css_file, &class, input);
97 }
98 }
99
100 *css_counter += 1;
101
102 let expanded = quote! {
103 #class
104 };
105
106 expanded.into()
107}
108
109fn write_css_to_file(css_file: &mut File, class: &str, input: TokenStream) {
110 for css in input.into_iter() {
111 let mut css = css.to_string();
112
113 let first_quote_mark = css.find(r#"""#).unwrap();
121 let last_quote_mark = css.rfind(r#"""#).unwrap();
122 css.truncate(last_quote_mark);
123 let mut css = css.split_off(first_quote_mark + 1);
124
125 let css = css.replace(":host", &format!(".{}", class));
128
129 css_file.write(&css.into_bytes()).unwrap();
130 css_file.write("\n".as_bytes()).unwrap();
131 }
132}