#![feature(proc_macro_diagnostic)]
#![feature(proc_macro_span)]
extern crate fasthash;
extern crate proc_macro;
mod core;
mod css_use_impl;
use crate::core::name_mangler::mangle;
use crate::core::parse::parse_rustyle;
use lazy_static::lazy_static;
use proc_macro::{Span, TokenStream};
use quote::quote;
use std::error::Error;
use std::sync::{Arc, Mutex};
lazy_static! {
static ref CSS_ID: Arc<Mutex<u32>> = Arc::new(Mutex::new(0));
static ref OUTPUT: String = std::env::var("RUSTYLE_OUTPUT").unwrap_or(String::from("./rustyle"));
}
#[proc_macro]
pub fn rustyle(input: TokenStream) -> TokenStream {
let mut id = CSS_ID.lock().unwrap();
let mut result = String::new();
let class_name = mangle(
&input
.clone()
.into_iter()
.map(|token| token.to_string())
.collect::<String>(),
);
for node in parse_rustyle(input) {
result.push_str(&node.generate_code(&class_name));
}
let file_name = format!("rustyle.{}.css", *id);
let string_path = format!("{}/{}", OUTPUT.as_str(), file_name);
let path = std::path::Path::new(&string_path);
if *id == 0 && std::fs::metadata(path.parent().unwrap()).is_ok() {
if let Err(err) = std::fs::remove_dir_all(path.parent().unwrap()) {
Span::call_site()
.warning(format!("couldn't empty the folder: {}", err))
.emit();
}
}
if let Err(err) = std::fs::create_dir_all(path.parent().unwrap()) {
Span::call_site()
.error(format!("couldn't create the folder: {}", err))
.emit();
return (quote! {}).into();
}
let mut file = match std::fs::File::create(path) {
Err(err) => {
Span::call_site()
.error(format!("couldn't create the file: {}", err))
.emit();
return (quote! {}).into();
}
Ok(file) => file,
};
match std::io::Write::write_all(&mut file, result.as_bytes()) {
Err(err) => {
Span::call_site()
.error(format!(
"couldn't write to {}: {}",
path.to_str().unwrap(),
err.description()
))
.emit();
}
Ok(_) => {}
}
*id += 1;
let expanded = quote! { #class_name };
expanded.into()
}
#[proc_macro]
pub fn css(input: TokenStream) -> TokenStream {
rustyle(input)
}
#[proc_macro_attribute]
pub fn css_use(attr: TokenStream, item: TokenStream) -> TokenStream {
if !attr.is_empty() {
Span::call_site().error("Unexpected parameters").emit();
item
} else {
css_use_impl::css_use_impl(item)
}
}