1#![feature(proc_macro_diagnostic)]
6#![feature(proc_macro_span)]
7extern crate fasthash;
8extern crate proc_macro;
9
10mod core;
11mod css_use_impl;
12
13use crate::core::name_mangler::mangle;
14use crate::core::parse::parse_rustyle;
15use lazy_static::lazy_static;
16use proc_macro::{Span, TokenStream};
17use quote::quote;
18use std::error::Error;
19use std::sync::{Arc, Mutex};
20lazy_static! {
21 static ref CSS_ID: Arc<Mutex<u32>> = Arc::new(Mutex::new(0));
22 static ref OUTPUT: String = std::env::var("RUSTYLE_OUTPUT").unwrap_or(String::from("./rustyle"));
23}
24
25#[proc_macro]
53pub fn rustyle(input: TokenStream) -> TokenStream {
54 let mut id = CSS_ID.lock().unwrap();
55
56 let mut result = String::new();
57
58 let class_name = mangle(
59 &input
60 .clone()
61 .into_iter()
62 .map(|token| token.to_string())
63 .collect::<String>(),
64 );
65
66 for node in parse_rustyle(input) {
67 result.push_str(&node.generate_code(&class_name));
68 }
69
70 let file_name = format!("rustyle.{}.css", *id);
71
72 let string_path = format!("{}/{}", OUTPUT.as_str(), file_name);
73 let path = std::path::Path::new(&string_path);
74
75 if *id == 0 && std::fs::metadata(path.parent().unwrap()).is_ok() {
76 if let Err(err) = std::fs::remove_dir_all(path.parent().unwrap()) {
77 Span::call_site()
78 .warning(format!("couldn't empty the folder: {}", err))
79 .emit();
80 }
81 }
82
83 if let Err(err) = std::fs::create_dir_all(path.parent().unwrap()) {
84 Span::call_site()
85 .error(format!("couldn't create the folder: {}", err))
86 .emit();
87 return (quote! {}).into();
88 }
89
90 let mut file = match std::fs::File::create(path) {
91 Err(err) => {
92 Span::call_site()
93 .error(format!("couldn't create the file: {}", err))
94 .emit();
95 return (quote! {}).into();
96 }
97 Ok(file) => file,
98 };
99
100 match std::io::Write::write_all(&mut file, result.as_bytes()) {
101 Err(err) => {
102 Span::call_site()
103 .error(format!(
104 "couldn't write to {}: {}",
105 path.to_str().unwrap(),
106 err.description()
107 ))
108 .emit();
109 }
110 Ok(_) => {}
111 }
112
113 *id += 1;
114
115 let expanded = quote! { #class_name };
116
117 expanded.into()
118}
119
120#[proc_macro]
138pub fn css(input: TokenStream) -> TokenStream {
139 rustyle(input)
140}
141
142#[proc_macro_attribute]
160pub fn css_use(attr: TokenStream, item: TokenStream) -> TokenStream {
161 if !attr.is_empty() {
162 Span::call_site().error("Unexpected parameters").emit();
163 item
164 } else {
165 css_use_impl::css_use_impl(item)
166 }
167}