summaryrefslogtreecommitdiffstats
path: root/crates/starship_module_config_derive
diff options
context:
space:
mode:
Diffstat (limited to 'crates/starship_module_config_derive')
-rw-r--r--crates/starship_module_config_derive/Cargo.toml25
-rw-r--r--crates/starship_module_config_derive/LICENSE15
-rw-r--r--crates/starship_module_config_derive/README.md1
-rw-r--r--crates/starship_module_config_derive/src/lib.rs90
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
+ }
+ })
+}