diff --git a/Cargo.lock b/Cargo.lock index f5694ba..2a51e1b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -332,6 +332,12 @@ dependencies = [ "hashbrown", ] +[[package]] +name = "heck" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" + [[package]] name = "hermit-abi" version = "0.1.19" @@ -784,6 +790,12 @@ dependencies = [ "smallvec", ] +[[package]] +name = "rustversion" +version = "1.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4f3208ce4d8448b3f3e7d168a73f5e0c43a61e32930de3bceeccedb388b6bf06" + [[package]] name = "ryu" version = "1.0.12" @@ -864,6 +876,25 @@ version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" +[[package]] +name = "strum" +version = "0.24.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "063e6045c0e62079840579a7e47a355ae92f60eb74daaf156fb1e84ba164e63f" + +[[package]] +name = "strum_macros" +version = "0.24.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e385be0d24f186b4ce2f9982191e7101bb737312ad61c1f2f984f34bcf85d59" +dependencies = [ + "heck", + "proc-macro2", + "quote", + "rustversion", + "syn", +] + [[package]] name = "syn" version = "1.0.107" @@ -954,6 +985,8 @@ dependencies = [ "serde", "serde_json", "serde_yaml", + "strum", + "strum_macros", "tempfile", "textwrap 0.14.2", "thiserror", diff --git a/Cargo.toml b/Cargo.toml index b7f6e60..073db57 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -30,6 +30,8 @@ serde_json = "1.0" hostname = "0.3" atty = "0.2" timeago = "0.3" +strum = "0.24" +strum_macros = "0.24" [dependencies.clap] version = "3" diff --git a/src/formatters.rs b/src/formatters.rs index 36503aa..2a42979 100644 --- a/src/formatters.rs +++ b/src/formatters.rs @@ -7,6 +7,9 @@ use crate::error; use crate::models::Entry; use crate::commands::Facts; +use strum_macros::{EnumVariantNames}; +use strum::VariantNames; + pub mod text; pub mod csv; pub mod json; @@ -15,8 +18,9 @@ pub mod ical; pub mod custom; pub mod chart; -#[derive(Debug, Clone, Serialize, Deserialize)] +#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, EnumVariantNames)] #[serde(rename_all = "lowercase")] +#[strum(serialize_all = "kebab_case")] pub enum Formatter { Text, Csv, @@ -57,6 +61,21 @@ impl Formatter { Ok(()) } + + /// Gets Formatter from prefix + /// + /// from Formatter variants try to match with starts_with. + /// Returns error if it doesn't match. + pub fn autocomplete(s: &str) -> error::Result { + if s.len() > 0 { + for formatter in Formatter::VARIANTS { + if formatter.starts_with(s) { + return Formatter::from_str(formatter) + } + } + } + Err(error::Error::InvalidAutocompleteFormatter(s.to_string())) + } } impl FromStr for Formatter { @@ -80,40 +99,22 @@ mod tests { use super::*; - fn autocomplete(s: &str) -> error::Result { - let formatters = vec!["text", "csv", "json", "ids", "ical", "chart"]; - if s.len() > 1 { - for formatter in formatters { - if formatter.contains(s) { - return Formatter::from_str(formatter) - } - } - } - Err(error::Error::InvalidAutocompleteFormatter(s.to_string())) + #[test] + fn valid_autocomplete() { + let format = Formatter::autocomplete("t"); + assert_eq!(format.unwrap(), Formatter::Text); } #[test] - fn valid_autocomplete_starts_with() { - let format = autocomplete("tex"); - assert!(format.is_ok()); + fn invalid_autocomplete() { + let format = Formatter::autocomplete("fail"); + assert!(matches!(format, Err(error::Error::InvalidAutocompleteFormatter(_)))); } #[test] - fn valid_autocomplete_contains() { - let format = autocomplete("sv"); - assert!(format.is_ok()); - } - - #[test] - fn invalid_autocomplete_to_short() { - let format = autocomplete("s"); - assert!(format.is_err()); - } - - #[test] - fn invalid_autocomplete_does_not_contains() { - let format = autocomplete("fail"); - assert!(format.is_err()); + fn invalid_autocomplete_empty() { + let format = Formatter::autocomplete(""); + assert!(matches!(format, Err(error::Error::InvalidAutocompleteFormatter(_)))); } // TODO: autocomplete for custom formatter