nf-icons 0.1.0

Compile-time Nerd Font glyph lookup proc-macro.
Documentation
#![doc = include_str!("../README.md")]

use proc_macro::TokenStream;
use quote::quote;
use syn::LitStr;
use syn::parse_macro_input;

include!(concat!(env!("OUT_DIR"), "/glyphs.rs"));

/// Look up a Nerd Font glyph by its cheat-sheet name.
///
/// ```
/// use nf_icons::nf;
/// assert_eq!(nf!("nf-fa-xmark"), "\u{f00d}");
/// ```
#[proc_macro]
pub fn nf(input: TokenStream) -> TokenStream {
    let glyph_name = parse_macro_input!(input as LitStr).value();

    if let Some(&glyph) = GLYPHS.get(glyph_name.as_str()) {
        quote!(#glyph)
    } else {
        let mut message = format!("Unknown Nerd Font glyph `{glyph_name}`.");

        let mut candidates =
            GLYPHS
                .keys()
                .map(|&key| (strsim::jaro_winkler(&glyph_name, key), key))
                .filter(|&(score, _)| score > 0.75)
                .collect::<Vec<_>>();
        candidates.sort_by(|a, b| f64::total_cmp(&b.0, &a.0));

        let suggestions =
            candidates
                .into_iter()
                .take(3)
                .map(|(_, candidate)| format!("`{candidate}`"))
                .collect::<Vec<_>>();

        if !suggestions.is_empty() {
            message.push_str(" Did you mean one of: ");
            message.push_str(&suggestions.join(", "));
            message.push('?');
        }

        quote!(compile_error!(#message))
    }.into()
}