diff options
Diffstat (limited to 'crates/starship_module_config_derive')
-rw-r--r-- | crates/starship_module_config_derive/Cargo.toml | 25 | ||||
-rw-r--r-- | crates/starship_module_config_derive/LICENSE | 15 | ||||
-rw-r--r-- | crates/starship_module_config_derive/README.md | 1 | ||||
-rw-r--r-- | crates/starship_module_config_derive/src/lib.rs | 90 |
4 files changed, 131 insertions, 0 deletions
diff --git a/crates/starship_module_config_derive/Cargo.toml b/crates/starship_module_config_derive/Cargo.toml new file mode 100644 index 000000000..928eef5f6 --- /dev/null +++ b/crates/starship_module_config_derive/Cargo.toml @@ -0,0 +1,25 @@ +[package] +name = "starship_module_config_derive" +version = "0.2.1" +edition = "2018" +authors = ["Matan Kushner <hello@matchai.me>"] +homepage = "https://starship.rs" +documentation = "https://starship.rs/guide/" +repository = "https://github.com/starship/starship" +readme = "README.md" +license = "ISC" +keywords = ["prompt", "shell", "bash", "fish", "zsh"] +categories = ["command-line-utilities"] +description = """ +The minimal, blazing-fast, and infinitely customizable prompt for any shell! ☄🌌️ +""" +include = ["src/**/*", "LICENSE", "README.md"] + +[lib] +name = "starship_module_config_derive" +proc-macro = true + +[dependencies] +proc-macro2 = "~1" +quote = "~1" +syn = "~1" diff --git a/crates/starship_module_config_derive/LICENSE b/crates/starship_module_config_derive/LICENSE new file mode 100644 index 000000000..1ce6f8232 --- /dev/null +++ b/crates/starship_module_config_derive/LICENSE @@ -0,0 +1,15 @@ +ISC License + +Copyright (c) 2019, Starship Contributors + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. diff --git a/crates/starship_module_config_derive/README.md b/crates/starship_module_config_derive/README.md new file mode 100644 index 000000000..b1a0ca9ee --- /dev/null +++ b/crates/starship_module_config_derive/README.md @@ -0,0 +1 @@ +# starship_module_config_derive diff --git a/crates/starship_module_config_derive/src/lib.rs b/crates/starship_module_config_derive/src/lib.rs new file mode 100644 index 000000000..40d4301b9 --- /dev/null +++ b/crates/starship_module_config_derive/src/lib.rs @@ -0,0 +1,90 @@ +use proc_macro::TokenStream; +use quote::quote; +use syn::{parse_macro_input, DeriveInput}; + +#[proc_macro_derive(ModuleConfig)] +pub fn derive_module_config(input: TokenStream) -> TokenStream { + let dinput = parse_macro_input!(input as DeriveInput); + impl_module_config(dinput) +} + +fn impl_module_config(dinput: DeriveInput) -> proc_macro::TokenStream { + let struct_ident = &dinput.ident; + let (_impl_generics, ty_generics, where_clause) = dinput.generics.split_for_impl(); + + let mut from_config = quote! {}; + let mut load_config = quote! {}; + + if let syn::Data::Struct(data) = dinput.data { + if let syn::Fields::Named(fields_named) = data.fields { + let mut load_tokens = quote! {}; + let mut fields = quote! {}; + + for field in fields_named.named.iter() { + let ident = field.ident.as_ref().unwrap(); + + let new_load_tokens = quote! { + stringify!(#ident) => self.#ident.load_config(v), + }; + + let new_field = quote! { + stringify!(#ident), + }; + + load_tokens = quote! { + #load_tokens + #new_load_tokens + }; + + fields = quote! { + #fields + #new_field + }; + } + + load_config = quote! { + fn load_config(&mut self, config: &'a toml::Value) { + if let toml::Value::Table(config) = config { + config.iter().for_each(|(k, v)| { + match k.as_str() { + #load_tokens + unknown => { + ::log::warn!("Unknown config key '{}'", unknown); + + let did_you_mean = ::std::array::IntoIter::new([#fields]) + .filter_map(|field| { + let score = ::strsim::jaro_winkler(unknown, field); + (score > 0.8).then(|| (score, field)) + }) + .max_by( + |(score_a, _field_a), (score_b, _field_b)| { + score_a.partial_cmp(score_b).unwrap_or(::std::cmp::Ordering::Equal) + }, + ); + + if let Some((_score, field)) = did_you_mean { + ::log::warn!("Did you mean '{}'?", field); + } + }, + } + }); + } + } + }; + from_config = quote! { + fn from_config(config: &'a toml::Value) -> Option<Self> { + let mut out = Self::default(); + out.load_config(config); + Some(out) + } + }; + } + } + + TokenStream::from(quote! { + impl<'a> ModuleConfig<'a> for #struct_ident #ty_generics #where_clause { + #from_config + #load_config + } + }) +} |