diff --git a/src/commands/groceries.rs b/src/commands/groceries.rs index 4eb1062..5ee2536 100644 --- a/src/commands/groceries.rs +++ b/src/commands/groceries.rs @@ -131,10 +131,7 @@ fn prepare_grocery_list(ingredients: &Vec<(Ingredient, Vec)>) -> Result< )?; writeln!(out)?; // leave an empty line for (ingredient, recipes) in ingredients { - writeln!(out, "- [ ] {}", ingredient)?; - for recipe in recipes { - writeln!(out, " * {}", recipe)?; - } + writeln!(out, "- [ ] {} ({})", ingredient, recipes.join(", "))?; } Ok(out) diff --git a/src/recipe.rs b/src/recipe.rs index 275101c..d229d65 100644 --- a/src/recipe.rs +++ b/src/recipe.rs @@ -159,7 +159,7 @@ impl<'de> serde::de::Visitor<'de> for IngredientVisitor { where E: serde::de::Error, { - use std::cmp::min; + use std::cmp::{max, min}; let quantity_regex_start: regex::Regex = regex::Regex::new(r"^(?P[0-9,\.]+)\s*(?P\w+)?\s+(?P.*)").unwrap(); @@ -170,20 +170,26 @@ impl<'de> serde::de::Visitor<'de> for IngredientVisitor { .captures(value) .or_else(|| quantity_regex_end.captures(value)) { - let v = captures.name("v").unwrap().as_str(); + let vm = captures.name("v").unwrap(); + let v = vm.as_str(); let um = captures.name("u"); let u = um.map(|u| u.as_str()).unwrap_or(""); let im = captures.name("i").unwrap(); let i = im.as_str(); - let (amount, unit) = Self::parse_quantity(v, u)?; + let (mut amount, unit) = Self::parse_quantity(v, u)?; let name = match unit { Unit::None => { // pick the longest string including what was recognized by the regex as the possible unit - let start = um - .map(|um| min(um.start(), im.start())) - .unwrap_or_else(|| im.start()); - &value[start..im.end()] + let range = um + .map(|um| min(um.start(), im.start())..max(um.end(), im.end())) + .unwrap_or_else(|| im.start()..im.end()); + + if range.start <= vm.start() && range.end >= vm.end() { + amount = 1.0; // e.g. for "Parsley, 5 leaves" -> Ingredient { 1, no unit, 'Parsley, 5 leaves' } + } + + &value[range] } _ => i, } @@ -218,7 +224,7 @@ impl IngredientVisitor { v = v / 1000.0; Unit::Kilogram } - "hg" => { + "hg" | "etto" | "etti" => { v = v / 10.0; Unit::Kilogram } @@ -231,15 +237,15 @@ impl IngredientVisitor { v = v / 100.0; Unit::Liter } - "ml" => { + "ml" | "cc" => { v = v / 1000.0; Unit::Liter } - "tl" => { + "tl" | "cucchiaino" | "cucchiaini" => { v = v / 1000.0 * 5.0; Unit::Liter } - "el" => { + "el" | "cucchiaio" | "cucchiai" => { v = v / 1000.0 * 15.0; Unit::Liter } @@ -260,12 +266,19 @@ impl IngredientVisitor { impl core::fmt::Display for Ingredient { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + const PRECISION: u32 = 3; + const ROUNDING_EXP: f64 = 10isize.pow(PRECISION) as f64; + write!( f, - "{amount:.3}{unit} {name}", + "{amount}{pad}{unit} {name}", name = self.name, - amount = self.amount, - unit = self.unit + amount = (self.amount * ROUNDING_EXP).round() / ROUNDING_EXP, + pad = match self.unit { + Unit::None => "", + _ => " ", + }, + unit = self.unit, ) } }