tabler-dominator 0.1.0

Tabler icons for Dominator
Documentation
use std::{collections::HashMap, path::Path, sync::Mutex};

use lazy_static::lazy_static;
use proc_macro::TokenStream;
use quote::{quote, quote_spanned};

lazy_static! {
    static ref ICONS: Mutex<HashMap<String, String>> = Mutex::new(HashMap::new());
}

#[proc_macro]
pub fn icon(item: TokenStream) -> TokenStream {
    icon_impl(item).unwrap_or_else(|e| e)
}

fn icon_impl(item: TokenStream) -> Result<TokenStream, TokenStream> {
    let item = item.into_iter().next().expect("No icon specified");
    let input = item
        .to_string()
        .strip_prefix('"')
        .expect("No leading quote?")
        .strip_suffix('"')
        .expect("No trailing quote?")
        .to_string();

    if !ICONS.lock().unwrap().contains_key(&input) {
        let path = Path::new(file!().strip_suffix("lib.rs").unwrap())
            .join("../svg/")
            .join(&format!("{input}.svg"))
            .canonicalize()
            .unwrap();

        let file = std::fs::read(path).map_err(|_| {
            return quote_spanned! {
                item.span().into() =>
                compile_error!("Invalid Tabler Icon");
            };
        })?;

        ICONS
            .lock()
            .unwrap()
            .insert(input.clone(), String::from_utf8_lossy(&file).to_string());
    }

    let icon = ICONS.lock().unwrap();
    let icon = icon.get(&input).unwrap();
    let exp = quote! {
        html!("svg", { .with_node!(e => {
                .apply(|d| {
                    e.set_outer_html(#icon);
                    d
                })
            })
        })
    };

    Ok(exp.into())
}