packages feed

herms 1.8.1.4 → 1.8.2.1

raw patch · 5 files changed

+153/−41 lines, 5 filesdep ~brickdep ~vty

Dependency ranges changed: brick, vty

Files

README.md view
@@ -17,6 +17,13 @@ - Generate shopping lists - Keep track of recipes with tags +### What's new:+- Set default unit systems, serving sizes, and recipe file path in ``config.hs``!+    - Coming soon: Multi-language support+- Added support for multi-word tags+- Check your Herm's version with ``-v`` or ``--version``+- Herm's is now on Stackage!+ ### Installation  #### PATH setup@@ -29,15 +36,9 @@  #### Download and install -You have options!--Via Hackage and Cabal:-```-cabal update-cabal install herms-```+At the moment, Herm's can only be compiled from source, but binaries are in the works! -Manually cloning and installing from source with stack (recommended):+##### Manually cloning and installing from source with Stack _(recommended)_:  ``` git clone https://github.com/JackKiefer/herms@@ -46,9 +47,18 @@ stack install ``` -You can also manually compile with cabal, but your milage may vary with dependency resolution:+##### Via Hackage and Cabal:  ```+cabal update+cabal install herms+```++##### Manually with Cabal:++Your milage may vary with dependency resolution++``` git clone https://github.com/JackKiefer/herms cd herms cabal update@@ -56,6 +66,13 @@ ```  ### Usage++#### Command-line interface ++Herm's has a pretty intuitive interface for users familiar with other command-line programs! ++Below is the exhaustive list of all commands and their functionalities. Take a gander!+ ``` Usage: @@ -76,10 +93,14 @@          herms shopping RECIPE_NAMES [-s|--serving INT] generate shopping list for particular recipes +        herms datadir                                  print location of recipe and config files+ Available options:          -h|--help                                      Show this help text +        -v|--version                                   Show version+         RECIPE_NAME                                    index or Recipe name          --sort SORT_ORDER                              'tags' to sort by tags@@ -99,6 +120,19 @@         -c|--convert CONV_UNIT                         view the recipe converted to imperial or metric                                                        E.g., 'herms view 2 -c imperial' ```++#### Configuring Herm's and managing recipe files++Herm's stores its recipes file, ``recipes.herms``,  and configuration file, ``config.hs``, in the same directory. Herm's keeps track of its location! Run ``herms datadir`` to see the full directory path.++``config.hs`` is a pseudo-Haskell-source-code file with several options for configuring the behaviour of Herm's. It currently supports the following options:++- `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 and relative location. Make sure the file already exists by running `touch FILENAME` before running Herm's or it will throw a fit. This option currently supports relative 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"`.+++---  In honor of Logan, Utah's greatest Breakfast & Brunch. 
app/herms.hs view
@@ -18,21 +18,29 @@ import RichText import Types import UnitConversions+import ReadConfig import Paths_herms  -- Global constants-recipesFileName :: String-recipesFileName = "recipes.herms"- versionStr :: String-versionStr = "1.8.1.4"+versionStr = "1.8.2.0" -getRecipeBook :: IO [Recipe]-getRecipeBook = do-  fileName <- getDataFileName recipesFileName+configPath :: IO FilePath+configPath = getDataFileName "config.hs"++-- | @getRecipeBookWith reads in recipe book with already read-in config+getRecipeBookWith :: Config -> IO [Recipe]+getRecipeBookWith config = do+  fileName <- getDataFileName (recipesFile config)   contents <- readFile fileName   return $ map read $ lines contents +-- | @getRecipeBook reads in config before reading in recipe book+getRecipeBook :: IO [Recipe]+getRecipeBook = do+  config <- getConfig+  getRecipeBookWith config+ getRecipe :: String -> [Recipe] -> Maybe Recipe getRecipe target = listToMaybe . filter ((target ==) . recipeName) @@ -46,10 +54,11 @@   response <- getLine   if response == "y" || response == "Y"     then do-    recipeBook <- getRecipeBook+    config <- getConfig+    recipeBook <- getRecipeBookWith config     let recpName = if isNothing oldRecp then recipeName newRecipe else recipeName (fromJust oldRecp)     unless (isNothing (readRecipeRef recpName recipeBook)) $ removeSilent [recpName]-    fileName <- getDataFileName recipesFileName+    fileName <- getDataFileName (recipesFile config)     appendFile fileName (show newRecipe ++ "\n")     putStrLn "Recipe saved!"   else if response == "n" || response == "N"@@ -100,12 +109,13 @@  importFile :: String -> IO () importFile target = do-  recipeBook <- getRecipeBook+  config     <- getConfig+  recipeBook <- getRecipeBookWith config   otherRecipeBook <- (map read . lines) <$> readFile target   let recipeEq = (==) `on` recipeName   let newRecipeBook = deleteFirstsBy recipeEq recipeBook otherRecipeBook                         ++ otherRecipeBook-  replaceDataFile recipesFileName $ unlines $ show <$> newRecipeBook+  replaceDataFile (recipesFile config) $ unlines $ show <$> newRecipeBook   if null otherRecipeBook   then putStrLn "Nothing to import"   else do@@ -115,14 +125,17 @@  view :: [String] -> Int -> String -> IO () view targets serv convName = do-  recipeBook <- getRecipeBook+  config     <- getConfig+  recipeBook <- getRecipeBookWith config   let servings = case serv of-                   0 -> Nothing+                   0 -> (case defaultServingSize config of+                           0 -> Nothing+                           j -> Just j)                    i -> Just i   let conv = case convName of                "metric"   -> Metric                "imperial" -> Imperial-               _          -> None +               _          -> (defaultUnit config)   forM_ targets $ \ target ->     putText $ case readRecipeRef target recipeBook of       Nothing   -> target ~~ " does not exist\n"@@ -130,14 +143,17 @@  viewByStep :: [String] -> Int -> String -> IO () viewByStep targets serv convName = do-  recipeBook <- getRecipeBook+  config     <- getConfig+  recipeBook <- getRecipeBookWith config   let servings = case serv of-                   0 -> Nothing+                   0 -> (case defaultServingSize config of+                           0 -> Nothing+                           j -> Just j)                    i -> Just i   let conv = case convName of               "metric"   -> Metric               "imperial" -> Imperial-              _          -> None+              _          -> (defaultUnit config)   hSetBuffering stdout NoBuffering   forM_ targets $ \ target -> case readRecipeRef target recipeBook of     Nothing   -> putStr $ target ++ " does not exist\n"@@ -225,7 +241,8 @@  removeWithVerbosity :: Bool -> [String] -> IO () removeWithVerbosity v targets = do-  recipeBook <- getRecipeBook+  config     <- getConfig+  recipeBook <- getRecipeBookWith config   mrecipes   <- forM targets $ \ target -> do     -- Resolve the recipes all at once; this way if we remove multiple     -- recipes based on their respective index, all of the index are@@ -238,7 +255,7 @@     return mrecp   -- Remove all the resolved recipes at once   let newRecipeBook = recipeBook \\ catMaybes mrecipes-  replaceDataFile recipesFileName $ unlines $ show <$> newRecipeBook+  replaceDataFile (recipesFile config) $ unlines $ show <$> newRecipeBook  remove :: [String] -> IO () remove = removeWithVerbosity True@@ -262,10 +279,16 @@   forM_ (sort ingrts) $ \ingr ->     putStrLn $ showIngredient 1 ingr +printDataDir :: IO ()+printDataDir = do+  dir <- getDataDir+  putStrLn $ filter (/= '\"') (show dir) ++ "/"+ -- Writes an empty recipes file if it doesn't exist checkFileExists :: IO () checkFileExists = do-  fileName <- getDataFileName recipesFileName+  config   <- getConfig+  fileName <- getDataFileName (recipesFile config)   fileExists <- doesFileExist fileName   unless fileExists (do     dirName <- getDataDir@@ -285,6 +308,7 @@ runWithOpts (View targets serving step conversion)  = if step then viewByStep targets serving conversion                                                       else view targets serving conversion runWithOpts (Shop targets serving)                  = shop targets serving+runWithOpts DataDir                                 = printDataDir   ------------------------------@@ -299,16 +323,18 @@              | Remove [String]                   -- ^ removes specified recipes              | View   [String] Int Bool String   -- ^ shows specified recipes with given serving              | Shop   [String] Int               -- ^ generates the shopping list for given recipes+             | DataDir                           -- ^ prints the directory of recipe file and config.hs  -listP, addP, editP, removeP, viewP, shopP :: Parser Command-listP   = List   <$> (words <$> tagsP) <*> groupByTagsP <*> nameOnlyP-addP    = pure Add-editP   = Edit   <$> recipeNameP-importP = Import <$> fileNameP-removeP = Remove <$> severalRecipesP-viewP   = View   <$> severalRecipesP <*> servingP <*> stepP <*> conversionP-shopP   = Shop   <$> severalRecipesP <*> servingP+listP, addP, editP, removeP, viewP, shopP, dataDirP :: Parser Command+listP    = List   <$> (words <$> tagsP) <*> groupByTagsP <*> nameOnlyP+addP     = pure Add+editP    = Edit   <$> recipeNameP+importP  = Import <$> fileNameP+removeP  = Remove <$> severalRecipesP+viewP    = View   <$> severalRecipesP <*> servingP <*> stepP <*> conversionP+shopP    = Shop   <$> severalRecipesP <*> servingP+dataDirP = pure DataDir   -- | @groupByTagsP is flag for grouping recipes by tags@@ -399,6 +425,9 @@      <> command "shopping"                 (info (helper <*> shopP)                       (progDesc "generate a shopping list for given recipes"))+     <> command "datadir"+                (info (helper <*> dataDirP)+                      (progDesc "show location of recipe and config files"))  versionOption :: Parser (a -> a) versionOption = infoOption versionStr 
+ data/config.hs view
@@ -0,0 +1,14 @@+Config+{ +-- Default unit system to show recipes in.+-- OPTIONS: Imperial, Metric, None+  defaultUnit = None++-- Default serving size to calculate when showing recipes.+-- Set to 0 for no default.+, defaultServingSize = 0++-- Recipes file name and relative location.+-- Default is "recipes.herms"+, recipesFile = "recipes.herms"+}
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.8.1.4+version:             1.8.2.1  -- A short (one-line) description of the package. synopsis:            A command-line manager for delicious kitchen recipes@@ -55,7 +55,7 @@ cabal-version:       >=1.10  -- Files available to the program at runtime-data-files:          recipes.herms+data-files:          recipes.herms, config.hs  -- The directory name for the aboce files data-dir:            data@@ -69,6 +69,7 @@   other-modules:       Utils                      , AddCLI                      , RichText+                     , ReadConfig                      , Types                      , UnitConversions                      , Paths_herms@@ -79,14 +80,14 @@   -- Other library packages from which modules are imported.   build-depends:       ansi-terminal >= 0.7.0 && <= 0.8.1                      , base >=4.8 && <5-                     , brick >=0.19 && <= 0.34.1+                     , brick >= 0.35 && < 0.36                      , directory >= 0.0                      , microlens >=0.4 && <0.5                      , microlens-th >=0.4 && <0.5                      , optparse-applicative >=0.14 && <0.15                      , semigroups >= 0.18.3 && <= 0.18.4                      , split >=0.2 && <0.3-                     , vty >=5.15 && <=5.20+                     , vty >=5.21 && < 5.22     -- Directories containing source files.
+ src/ReadConfig.hs view
@@ -0,0 +1,34 @@+module ReadConfig where++import UnitConversions+import qualified Text.Read as TR+import Control.Exception+import Data.Typeable+import Data.List.Split+import Paths_herms++data Config = Config+  { defaultUnit        :: Conversion+  , defaultServingSize :: Int+  , recipesFile        :: String+  } deriving (Read, Show)++data ConfigParseError = ConfigParseError +  deriving Typeable++instance Show ConfigParseError where+  show ConfigParseError = "Error parsing config.hs"++instance Exception ConfigParseError++dropComments :: String -> String+dropComments = unlines . map (head . (splitOn "--")) . lines++getConfig :: IO Config+getConfig = do+  fileName <- getDataFileName "config.hs"+  contents <- readFile fileName+  let result = TR.readEither (dropComments contents) :: Either String Config+  case result of+    Left str -> throw ConfigParseError+    Right r  -> return r