herms 1.9.0.0 → 1.9.0.2
raw patch · 8 files changed
+157/−33 lines, 8 filesdep ~semigroups
Dependency ranges changed: semigroups
Files
- README.md +8/−8
- app/herms.hs +20/−4
- herms.cabal +3/−2
- src/AddCLI.hs +18/−18
- src/Lang/French.hs +86/−0
- src/Lang/Strings.hs +3/−0
- src/ReadConfig.hs +17/−0
- src/Types.hs +2/−1
README.md view
@@ -19,11 +19,11 @@ - Import recipe files - Generate shopping lists - Keep track of recipes with tags-- Set default unit systems, serving sizes, and recipe file path in ``config.hs``+- Set default unit systems, serving sizes, language, and recipe file path in ``config.hs`` ### What's new:-- Yarr! Herm's now supports both English and Pirate! Simply make it ``language = "pirate"`` in your ``config.hs``!-- "Pirate" is but the first language that Herm's is now capable of supporting. We need your help to translate it into others! Currently in progress: Português, Español +- Bonjour! Herm's now has language support for Français (French), English, and Pirate. Set your language preferences in ``config.hs``!+- These are but the first languages that Herm's is now capable of supporting. We need your help to translate it into others! Currently in progress: Português (Portuguese), Español (Spanish) ### Installation @@ -49,7 +49,7 @@ ##### Via Hackage and Cabal: -_Note_: Your milage may vary with dependency resolution+_Note_: Your mileage may vary with dependency resolution ``` cabal update@@ -58,8 +58,6 @@ ##### Manually with Cabal: -_Note_: Your milage may vary with dependency resolution- ``` git clone https://github.com/JackKiefer/herms cd herms@@ -86,6 +84,8 @@ herms edit RECIPE_NAME edit a recipe herms import FILE_NAME import a recipe file+ + herms export DESTINATION export recipes to DESTINATION herms remove RECIPE_NAMES remove the particular recipes @@ -131,8 +131,8 @@ - `defaultUnit` : The default unit system to show recipes in. Options: `Imperial`, `Metric`, `None`. Setting to `None` will simply show recipes in whatever unit system they're stored in. - `defaultServingSize` : Default serving size to calculate when showing recipes. Can be any non-negative integer; set to `0` for no default. This can be useful when you're always cooking for the same number of people!-- `recipesFile` : The recipes file to use. This option currently supports relative (but not absolute) location, as well; if your data directory is `~/herms/data`, for example, and you want a recipe file in your home directoy called `~/GrandmasHugeCookbook.herms`, set this option to `"../../GrandmasHugeCookbook.herms"`.-- `language` : Human language to use. Currently supported: ``"english"``, ``"pirate"``+- `recipesFile` : The recipes file to use. This option currently supports relative (but not absolute) location, as well; if your data directory is `~/herms/data`, for example, and you want a recipe file in your home directory called `~/GrandmasHugeCookbook.herms`, set this option to `"../../GrandmasHugeCookbook.herms"`.+- `language` : Human language to use. Currently supported: ``"Français"``, ``"English"``, ``"Pirate"`` ---
app/herms.hs view
@@ -11,6 +11,7 @@ import Data.List import Data.Maybe import Data.Semigroup ((<>))+import Data.String (IsString(..)) import Data.Ratio import Control.Applicative import Options.Applicative hiding (str)@@ -29,7 +30,7 @@ -- Global constants versionStr :: String-versionStr = "1.9.0.0"+versionStr = "1.9.0.2" configPath :: IO FilePath configPath = getDataFileName "config.hs"@@ -75,7 +76,7 @@ saveOrDiscard input oldRecp add :: HermsReader IO ()-add = do +add = do (config, recipeBook) <- ask input <- liftIO $ getAddInput (translator config) saveOrDiscard input Nothing@@ -93,7 +94,7 @@ ingrs = toStr ingredientName dirs = unlines (directions recp) attrs = toStr attribute- tag = unlines (tags recp)+ tag = unwords (tags recp) edit :: String -> HermsReader IO () edit target = do@@ -128,6 +129,15 @@ forM_ otherRecipeBook $ \recipe -> putStrLn $ " " ++ recipeName recipe +export :: [String] -> HermsReader IO ()+export targets = do+ (config, recipeBook) <- ask+ let t = translator config+ liftIO $ forM_ targets $ \ target ->+ putText $ case readRecipeRef target recipeBook of+ Nothing -> target ~~ (t Str.doesNotExist)+ Just recp -> fromString $ show recp+ getServingsAndConv :: Int -> String -> Config -> (Maybe Int, Conversion) getServingsAndConv serv convName config = (servings, conv) where servings = case serv of@@ -318,6 +328,7 @@ runWithOpts Add = add runWithOpts (Edit target) = edit target runWithOpts (Import target) = importFile target+runWithOpts (Export targets) = export targets runWithOpts (Remove targets) = remove targets runWithOpts (View targets serving step conversion) = if step then viewByStep targets serving conversion@@ -336,15 +347,17 @@ | Add -- ^ adds the recipe (interactively) | Edit String -- ^ edits the recipe | Import String -- ^ imports a recipe file+ | Export [String] -- ^ exports recipes to stdout | Remove [String] -- ^ removes specified recipes | Shop [String] Int -- ^ generates the shopping list for given recipes | DataDir -- ^ prints the directory of recipe file and config.hs -listP, addP, viewP, editP, importP, shopP, dataDirP :: Translator -> Parser Command+listP, addP, viewP, editP, importP, exportP, shopP, dataDirP :: Translator -> Parser Command listP t = List <$> (words <$> (tagsP t)) <*> (groupByTagsP t) <*> (nameOnlyP t) addP _ = pure Add editP t = Edit <$> (recipeNameP t) importP t = Import <$> (fileNameP t)+exportP t = Export <$> (severalRecipesP t) removeP t = Remove <$> (severalRecipesP t) viewP t = View <$> (severalRecipesP t) <*> (servingP t) <*> (stepP t) <*> (conversionP t) shopP t = Shop <$> (severalRecipesP t) <*> (servingP t)@@ -433,6 +446,9 @@ <> command (t Str.import') (info (helper <*> importP t) (progDesc (t Str.importDesc)))+ <> command (t Str.export)+ (info (helper <*> exportP t)+ (progDesc (t Str.exportDesc))) <> command (t Str.remove) (info (helper <*> removeP t) (progDesc (t Str.removeDesc)))
herms.cabal view
@@ -16,7 +16,7 @@ -- PVP summary: +-+------- New features or improvements with significant API change -- | | +----- Bugfixes and improvements with minor change to API -- | | | +--- Bugfixes and improvements with no change to API-version: 1.9.0.0+version: 1.9.0.2 -- A short (one-line) description of the package. synopsis: A command-line manager for delicious kitchen recipes@@ -76,6 +76,7 @@ , Lang.Strings , Lang.Pirate , Lang.Portuguese+ , Lang.French -- LANGUAGE extensions used by modules in this package. other-extensions: OverloadedStrings, TemplateHaskell, RankNTypes@@ -89,7 +90,7 @@ , microlens-th >=0.4 && <0.5 , mtl >= 2.2.1 && <= 2.2.2 , optparse-applicative >=0.14 && <0.15- , semigroups >= 0.18.3 && <= 0.18.4+ , semigroups >= 0.18.3 && < 0.19 , split >=0.2 && <0.3 , vty >=5.15 && < 5.22
src/AddCLI.hs view
@@ -80,12 +80,12 @@ (str (t Str.tuiServingSize) <+> (hLimit 3 e3)) <=> str " " <=> str (t Str.tuiHeaders) <=>- (str (t Str.tuiIngrs) + (str (t Str.tuiIngrs) <+> (hLimit 7 $ vLimit 7 e4) <+> (hLimit 9 $ vLimit 7 e5) <+> (hLimit 28 $ vLimit 7 e6) <+> (hLimit 18 $ vLimit 7 e7))- <=> + <=> str " " <=> (str (t Str.tuiDirs) <+> (hLimit 62 $ vLimit 8 e8)) <=> str " " <=>@@ -102,27 +102,27 @@ V.EvKey V.KEsc [] -> M.halt st V.EvKey (V.KChar '\t') [] -> M.continue $ st & focusRing %~ F.focusNext V.EvKey V.KBackTab [] -> M.continue $ st & focusRing %~ F.focusPrev- + -- Ctrl + <Arrow Keys>- V.EvKey V.KDown [V.MCtrl] -> + V.EvKey V.KDown [V.MCtrl] -> M.continue $ st & focusRing %~ (determineNextFocus FocusDown st)- V.EvKey V.KUp [V.MCtrl] -> + V.EvKey V.KUp [V.MCtrl] -> M.continue $ st & focusRing %~ (determineNextFocus FocusUp st)- V.EvKey V.KRight [V.MCtrl] -> + V.EvKey V.KRight [V.MCtrl] -> M.continue $ st & focusRing %~ (determineNextFocus FocusRight st)- V.EvKey V.KLeft [V.MCtrl] -> + V.EvKey V.KLeft [V.MCtrl] -> M.continue $ st & focusRing %~ (determineNextFocus FocusLeft st) -- Meta + <h-j-k-l>- V.EvKey (V.KChar 'h') [V.MMeta] -> + V.EvKey (V.KChar 'h') [V.MMeta] -> M.continue $ st & focusRing %~ (determineNextFocus FocusLeft st)- V.EvKey (V.KChar 'j') [V.MMeta] -> + V.EvKey (V.KChar 'j') [V.MMeta] -> M.continue $ st & focusRing %~ (determineNextFocus FocusDown st)- V.EvKey (V.KChar 'k') [V.MMeta] -> + V.EvKey (V.KChar 'k') [V.MMeta] -> M.continue $ st & focusRing %~ (determineNextFocus FocusUp st)- V.EvKey (V.KChar 'l') [V.MMeta] -> + V.EvKey (V.KChar 'l') [V.MMeta] -> M.continue $ st & focusRing %~ (determineNextFocus FocusRight st)- + _ -> M.continue =<< case F.focusGetCurrent (st^.focusRing) of Just RecipeName -> T.handleEventLensed st edit1 E.handleEditorEvent ev Just Description -> T.handleEventLensed st edit2 E.handleEditorEvent ev@@ -137,9 +137,9 @@ appEvent st _ = M.continue st determineNextFocus :: FocusChange -> St -> F.FocusRing n -> F.FocusRing n-determineNextFocus action st = +determineNextFocus action st = case action of- FocusDown -> case currentFocus of + FocusDown -> case currentFocus of Just RecipeName -> (F.focusNext) Just Description -> (F.focusNext) Just ServingSize -> (F.focusNext)@@ -227,9 +227,9 @@ , E.getEditContents $ st^.edit5 , E.getEditContents $ st^.edit6 , E.getEditContents $ st^.edit7- , E.getEditContents $ st^.edit8 + , E.getEditContents $ st^.edit8 , E.getEditContents $ st^.edit9- ] + ] getAddInput :: Translator -> IO ([[String]]) getAddInput t = do @@ -241,6 +241,6 @@ , E.getEditContents $ st^.edit5 , E.getEditContents $ st^.edit6 , E.getEditContents $ st^.edit7- , E.getEditContents $ st^.edit8 + , E.getEditContents $ st^.edit8 , E.getEditContents $ st^.edit9- ] + ]
+ src/Lang/French.hs view
@@ -0,0 +1,86 @@+module Lang.French where++import Lang.Strings++french :: String -> String+french str+ | is tuiTitle = " Herm's - Ajouter une recette"+ | is tuiName = " Nom: "+ | is tuiDesc = " Description: "+ | is tuiServingSize = " Portion: "+ | is tuiHeaders = " qté. unité nom attribut"+ | is tuiIngrs = " Ingrédients: \n(un par ligne) " + | is tuiDirs = " Directions: \n(un par ligne) "+ | is tuiTags = " Mots-clés: "+ | is tuiHelp1 = " Tab / Shift+Tab - Champ suivant / précédent"+ | is tuiHelp2 = " Ctrl + <flêches> - Parcourir les champs"+ | is tuiHelp3 = " [Meta or Alt] + <h-j-k-l> - Parcourir les champs"+ | is tuiHelp4 = " Esc - Enregistrer ou Annuler"+ | is headerServs = "\nPortions: "+ | is headerIngrs = "\nIngrédients:\n"+ | is saveRecipeYesNoEdit = "Enregister la recette? (O)ui (N)on (E)diter"+ | is y = "o" + | is yCap = "O"+ | is n = "n" + | is nCap = "N"+ | is e = "e" + | is eCap = "E"+ | is recipeSaved = "Recette enregistrée!"+ | is changesDiscarded = "Modifications annulées."+ | is badEntry = "Merci de SEULEMENT entrer 'o', 'n' ou 'e'"+ | is doesNotExist = " n'existe pas\n"+ | is nothingToImport = "Rien a importer"+ | is importedRecipes = "Recettes importées:"+ | is metric = "métrique"+ | is imperial = "impériale"+ | is more = " [plus]"+ | is capTags = "Mots-clés"+ | is removingRecipe = "Enlever la recette: "+ | is group = "grouper"+ -- | is groupShort = "g"+ | is groupDesc = "grouper les recettes par mots-cles"+ | is nameOnly = "nom"+ -- | is nameOnlyShort = "n"+ | is nameOnlyDesc = "afficher que le nom des recettes"+ | is tags = "mots-clés"+ | is tagsMetavar = "MOTS-CLES"+ | is tagsDesc = "afficher les recettes avec des mots-clés particuliers"+ | is serving = "portion"+ -- | is servingShort = "p"+ | is servingDesc = "spécifier la portion en affichant"+ | is servingMetavar = "INT"+ | is step = "pas"+ -- | is stepShort = "t"+ | is stepDesc = "s'il faut afficher un pas après l'autre"+ | is convert = "convertir"+ -- | is convertShort = "c"+ | is convertDesc = "convertit les unités de la recette en métrique ou impérial."+ | is convertMetavar = "CONV_UNIT"+ | is none = "aucun"+ | is recipeNameMetavar = "NOM_RECETTE"+ | is recipeNameDesc = "index ou nom de recette"+ | is fileNameMetavar = "NOM_FICHIER"+ | is fileNameDesc = "nom du fichier"+ | is list = "lister"+ | is listDesc = "lister les recettes"+ | is view = "afficher"+ | is viewDesc = "afficher les recettes particulières"+ | is add = "ajouter"+ | is addDesc = "ajouter une nouvelle recette (interactivement)"+ | is edit = "éditer"+ | is editDesc = "éditer une recette"+ | is import' = "importer"+ | is importDesc = "importer un ficher de recette"+ | is remove = "retirer"+ | is removeDesc = "retirer les recettes particulières"+ | is shopping = "course"+ | is shoppingDesc = "générer une liste de course pour les recettes données"+ | is datadir = "datadir"+ | is datadirDesc = "afficher l'emplacement des fichers de configuration et de recettes"+ | is version = "version"+ -- | is versionShort = "v"+ | is versionDesc = "afficher la version"+ | is progDesc = "HeRM's: Un gestionnaire de recette en Haskell. Taper \"herms --help\" pour les options"+ | otherwise = str++ where is = (str ==)
src/Lang/Strings.hs view
@@ -120,6 +120,9 @@ import' = "import" importDesc = "import a recipe file" +export = "export"+exportDesc = "export recipes to stdout"+ remove = "remove" removeDesc = "remove the particular recipes"
src/ReadConfig.hs view
@@ -7,6 +7,7 @@ import Data.Char (toLower) import Data.List.Split import Lang.Pirate+import Lang.French import Paths_herms ------------------------------@@ -32,6 +33,7 @@ data Language = English | Pirate | Portuguese+ | French type Translator = String -> String @@ -51,6 +53,10 @@ ------ Language Synonyms ----- ------------------------------ +-- Contributor's note: Make sure that all of these synonyms are lower-case as+-- we handle case-sensitivity by first converting the user's settings input+-- to all lower-case.+ englishSyns = [ "english" , "en" , "en-us"@@ -67,6 +73,14 @@ , "pt" ] +frenchSyns = [ "french"+ , "fr"+ , "fr-fr"+ , "français"+ , "francais"+ ]++ ------------------------------ --------- Functions ---------- ------------------------------@@ -76,12 +90,15 @@ | isIn englishSyns = English -- | isIn portugueseSyns = Portuguese | isIn pirateSyns = Pirate+ -- | isIn frenchSyns = French+ | isIn frenchSyns = French where isIn = elem (map toLower $ language c) getTranslator :: Language -> Translator getTranslator lang = case lang of English -> id :: String -> String Pirate -> pirate+ French -> french dropComments :: String -> String dropComments = unlines . map (head . splitOn "--") . lines
src/Types.hs view
@@ -7,6 +7,7 @@ import Data.Ord import RichText import qualified Lang.Strings as Str+import Text.Read (readMaybe) data Ingredient = Ingredient { quantity :: Ratio Int , unit :: String@@ -103,7 +104,7 @@ ingredients = i, directions = dir, tags = t } where n = concat $ head r des = concat $ r !! 1- s = read $ concat $ r !! 2+ s = fromMaybe 1 $ readMaybe $ concat $ r !! 2 i = adjustIngredients (1 % s) $ readIngredients [r !! 3, r !! 4, r !! 5, r !! 6] dir = r !! 7 unparsedTags = concat (r !! 8)