-- | Parsing options for the Convert report from the command line. module Penny.Cabin.Balance.Convert.Parser ( Opts(..) , Target(..) , SortBy(..) , allOptSpecs ) where import qualified Control.Monad.Exception.Synchronous as Ex import qualified Data.Text as X import qualified Penny.Cabin.Options as CO import qualified Penny.Cabin.Parsers as P import qualified Penny.Lincoln as L import qualified Penny.Copper.Parsec as Pc import qualified System.Console.MultiArg.Combinator as C import qualified Text.Parsec as Parsec -- | Is the target commodity determined by the user or automatically? data Target = AutoTarget | ManualTarget L.To data SortBy = SortByQty | SortByName deriving (Eq, Show, Ord) -- | Default starting options for the Convert report. After -- considering what is parsed in from the command line and price data, -- a Convert.Opts will be generated. data Opts = Opts { showZeroBalances :: CO.ShowZeroBalances , target :: Target , dateTime :: L.DateTime , sortOrder :: P.SortOrder , sortBy :: SortBy } -- | Do not be tempted to change the setup in this module so that the -- individual functions such as parseColor and parseBackground return -- parsers rather than OptSpec. Such an arrangement breaks the correct -- parsing of abbreviated long options. allOptSpecs :: [C.OptSpec (Opts -> Ex.Exceptional String Opts)] allOptSpecs = [ fmap toExc parseZeroBalances , parseCommodity , fmap toExc parseAuto , parseDate , fmap toExc parseSort , fmap toExc parseOrder ] where toExc f = return . f parseZeroBalances :: C.OptSpec (Opts -> Opts) parseZeroBalances = fmap f P.zeroBalances where f x o = o { showZeroBalances = x } parseCommodity :: C.OptSpec (Opts -> Ex.Exceptional String Opts) parseCommodity = C.OptSpec ["commodity"] "c" (C.OneArg f) where f a1 os = case Parsec.parse Pc.lvl1Cmdty "" (X.pack a1) of Left _ -> Ex.throw $ "invalid commodity: " ++ a1 Right g -> return $ os { target = ManualTarget . L.To $ g } parseAuto :: C.OptSpec (Opts -> Opts) parseAuto = C.OptSpec ["auto-commodity"] "" (C.NoArg f) where f os = os { target = AutoTarget } parseDate :: C.OptSpec (Opts -> Ex.Exceptional String Opts) parseDate = C.OptSpec ["date"] "d" (C.OneArg f) where f a1 os = case Parsec.parse Pc.dateTime "" (X.pack a1) of Left _ -> Ex.throw $ "invalid date: " ++ a1 Right g -> return $ os { dateTime = g } parseSort :: C.OptSpec (Opts -> Opts) parseSort = C.OptSpec ["sort"] "s" (C.ChoiceArg ls) where ls = [ ("qty", (\os -> os { sortBy = SortByQty })) , ("name", (\os -> os { sortBy = SortByName })) ] parseOrder :: C.OptSpec (Opts -> Opts) parseOrder = fmap f P.order where f x o = o { sortOrder = x }