promkit-derive 0.2.0

A derive macro for promkit
Documentation
use proc_macro2::TokenStream;
use quote::{quote, ToTokens};
use syn::{parse::Error, punctuated::Punctuated, spanned::Spanned, Meta, MetaNameValue, Token};

pub fn create_state(attr: &syn::Attribute) -> Result<TokenStream, Error> {
    let mut prefix = quote! { String::from("❯❯ ") };
    let mut prefix_style = quote! {
        promkit::core::crossterm::style::ContentStyle {
            attributes: promkit::core::crossterm::style::Attributes::from(promkit::core::crossterm::style::Attribute::Bold),
            ..Default::default()
        }
    };
    let mut active_char_style = quote! {
        promkit::core::crossterm::style::ContentStyle {
            background_color: Some(promkit::core::crossterm::style::Color::DarkCyan),
            ..Default::default()
        }
    };
    let mut inactive_char_style = quote! {
        promkit::core::crossterm::style::ContentStyle::default()
    };
    let mut mask = quote! { None::<char> };
    let mut edit_mode = quote! { promkit::widgets::text_editor::Mode::default() };
    let mut word_break_chars = quote! { std::collections::HashSet::from([' ']) };

    match &attr.meta {
        Meta::List(list) => {
            if list.tokens.to_string() != "default" {
                list.parse_args_with(Punctuated::<MetaNameValue, Token![,]>::parse_terminated)
                    .map_err(|e| {
                        Error::new(
                            list.span(),
                            format!(
                                "Support form(key=value, ...) but got {}, caused error: {}",
                                list.tokens, e
                            ),
                        )
                    })?
                    .into_iter()
                    .for_each(
                        |entry| match entry.path.get_ident().unwrap().to_string().as_str() {
                            "label" => {
                                let expr = entry.value;
                                prefix = quote! { format!("{} ", #expr) };
                            }
                            "label_style" => {
                                let expr = entry.value;
                                prefix_style = quote! { #expr };
                            }
                            "active_char_style" => {
                                let expr = entry.value;
                                active_char_style = quote! { #expr };
                            }
                            "inactive_char_style" => {
                                let expr = entry.value;
                                inactive_char_style = quote! { #expr };
                            }
                            "mask" => {
                                let expr = entry.value;
                                mask = quote! { #expr };
                            }
                            "edit_mode" => {
                                let expr = entry.value;
                                edit_mode = quote! { #expr };
                            }
                            "word_break_chars" => {
                                let expr = entry.value;
                                word_break_chars = quote! { #expr };
                            }
                            _ => (),
                        },
                    );
            }
        }
        others => {
            return Err(Error::new(
                others.span(),
                format!(
                    "Support only form, form(default), or form(key=value, ...), but got {}",
                    others.to_token_stream()
                ),
            ))
        }
    };

    Ok(quote! {
        promkit::widgets::text_editor::State {
            texteditor: Default::default(),
            history: Default::default(),
            prefix: #prefix,
            prefix_style: #prefix_style,
            active_char_style: #active_char_style,
            inactive_char_style: #inactive_char_style,
            mask: #mask,
            edit_mode: #edit_mode,
            word_break_chars: #word_break_chars,
            lines: Default::default()
        }
    })
}