packages feed

penny-lib 0.2.0.0 → 0.4.0.0

raw patch · 19 files changed

+1245/−1036 lines, 19 filesPVP ok

version bump matches the API change (PVP)

API changes (from Hackage documentation)

- Penny.Cabin.Balance: Options :: DrCrColors -> BaseColors -> (BottomLine -> Text) -> Colors -> ShowZeroBalances -> Maybe (Commodity, DateTime) -> DefaultTimeZone -> Options
- Penny.Cabin.Balance: data Options
- Penny.Cabin.Balance: defaultBalanceReport :: Report
- Penny.Cabin.Balance.Options: Options :: DrCrColors -> BaseColors -> (BottomLine -> Text) -> Colors -> ShowZeroBalances -> Maybe (Commodity, DateTime) -> DefaultTimeZone -> Options
- Penny.Cabin.Balance.Options: balanceAsIs :: BottomLine -> Text
- Penny.Cabin.Balance.Options: balanceFormat :: Options -> BottomLine -> Text
- Penny.Cabin.Balance.Options: baseColors :: Options -> BaseColors
- Penny.Cabin.Balance.Options: colorPref :: Options -> Colors
- Penny.Cabin.Balance.Options: convert :: Options -> Maybe (Commodity, DateTime)
- Penny.Cabin.Balance.Options: data Options
- Penny.Cabin.Balance.Options: defaultOptions :: Runtime -> Options
- Penny.Cabin.Balance.Options: defaultTimeZone :: Options -> DefaultTimeZone
- Penny.Cabin.Balance.Options: drCrColors :: Options -> DrCrColors
- Penny.Cabin.Balance.Options: showZeroBalances :: Options -> ShowZeroBalances
- Penny.Cabin.Balance.Parser: parser :: Parser (Runtime -> Options -> [Box LibertyMeta] -> [PricePoint] -> Exceptional Text Text)
- Penny.Cabin.Posts: ReportWidth :: Int -> ReportWidth
- Penny.Cabin.Posts: T :: DrCrColors -> BaseColors -> (Box -> Text) -> (Box -> Text) -> (Commodity -> BottomLine -> Text) -> Allocation -> Allocation -> ReportWidth -> Int -> Colors -> DefaultTimeZone -> RadGroup -> CaseSensitive -> (CaseSensitive -> Text -> Exceptional Text (Text -> Bool)) -> [Token (Box LibertyMeta -> Bool)] -> [PostFilterFn] -> T Bool -> T Int -> ShowZeroBalances -> T
- Penny.Cabin.Posts: customPostsReport :: (Runtime -> T) -> Report
- Penny.Cabin.Posts: data T
- Penny.Cabin.Posts: defaultPostsReport :: DefaultTimeZone -> RadGroup -> Report
- Penny.Cabin.Posts: factory :: T -> CaseSensitive -> Text -> Exceptional Text (Text -> Bool)
- Penny.Cabin.Posts: newtype ReportWidth
- Penny.Cabin.Posts: postFilter :: T -> [PostFilterFn]
- Penny.Cabin.Posts: sensitive :: T -> CaseSensitive
- Penny.Cabin.Posts: timeZone :: T -> DefaultTimeZone
- Penny.Cabin.Posts: tokens :: T -> [Token (Box LibertyMeta -> Bool)]
- Penny.Cabin.Posts: unReportWidth :: ReportWidth -> Int
- Penny.Cabin.Posts.Fields: T :: a -> a -> a -> a -> a -> a -> a -> a -> a -> a -> a -> a -> a -> a -> a -> a -> a -> a -> a -> a -> a -> a -> a -> a -> a -> a -> a -> a -> a -> T a
- Penny.Cabin.Posts.Fields: data T a
- Penny.Cabin.Posts.Fields: instance Applicative T
- Penny.Cabin.Posts.Fields: instance Eq a => Eq (T a)
- Penny.Cabin.Posts.Fields: instance Foldable T
- Penny.Cabin.Posts.Fields: instance Functor T
- Penny.Cabin.Posts.Fields: instance Show a => Show (T a)
- Penny.Cabin.Posts.Meta: addMetadata :: ShowZeroBalances -> [Box LibertyMeta] -> [Box PostMeta]
- Penny.Cabin.Posts.Meta: filterBoxes :: [Token (Box LibertyMeta -> Bool)] -> [PostFilterFn] -> [Box LibertyMeta] -> Maybe [Box LibertyMeta]
- Penny.Cabin.Posts.Options: ReportWidth :: Int -> ReportWidth
- Penny.Cabin.Posts.Options: T :: DrCrColors -> BaseColors -> (Box -> Text) -> (Box -> Text) -> (Commodity -> BottomLine -> Text) -> Allocation -> Allocation -> ReportWidth -> Int -> Colors -> DefaultTimeZone -> RadGroup -> CaseSensitive -> (CaseSensitive -> Text -> Exceptional Text (Text -> Bool)) -> [Token (Box LibertyMeta -> Bool)] -> [PostFilterFn] -> T Bool -> T Int -> ShowZeroBalances -> T
- Penny.Cabin.Posts.Options: accountAllocation :: T -> Allocation
- Penny.Cabin.Posts.Options: balanceAsIs :: Commodity -> BottomLine -> Text
- Penny.Cabin.Posts.Options: balanceFormat :: T -> Commodity -> BottomLine -> Text
- Penny.Cabin.Posts.Options: baseColors :: T -> BaseColors
- Penny.Cabin.Posts.Options: colorPref :: T -> Colors
- Penny.Cabin.Posts.Options: columnsVarToWidth :: Maybe String -> ReportWidth
- Penny.Cabin.Posts.Options: data T
- Penny.Cabin.Posts.Options: dateFormat :: T -> Box -> Text
- Penny.Cabin.Posts.Options: defaultFields :: T Bool
- Penny.Cabin.Posts.Options: defaultOptions :: DefaultTimeZone -> RadGroup -> Runtime -> T
- Penny.Cabin.Posts.Options: defaultSpacerWidth :: T Int
- Penny.Cabin.Posts.Options: defaultWidth :: ReportWidth
- Penny.Cabin.Posts.Options: drCrColors :: T -> DrCrColors
- Penny.Cabin.Posts.Options: factory :: T -> CaseSensitive -> Text -> Exceptional Text (Text -> Bool)
- Penny.Cabin.Posts.Options: fields :: T -> T Bool
- Penny.Cabin.Posts.Options: instance Eq ReportWidth
- Penny.Cabin.Posts.Options: instance Ord ReportWidth
- Penny.Cabin.Posts.Options: instance Show ReportWidth
- Penny.Cabin.Posts.Options: newtype ReportWidth
- Penny.Cabin.Posts.Options: payeeAllocation :: T -> Allocation
- Penny.Cabin.Posts.Options: postFilter :: T -> [PostFilterFn]
- Penny.Cabin.Posts.Options: qtyAsIs :: Box -> Text
- Penny.Cabin.Posts.Options: qtyFormat :: T -> Box -> Text
- Penny.Cabin.Posts.Options: radGroup :: T -> RadGroup
- Penny.Cabin.Posts.Options: sensitive :: T -> CaseSensitive
- Penny.Cabin.Posts.Options: showZeroBalances :: T -> ShowZeroBalances
- Penny.Cabin.Posts.Options: spacers :: T -> T Int
- Penny.Cabin.Posts.Options: subAccountLength :: T -> Int
- Penny.Cabin.Posts.Options: timeZone :: T -> DefaultTimeZone
- Penny.Cabin.Posts.Options: tokens :: T -> [Token (Box LibertyMeta -> Bool)]
- Penny.Cabin.Posts.Options: type Box = Box PostMeta
- Penny.Cabin.Posts.Options: unReportWidth :: ReportWidth -> Int
- Penny.Cabin.Posts.Options: width :: T -> ReportWidth
- Penny.Cabin.Posts.Options: widthFromRuntime :: Runtime -> ReportWidth
- Penny.Cabin.Posts.Options: ymd :: Box -> Text
- Penny.Cabin.Posts.Spacers: T :: a -> a -> a -> a -> a -> a -> a -> a -> a -> a -> a -> a -> a -> a -> a -> a -> a -> a -> a -> a -> a -> a -> a -> a -> a -> T a
- Penny.Cabin.Posts.Spacers: data T a
- Penny.Cabin.Posts.Spacers: instance Eq a => Eq (T a)
- Penny.Cabin.Posts.Spacers: instance Show a => Show (T a)
- Penny.Cabin.Posts.Spacers: t_account :: a -> T a -> T a
- Penny.Cabin.Posts.Spacers: t_date :: a -> T a -> T a
- Penny.Cabin.Posts.Spacers: t_filePosting :: a -> T a -> T a
- Penny.Cabin.Posts.Spacers: t_fileTransaction :: a -> T a -> T a
- Penny.Cabin.Posts.Spacers: t_filtered :: a -> T a -> T a
- Penny.Cabin.Posts.Spacers: t_flag :: a -> T a -> T a
- Penny.Cabin.Posts.Spacers: t_globalPosting :: a -> T a -> T a
- Penny.Cabin.Posts.Spacers: t_globalTransaction :: a -> T a -> T a
- Penny.Cabin.Posts.Spacers: t_lineNum :: a -> T a -> T a
- Penny.Cabin.Posts.Spacers: t_number :: a -> T a -> T a
- Penny.Cabin.Posts.Spacers: t_payee :: a -> T a -> T a
- Penny.Cabin.Posts.Spacers: t_postingCmdty :: a -> T a -> T a
- Penny.Cabin.Posts.Spacers: t_postingDrCr :: a -> T a -> T a
- Penny.Cabin.Posts.Spacers: t_postingQty :: a -> T a -> T a
- Penny.Cabin.Posts.Spacers: t_revFilePosting :: a -> T a -> T a
- Penny.Cabin.Posts.Spacers: t_revFileTransaction :: a -> T a -> T a
- Penny.Cabin.Posts.Spacers: t_revFiltered :: a -> T a -> T a
- Penny.Cabin.Posts.Spacers: t_revGlobalPosting :: a -> T a -> T a
- Penny.Cabin.Posts.Spacers: t_revGlobalTransaction :: a -> T a -> T a
- Penny.Cabin.Posts.Spacers: t_revSorted :: a -> T a -> T a
- Penny.Cabin.Posts.Spacers: t_revVisible :: a -> T a -> T a
- Penny.Cabin.Posts.Spacers: t_sorted :: a -> T a -> T a
- Penny.Cabin.Posts.Spacers: t_totalCmdty :: a -> T a -> T a
- Penny.Cabin.Posts.Spacers: t_totalDrCr :: a -> T a -> T a
- Penny.Cabin.Posts.Spacers: t_visible :: a -> T a -> T a
+ Penny.Cabin.Balance: BalanceOpts :: DrCrColors -> BaseColors -> (BottomLine -> Text) -> Colors -> ShowZeroBalances -> DefaultTimeZone -> Maybe (Commodity, DateTime) -> BalanceOpts
+ Penny.Cabin.Balance: balanceAsIs :: BottomLine -> Text
+ Penny.Cabin.Balance: converter :: (Commodity, DateTime) -> [PricePoint] -> [Box LibertyMeta] -> Exceptional Text PriceConverteds
+ Penny.Cabin.Balance: data BalanceOpts
+ Penny.Cabin.Balance: nullConvert :: [Box LibertyMeta] -> PriceConverteds
+ Penny.Cabin.Balance: report :: TreeOpts -> PriceConverteds -> [[Chunk]]
+ Penny.Cabin.Balance.Parser: BadBackground :: String -> Error
+ Penny.Cabin.Balance.Parser: BadColorName :: String -> Error
+ Penny.Cabin.Balance.Parser: BadCommodity :: String -> Error
+ Penny.Cabin.Balance.Parser: BadDate :: String -> Error
+ Penny.Cabin.Balance.Parser: ParseOpts :: DrCrColors -> BaseColors -> Colors -> ShowZeroBalances -> Maybe (Commodity, DateTime) -> ParseOpts
+ Penny.Cabin.Balance.Parser: baseColors :: ParseOpts -> BaseColors
+ Penny.Cabin.Balance.Parser: colorPref :: ParseOpts -> Colors
+ Penny.Cabin.Balance.Parser: convert :: ParseOpts -> Maybe (Commodity, DateTime)
+ Penny.Cabin.Balance.Parser: data Error
+ Penny.Cabin.Balance.Parser: data ParseOpts
+ Penny.Cabin.Balance.Parser: drCrColors :: ParseOpts -> DrCrColors
+ Penny.Cabin.Balance.Parser: parseOptions :: Parser (Runtime -> DefaultTimeZone -> ParseOpts -> Exceptional Error ParseOpts)
+ Penny.Cabin.Balance.Parser: showZeroBalances :: ParseOpts -> ShowZeroBalances
+ Penny.Cabin.Balance.Tree: TreeOpts :: DrCrColors -> BaseColors -> (BottomLine -> Text) -> ShowZeroBalances -> TreeOpts
+ Penny.Cabin.Balance.Tree: balanceFormat :: TreeOpts -> BottomLine -> Text
+ Penny.Cabin.Balance.Tree: baseColors :: TreeOpts -> BaseColors
+ Penny.Cabin.Balance.Tree: converter :: (Commodity, DateTime) -> [PricePoint] -> [Box LibertyMeta] -> Exceptional Text PriceConverteds
+ Penny.Cabin.Balance.Tree: data PriceConverteds
+ Penny.Cabin.Balance.Tree: data TreeOpts
+ Penny.Cabin.Balance.Tree: drCrColors :: TreeOpts -> DrCrColors
+ Penny.Cabin.Balance.Tree: nullConvert :: [Box LibertyMeta] -> PriceConverteds
+ Penny.Cabin.Balance.Tree: showZeroBalances :: TreeOpts -> ShowZeroBalances
+ Penny.Cabin.Posts: ZincOpts :: DefaultTimeZone -> RadGroup -> Fields Bool -> Colors -> DrCrColors -> BaseColors -> ReportWidth -> ShowZeroBalances -> (Box -> Text) -> (Box -> Text) -> (Commodity -> BottomLine -> Text) -> SubAccountLength -> Allocation -> Allocation -> Spacers Int -> ZincOpts
+ Penny.Cabin.Posts: data ZincOpts
+ Penny.Cabin.Posts: defaultSpacerWidth :: Spacers Int
+ Penny.Cabin.Posts: defaultTimeZone :: ZincOpts -> DefaultTimeZone
+ Penny.Cabin.Posts: makeReport :: (Runtime -> ZincOpts) -> Report
+ Penny.Cabin.Posts: parseReport :: (Runtime -> ZincOpts) -> Parser ReportFunc
+ Penny.Cabin.Posts: postsReport :: Colors -> ShowZeroBalances -> (Box LibertyMeta -> Bool) -> [PostFilterFn] -> ChunkOpts -> [Box LibertyMeta] -> Text
+ Penny.Cabin.Posts.Allocated: AllocatedOpts :: Fields Bool -> SubAccountLength -> BaseColors -> Allocation -> Allocation -> Spacers Int -> Fields (Maybe Int) -> ReportWidth -> AllocatedOpts
+ Penny.Cabin.Posts.Allocated: SubAccountLength :: Int -> SubAccountLength
+ Penny.Cabin.Posts.Allocated: accountAllocation :: AllocatedOpts -> Allocation
+ Penny.Cabin.Posts.Allocated: baseColors :: AllocatedOpts -> BaseColors
+ Penny.Cabin.Posts.Allocated: data AllocatedOpts
+ Penny.Cabin.Posts.Allocated: fields :: AllocatedOpts -> Fields Bool
+ Penny.Cabin.Posts.Allocated: growerWidths :: AllocatedOpts -> Fields (Maybe Int)
+ Penny.Cabin.Posts.Allocated: instance Show SubAccountLength
+ Penny.Cabin.Posts.Allocated: instance Show UnShrunkWidth
+ Penny.Cabin.Posts.Allocated: newtype SubAccountLength
+ Penny.Cabin.Posts.Allocated: payeeAllocation :: AllocatedOpts -> Allocation
+ Penny.Cabin.Posts.Allocated: reportWidth :: AllocatedOpts -> ReportWidth
+ Penny.Cabin.Posts.Allocated: spacers :: AllocatedOpts -> Spacers Int
+ Penny.Cabin.Posts.Allocated: subAccountLength :: AllocatedOpts -> SubAccountLength
+ Penny.Cabin.Posts.Allocated: unSubAccountLength :: SubAccountLength -> Int
+ Penny.Cabin.Posts.BottomRows: BottomOpts :: Fields (Maybe Int) -> Fields (Maybe Int) -> Fields Bool -> BaseColors -> ReportWidth -> Spacers Int -> BottomOpts
+ Penny.Cabin.Posts.BottomRows: allocatedWidths :: BottomOpts -> Fields (Maybe Int)
+ Penny.Cabin.Posts.BottomRows: baseColors :: BottomOpts -> BaseColors
+ Penny.Cabin.Posts.BottomRows: data BottomOpts
+ Penny.Cabin.Posts.BottomRows: fields :: BottomOpts -> Fields Bool
+ Penny.Cabin.Posts.BottomRows: growingWidths :: BottomOpts -> Fields (Maybe Int)
+ Penny.Cabin.Posts.BottomRows: reportWidth :: BottomOpts -> ReportWidth
+ Penny.Cabin.Posts.BottomRows: spacers :: BottomOpts -> Spacers Int
+ Penny.Cabin.Posts.Chunk: ChunkOpts :: BaseColors -> DrCrColors -> (Box -> Text) -> (Box -> Text) -> (Commodity -> BottomLine -> Text) -> Fields Bool -> SubAccountLength -> Allocation -> Allocation -> Spacers Int -> ReportWidth -> ChunkOpts
+ Penny.Cabin.Posts.Chunk: accountAllocation :: ChunkOpts -> Allocation
+ Penny.Cabin.Posts.Chunk: balanceFormat :: ChunkOpts -> Commodity -> BottomLine -> Text
+ Penny.Cabin.Posts.Chunk: baseColors :: ChunkOpts -> BaseColors
+ Penny.Cabin.Posts.Chunk: data ChunkOpts
+ Penny.Cabin.Posts.Chunk: dateFormat :: ChunkOpts -> Box -> Text
+ Penny.Cabin.Posts.Chunk: drCrColors :: ChunkOpts -> DrCrColors
+ Penny.Cabin.Posts.Chunk: fields :: ChunkOpts -> Fields Bool
+ Penny.Cabin.Posts.Chunk: payeeAllocation :: ChunkOpts -> Allocation
+ Penny.Cabin.Posts.Chunk: qtyFormat :: ChunkOpts -> Box -> Text
+ Penny.Cabin.Posts.Chunk: reportWidth :: ChunkOpts -> ReportWidth
+ Penny.Cabin.Posts.Chunk: spacers :: ChunkOpts -> Spacers Int
+ Penny.Cabin.Posts.Chunk: subAccountLength :: ChunkOpts -> SubAccountLength
+ Penny.Cabin.Posts.Fields: Fields :: a -> a -> a -> a -> a -> a -> a -> a -> a -> a -> a -> a -> a -> a -> a -> a -> a -> a -> a -> a -> a -> a -> a -> a -> a -> a -> a -> a -> a -> Fields a
+ Penny.Cabin.Posts.Fields: data Fields a
+ Penny.Cabin.Posts.Fields: instance Applicative Fields
+ Penny.Cabin.Posts.Fields: instance Eq a => Eq (Fields a)
+ Penny.Cabin.Posts.Fields: instance Foldable Fields
+ Penny.Cabin.Posts.Fields: instance Functor Fields
+ Penny.Cabin.Posts.Fields: instance Show a => Show (Fields a)
+ Penny.Cabin.Posts.Growers: GrowOpts :: BaseColors -> DrCrColors -> (Box -> Text) -> (Box -> Text) -> (Commodity -> BottomLine -> Text) -> Fields Bool -> GrowOpts
+ Penny.Cabin.Posts.Growers: balanceFormat :: GrowOpts -> Commodity -> BottomLine -> Text
+ Penny.Cabin.Posts.Growers: baseColors :: GrowOpts -> BaseColors
+ Penny.Cabin.Posts.Growers: data GrowOpts
+ Penny.Cabin.Posts.Growers: dateFormat :: GrowOpts -> Box -> Text
+ Penny.Cabin.Posts.Growers: drCrColors :: GrowOpts -> DrCrColors
+ Penny.Cabin.Posts.Growers: fields :: GrowOpts -> Fields Bool
+ Penny.Cabin.Posts.Growers: qtyFormat :: GrowOpts -> Box -> Text
+ Penny.Cabin.Posts.Meta: toBoxList :: ShowZeroBalances -> (Box LibertyMeta -> Bool) -> [PostFilterFn] -> [Box LibertyMeta] -> [Box]
+ Penny.Cabin.Posts.Meta: type Box = Box PostMeta
+ Penny.Cabin.Posts.Parser: BadBackgroundArg :: String -> Error
+ Penny.Cabin.Posts.Parser: BadColorName :: String -> Error
+ Penny.Cabin.Posts.Parser: BadComparator :: String -> Error
+ Penny.Cabin.Posts.Parser: BadNumber :: String -> Error
+ Penny.Cabin.Posts.Parser: BadWidthArg :: String -> Error
+ Penny.Cabin.Posts.Parser: LibertyError :: Error -> Error
+ Penny.Cabin.Posts.Parser: MultipleMatchingFieldNames :: [String] -> Error
+ Penny.Cabin.Posts.Parser: NoMatchingFieldName :: Error
+ Penny.Cabin.Posts.Parser: State :: CaseSensitive -> Factory -> [Token (Box LibertyMeta -> Bool)] -> [PostFilterFn] -> Fields Bool -> Colors -> DrCrColors -> BaseColors -> ReportWidth -> ShowZeroBalances -> State
+ Penny.Cabin.Posts.Parser: baseColors :: State -> BaseColors
+ Penny.Cabin.Posts.Parser: colorPref :: State -> Colors
+ Penny.Cabin.Posts.Parser: data Error
+ Penny.Cabin.Posts.Parser: data State
+ Penny.Cabin.Posts.Parser: drCrColors :: State -> DrCrColors
+ Penny.Cabin.Posts.Parser: factory :: State -> Factory
+ Penny.Cabin.Posts.Parser: fields :: State -> Fields Bool
+ Penny.Cabin.Posts.Parser: postFilter :: State -> [PostFilterFn]
+ Penny.Cabin.Posts.Parser: sensitive :: State -> CaseSensitive
+ Penny.Cabin.Posts.Parser: showZeroBalances :: State -> ShowZeroBalances
+ Penny.Cabin.Posts.Parser: tokens :: State -> [Token (Box LibertyMeta -> Bool)]
+ Penny.Cabin.Posts.Parser: width :: State -> ReportWidth
+ Penny.Cabin.Posts.Spacers: Spacers :: a -> a -> a -> a -> a -> a -> a -> a -> a -> a -> a -> a -> a -> a -> a -> a -> a -> a -> a -> a -> a -> a -> a -> a -> a -> Spacers a
+ Penny.Cabin.Posts.Spacers: data Spacers a
+ Penny.Cabin.Posts.Spacers: instance Eq a => Eq (Spacers a)
+ Penny.Cabin.Posts.Spacers: instance Show a => Show (Spacers a)
+ Penny.Cabin.Posts.Types: ReportWidth :: Int -> ReportWidth
+ Penny.Cabin.Posts.Types: instance Eq ReportWidth
+ Penny.Cabin.Posts.Types: instance Ord ReportWidth
+ Penny.Cabin.Posts.Types: instance Show ReportWidth
+ Penny.Cabin.Posts.Types: newtype ReportWidth
+ Penny.Cabin.Posts.Types: unReportWidth :: ReportWidth -> Int
+ Penny.Lincoln: type Factory = CaseSensitive -> Text -> Exceptional Text Matcher
+ Penny.Lincoln: type Matcher = Text -> Bool
+ Penny.Lincoln.Matchers: type Factory = CaseSensitive -> Text -> Exceptional Text Matcher
+ Penny.Lincoln.Matchers: type Matcher = Text -> Bool
- Penny.Cabin.Balance: balanceFormat :: Options -> BottomLine -> Text
+ Penny.Cabin.Balance: balanceFormat :: BalanceOpts -> BottomLine -> Text
- Penny.Cabin.Balance: balanceReport :: (Runtime -> Options) -> Report
+ Penny.Cabin.Balance: balanceReport :: (Runtime -> BalanceOpts) -> Report
- Penny.Cabin.Balance: baseColors :: Options -> BaseColors
+ Penny.Cabin.Balance: baseColors :: BalanceOpts -> BaseColors
- Penny.Cabin.Balance: colorPref :: Options -> Colors
+ Penny.Cabin.Balance: colorPref :: BalanceOpts -> Colors
- Penny.Cabin.Balance: convert :: Options -> Maybe (Commodity, DateTime)
+ Penny.Cabin.Balance: convert :: BalanceOpts -> Maybe (Commodity, DateTime)
- Penny.Cabin.Balance: defaultOptions :: Runtime -> Options
+ Penny.Cabin.Balance: defaultOptions :: DefaultTimeZone -> Runtime -> BalanceOpts
- Penny.Cabin.Balance: defaultTimeZone :: Options -> DefaultTimeZone
+ Penny.Cabin.Balance: defaultTimeZone :: BalanceOpts -> DefaultTimeZone
- Penny.Cabin.Balance: drCrColors :: Options -> DrCrColors
+ Penny.Cabin.Balance: drCrColors :: BalanceOpts -> DrCrColors
- Penny.Cabin.Balance: showZeroBalances :: Options -> ShowZeroBalances
+ Penny.Cabin.Balance: showZeroBalances :: BalanceOpts -> ShowZeroBalances
- Penny.Cabin.Balance.Tree: report :: Options -> [Box LibertyMeta] -> [PricePoint] -> Exceptional Text [[Chunk]]
+ Penny.Cabin.Balance.Tree: report :: TreeOpts -> PriceConverteds -> [[Chunk]]
- Penny.Cabin.Posts: accountAllocation :: T -> Allocation
+ Penny.Cabin.Posts: accountAllocation :: ZincOpts -> Allocation
- Penny.Cabin.Posts: balanceAsIs :: Commodity -> BottomLine -> Text
+ Penny.Cabin.Posts: balanceAsIs :: a -> BottomLine -> Text
- Penny.Cabin.Posts: balanceFormat :: T -> Commodity -> BottomLine -> Text
+ Penny.Cabin.Posts: balanceFormat :: ZincOpts -> Commodity -> BottomLine -> Text
- Penny.Cabin.Posts: baseColors :: T -> BaseColors
+ Penny.Cabin.Posts: baseColors :: ZincOpts -> BaseColors
- Penny.Cabin.Posts: colorPref :: T -> Colors
+ Penny.Cabin.Posts: colorPref :: ZincOpts -> Colors
- Penny.Cabin.Posts: dateFormat :: T -> Box -> Text
+ Penny.Cabin.Posts: dateFormat :: ZincOpts -> Box -> Text
- Penny.Cabin.Posts: defaultFields :: T Bool
+ Penny.Cabin.Posts: defaultFields :: Fields Bool
- Penny.Cabin.Posts: defaultOptions :: DefaultTimeZone -> RadGroup -> Runtime -> T
+ Penny.Cabin.Posts: defaultOptions :: DefaultTimeZone -> RadGroup -> Runtime -> ZincOpts
- Penny.Cabin.Posts: drCrColors :: T -> DrCrColors
+ Penny.Cabin.Posts: drCrColors :: ZincOpts -> DrCrColors
- Penny.Cabin.Posts: fields :: T -> T Bool
+ Penny.Cabin.Posts: fields :: ZincOpts -> Fields Bool
- Penny.Cabin.Posts: payeeAllocation :: T -> Allocation
+ Penny.Cabin.Posts: payeeAllocation :: ZincOpts -> Allocation
- Penny.Cabin.Posts: qtyFormat :: T -> Box -> Text
+ Penny.Cabin.Posts: qtyFormat :: ZincOpts -> Box -> Text
- Penny.Cabin.Posts: radGroup :: T -> RadGroup
+ Penny.Cabin.Posts: radGroup :: ZincOpts -> RadGroup
- Penny.Cabin.Posts: showZeroBalances :: T -> ShowZeroBalances
+ Penny.Cabin.Posts: showZeroBalances :: ZincOpts -> ShowZeroBalances
- Penny.Cabin.Posts: spacers :: T -> T Int
+ Penny.Cabin.Posts: spacers :: ZincOpts -> Spacers Int
- Penny.Cabin.Posts: subAccountLength :: T -> Int
+ Penny.Cabin.Posts: subAccountLength :: ZincOpts -> SubAccountLength
- Penny.Cabin.Posts: width :: T -> ReportWidth
+ Penny.Cabin.Posts: width :: ZincOpts -> ReportWidth
- Penny.Cabin.Posts.Allocated: payeeAndAcct :: Fields (Maybe Int) -> T -> [Box] -> Fields (Maybe ([ColumnSpec], Int))
+ Penny.Cabin.Posts.Allocated: payeeAndAcct :: AllocatedOpts -> [Box] -> Fields (Maybe ([ColumnSpec], Int))
- Penny.Cabin.Posts.BottomRows: bottomRows :: Fields (Maybe Int) -> Fields (Maybe Int) -> T -> [Box] -> Fields (Maybe [[Chunk]])
+ Penny.Cabin.Posts.BottomRows: bottomRows :: BottomOpts -> [Box] -> Fields (Maybe [[Chunk]])
- Penny.Cabin.Posts.BottomRows: mergeWithSpacers :: TopRowCells a -> T b -> TopRowCells (a, Maybe b)
+ Penny.Cabin.Posts.BottomRows: mergeWithSpacers :: TopRowCells a -> Spacers b -> TopRowCells (a, Maybe b)
- Penny.Cabin.Posts.Chunk: makeChunk :: T -> [Box] -> [Chunk]
+ Penny.Cabin.Posts.Chunk: makeChunk :: ChunkOpts -> [Box] -> [Chunk]
- Penny.Cabin.Posts.Fields: account :: T a -> a
+ Penny.Cabin.Posts.Fields: account :: Fields a -> a
- Penny.Cabin.Posts.Fields: date :: T a -> a
+ Penny.Cabin.Posts.Fields: date :: Fields a -> a
- Penny.Cabin.Posts.Fields: filePosting :: T a -> a
+ Penny.Cabin.Posts.Fields: filePosting :: Fields a -> a
- Penny.Cabin.Posts.Fields: fileTransaction :: T a -> a
+ Penny.Cabin.Posts.Fields: fileTransaction :: Fields a -> a
- Penny.Cabin.Posts.Fields: filename :: T a -> a
+ Penny.Cabin.Posts.Fields: filename :: Fields a -> a
- Penny.Cabin.Posts.Fields: filtered :: T a -> a
+ Penny.Cabin.Posts.Fields: filtered :: Fields a -> a
- Penny.Cabin.Posts.Fields: flag :: T a -> a
+ Penny.Cabin.Posts.Fields: flag :: Fields a -> a
- Penny.Cabin.Posts.Fields: globalPosting :: T a -> a
+ Penny.Cabin.Posts.Fields: globalPosting :: Fields a -> a
- Penny.Cabin.Posts.Fields: globalTransaction :: T a -> a
+ Penny.Cabin.Posts.Fields: globalTransaction :: Fields a -> a
- Penny.Cabin.Posts.Fields: lineNum :: T a -> a
+ Penny.Cabin.Posts.Fields: lineNum :: Fields a -> a
- Penny.Cabin.Posts.Fields: memo :: T a -> a
+ Penny.Cabin.Posts.Fields: memo :: Fields a -> a
- Penny.Cabin.Posts.Fields: number :: T a -> a
+ Penny.Cabin.Posts.Fields: number :: Fields a -> a
- Penny.Cabin.Posts.Fields: payee :: T a -> a
+ Penny.Cabin.Posts.Fields: payee :: Fields a -> a
- Penny.Cabin.Posts.Fields: postingCmdty :: T a -> a
+ Penny.Cabin.Posts.Fields: postingCmdty :: Fields a -> a
- Penny.Cabin.Posts.Fields: postingDrCr :: T a -> a
+ Penny.Cabin.Posts.Fields: postingDrCr :: Fields a -> a
- Penny.Cabin.Posts.Fields: postingQty :: T a -> a
+ Penny.Cabin.Posts.Fields: postingQty :: Fields a -> a
- Penny.Cabin.Posts.Fields: revFilePosting :: T a -> a
+ Penny.Cabin.Posts.Fields: revFilePosting :: Fields a -> a
- Penny.Cabin.Posts.Fields: revFileTransaction :: T a -> a
+ Penny.Cabin.Posts.Fields: revFileTransaction :: Fields a -> a
- Penny.Cabin.Posts.Fields: revFiltered :: T a -> a
+ Penny.Cabin.Posts.Fields: revFiltered :: Fields a -> a
- Penny.Cabin.Posts.Fields: revGlobalPosting :: T a -> a
+ Penny.Cabin.Posts.Fields: revGlobalPosting :: Fields a -> a
- Penny.Cabin.Posts.Fields: revGlobalTransaction :: T a -> a
+ Penny.Cabin.Posts.Fields: revGlobalTransaction :: Fields a -> a
- Penny.Cabin.Posts.Fields: revSorted :: T a -> a
+ Penny.Cabin.Posts.Fields: revSorted :: Fields a -> a
- Penny.Cabin.Posts.Fields: revVisible :: T a -> a
+ Penny.Cabin.Posts.Fields: revVisible :: Fields a -> a
- Penny.Cabin.Posts.Fields: sorted :: T a -> a
+ Penny.Cabin.Posts.Fields: sorted :: Fields a -> a
- Penny.Cabin.Posts.Fields: tags :: T a -> a
+ Penny.Cabin.Posts.Fields: tags :: Fields a -> a
- Penny.Cabin.Posts.Fields: totalCmdty :: T a -> a
+ Penny.Cabin.Posts.Fields: totalCmdty :: Fields a -> a
- Penny.Cabin.Posts.Fields: totalDrCr :: T a -> a
+ Penny.Cabin.Posts.Fields: totalDrCr :: Fields a -> a
- Penny.Cabin.Posts.Fields: totalQty :: T a -> a
+ Penny.Cabin.Posts.Fields: totalQty :: Fields a -> a
- Penny.Cabin.Posts.Fields: visible :: T a -> a
+ Penny.Cabin.Posts.Fields: visible :: Fields a -> a
- Penny.Cabin.Posts.Growers: growCells :: T -> [Box] -> Fields (Maybe ([ColumnSpec], Int))
+ Penny.Cabin.Posts.Growers: growCells :: GrowOpts -> [Box] -> Fields (Maybe ([ColumnSpec], Int))
- Penny.Cabin.Posts.Growers: grownWidth :: Fields (Maybe Int) -> T Int -> Int
+ Penny.Cabin.Posts.Growers: grownWidth :: Fields (Maybe Int) -> Spacers Int -> Int
- Penny.Cabin.Posts.Growers: pairWithSpacer :: Fields a -> T b -> Fields (a, Maybe b)
+ Penny.Cabin.Posts.Growers: pairWithSpacer :: Fields a -> Spacers b -> Fields (a, Maybe b)
- Penny.Cabin.Posts.Parser: parseOptions :: Parser (Runtime -> T -> Exceptional Error T)
+ Penny.Cabin.Posts.Parser: parseOptions :: Parser (Runtime -> DefaultTimeZone -> RadGroup -> State -> Exceptional Error State)
- Penny.Cabin.Posts.Spacers: account :: T a -> a
+ Penny.Cabin.Posts.Spacers: account :: Spacers a -> a
- Penny.Cabin.Posts.Spacers: date :: T a -> a
+ Penny.Cabin.Posts.Spacers: date :: Spacers a -> a
- Penny.Cabin.Posts.Spacers: filePosting :: T a -> a
+ Penny.Cabin.Posts.Spacers: filePosting :: Spacers a -> a
- Penny.Cabin.Posts.Spacers: fileTransaction :: T a -> a
+ Penny.Cabin.Posts.Spacers: fileTransaction :: Spacers a -> a
- Penny.Cabin.Posts.Spacers: filtered :: T a -> a
+ Penny.Cabin.Posts.Spacers: filtered :: Spacers a -> a
- Penny.Cabin.Posts.Spacers: flag :: T a -> a
+ Penny.Cabin.Posts.Spacers: flag :: Spacers a -> a
- Penny.Cabin.Posts.Spacers: globalPosting :: T a -> a
+ Penny.Cabin.Posts.Spacers: globalPosting :: Spacers a -> a
- Penny.Cabin.Posts.Spacers: globalTransaction :: T a -> a
+ Penny.Cabin.Posts.Spacers: globalTransaction :: Spacers a -> a
- Penny.Cabin.Posts.Spacers: lineNum :: T a -> a
+ Penny.Cabin.Posts.Spacers: lineNum :: Spacers a -> a
- Penny.Cabin.Posts.Spacers: number :: T a -> a
+ Penny.Cabin.Posts.Spacers: number :: Spacers a -> a
- Penny.Cabin.Posts.Spacers: payee :: T a -> a
+ Penny.Cabin.Posts.Spacers: payee :: Spacers a -> a
- Penny.Cabin.Posts.Spacers: postingCmdty :: T a -> a
+ Penny.Cabin.Posts.Spacers: postingCmdty :: Spacers a -> a
- Penny.Cabin.Posts.Spacers: postingDrCr :: T a -> a
+ Penny.Cabin.Posts.Spacers: postingDrCr :: Spacers a -> a
- Penny.Cabin.Posts.Spacers: postingQty :: T a -> a
+ Penny.Cabin.Posts.Spacers: postingQty :: Spacers a -> a
- Penny.Cabin.Posts.Spacers: revFilePosting :: T a -> a
+ Penny.Cabin.Posts.Spacers: revFilePosting :: Spacers a -> a
- Penny.Cabin.Posts.Spacers: revFileTransaction :: T a -> a
+ Penny.Cabin.Posts.Spacers: revFileTransaction :: Spacers a -> a
- Penny.Cabin.Posts.Spacers: revFiltered :: T a -> a
+ Penny.Cabin.Posts.Spacers: revFiltered :: Spacers a -> a
- Penny.Cabin.Posts.Spacers: revGlobalPosting :: T a -> a
+ Penny.Cabin.Posts.Spacers: revGlobalPosting :: Spacers a -> a
- Penny.Cabin.Posts.Spacers: revGlobalTransaction :: T a -> a
+ Penny.Cabin.Posts.Spacers: revGlobalTransaction :: Spacers a -> a
- Penny.Cabin.Posts.Spacers: revSorted :: T a -> a
+ Penny.Cabin.Posts.Spacers: revSorted :: Spacers a -> a
- Penny.Cabin.Posts.Spacers: revVisible :: T a -> a
+ Penny.Cabin.Posts.Spacers: revVisible :: Spacers a -> a
- Penny.Cabin.Posts.Spacers: sorted :: T a -> a
+ Penny.Cabin.Posts.Spacers: sorted :: Spacers a -> a
- Penny.Cabin.Posts.Spacers: totalCmdty :: T a -> a
+ Penny.Cabin.Posts.Spacers: totalCmdty :: Spacers a -> a
- Penny.Cabin.Posts.Spacers: totalDrCr :: T a -> a
+ Penny.Cabin.Posts.Spacers: totalDrCr :: Spacers a -> a
- Penny.Cabin.Posts.Spacers: visible :: T a -> a
+ Penny.Cabin.Posts.Spacers: visible :: Spacers a -> a

Files

Penny/Cabin.hs view
@@ -11,5 +11,5 @@   -> C.RadGroup   -> [I.Report] allReportsWithDefaults dtz rg =-  [B.defaultBalanceReport, P.defaultPostsReport dtz rg]-  +  [ B.balanceReport (B.defaultOptions dtz)+  , P.makeReport (P.defaultOptions dtz rg) ]
Penny/Cabin/Balance.hs view
@@ -1,21 +1,107 @@ -- | The Penny balance report-module Penny.Cabin.Balance (balanceReport, O.defaultOptions,-                            O.Options(..),-                            defaultBalanceReport) where+module Penny.Cabin.Balance (+  -- * Making reports+  +  -- | Use these functions if you are building a report from your own+  -- code and you are not using the Zinc parser.+  T.report+  , T.nullConvert+  , T.converter+    +    -- * Parsing reports+    -- | For use with the Zinc command line parser.+  , BalanceOpts(..)+  , balanceReport+  , defaultOptions+  , balanceAsIs +  ) where++import qualified Penny.Cabin.Balance.Tree as T import qualified Penny.Cabin.Balance.Parser as P-import qualified Penny.Cabin.Balance.Options as O import qualified Penny.Cabin.Balance.Help as H+import qualified Penny.Cabin.Chunk as Chunk+import qualified Penny.Cabin.Colors as C+import qualified Penny.Cabin.Colors.DarkBackground as Dark import qualified Penny.Cabin.Interface as I+import qualified Penny.Cabin.Options as CO+import qualified Penny.Copper as Cop+import qualified Penny.Lincoln as L+import qualified Penny.Lincoln.Balance as Bal import qualified Penny.Shield as S -balanceReport :: (S.Runtime -> O.Options) -> I.Report-balanceReport getOpts = I.Report H.help "balance" pr-  where-    pr = do-      fn <- P.parser-      let f rt _ _ bs ps = fn rt (getOpts rt) bs ps-      return f+import qualified Control.Monad.Exception.Synchronous as Ex+import qualified Data.Text as X+import System.Console.MultiArg.Prim (Parser) -defaultBalanceReport :: I.Report-defaultBalanceReport = balanceReport O.defaultOptions+data BalanceOpts = BalanceOpts {+  drCrColors :: C.DrCrColors+  , baseColors :: C.BaseColors+  , balanceFormat :: L.BottomLine -> X.Text+  , colorPref :: Chunk.Colors+  , showZeroBalances :: CO.ShowZeroBalances+  , defaultTimeZone :: Cop.DefaultTimeZone+  , convert :: Maybe (L.Commodity, L.DateTime)+  }++toParseOpts :: BalanceOpts -> P.ParseOpts+toParseOpts b = P.ParseOpts {+  P.drCrColors = drCrColors b+  , P.baseColors = baseColors b+  , P.colorPref = colorPref b+  , P.showZeroBalances = showZeroBalances b+  , P.convert = convert b+  }++toTreeOpts :: P.ParseOpts -> BalanceOpts -> T.TreeOpts+toTreeOpts p b = T.TreeOpts {+  T.drCrColors = P.drCrColors p+  , T.baseColors = P.baseColors p+  , T.balanceFormat = balanceFormat b+  , T.showZeroBalances = P.showZeroBalances p+  }++parser :: (S.Runtime -> BalanceOpts) -> Parser I.ReportFunc+parser frt = do+  parsed <- P.parseOptions+  let rf rt _ _ ps pps = do+        let bo = frt rt+            po = toParseOpts bo+        po' <- Ex.mapException showParseErr $+               parsed rt (defaultTimeZone bo) po+        let to = toTreeOpts po' bo+        conv <- case P.convert po' of+          Nothing -> return $ T.nullConvert ps+          Just co -> T.converter co pps ps+        return+          . Chunk.chunksToText (P.colorPref po')+          . concat+          . T.report to+          $ conv+  return rf+        ++showParseErr :: P.Error -> X.Text+showParseErr = X.pack . show+++balanceReport :: (S.Runtime -> BalanceOpts) -> I.Report+balanceReport f = I.Report H.help "balance" (parser f)+++defaultOptions :: Cop.DefaultTimeZone -> S.Runtime -> BalanceOpts+defaultOptions dtz rt = BalanceOpts {+  drCrColors = Dark.drCrColors+  , baseColors = Dark.baseColors+  , balanceFormat = balanceAsIs+  , colorPref = CO.maxCapableColors rt+  , showZeroBalances = CO.ShowZeroBalances False+  , defaultTimeZone = dtz+  , convert = Nothing+  }++balanceAsIs :: L.BottomLine -> X.Text+balanceAsIs n = case n of+  L.Zero -> X.pack "--"+  L.NonZero c -> X.pack . show . L.unQty . Bal.qty $ c+
− Penny/Cabin/Balance/Options.hs
@@ -1,37 +0,0 @@--- | Options for the Balance report.-module Penny.Cabin.Balance.Options where--import qualified Data.Text as X-import qualified Penny.Lincoln as L-import qualified Penny.Cabin.Chunk as Chunk-import qualified Penny.Cabin.Colors as C-import qualified Penny.Cabin.Options as O-import qualified Penny.Shield as S-import qualified Penny.Cabin.Colors.DarkBackground as DB-import qualified Penny.Copper.DateTime as DT-import qualified Penny.Lincoln.Balance as Bal--data Options = Options {-  drCrColors :: C.DrCrColors-  , baseColors :: C.BaseColors-  , balanceFormat :: L.BottomLine -> X.Text-  , colorPref :: Chunk.Colors-  , showZeroBalances :: O.ShowZeroBalances-  , convert :: Maybe (L.Commodity, L.DateTime)-  , defaultTimeZone :: DT.DefaultTimeZone-  }--balanceAsIs :: L.BottomLine -> X.Text-balanceAsIs n = case n of-  L.Zero -> X.pack "--"-  L.NonZero c -> X.pack . show . L.unQty . Bal.qty $ c--defaultOptions :: S.Runtime -> Options-defaultOptions rt = Options {-  drCrColors = DB.drCrColors-  , baseColors = DB.baseColors-  , balanceFormat = balanceAsIs-  , colorPref = O.maxCapableColors rt-  , showZeroBalances = O.ShowZeroBalances False-  , convert = Nothing-  , defaultTimeZone = DT.utcDefault }
Penny/Cabin/Balance/Parser.hs view
@@ -1,52 +1,41 @@-module Penny.Cabin.Balance.Parser (parser) where+module Penny.Cabin.Balance.Parser (+  Error(..)+  , ParseOpts(..)+  , parseOptions+  ) where  import qualified Data.Text as X-import qualified Data.Text.Lazy as XL-import Control.Applicative ((<|>), many)+import Control.Applicative ((<|>), many, Applicative, pure) import Control.Monad ((>=>)) import qualified Control.Monad.Exception.Synchronous as Ex import qualified Penny.Cabin.Colors as Col import qualified Penny.Cabin.Colors.DarkBackground as DB import qualified Penny.Cabin.Colors.LightBackground as LB import qualified Penny.Cabin.Chunk as Chk-import qualified Penny.Cabin.Balance.Options as O-import qualified Penny.Cabin.Balance.Tree as Tree import qualified Penny.Cabin.Options as CO import qualified Penny.Copper.Commodity as CC import qualified Penny.Copper.DateTime as CD-import qualified Penny.Liberty as Ly import qualified Penny.Lincoln as L import qualified Penny.Shield as S import System.Console.MultiArg.Prim (Parser) import qualified System.Console.MultiArg.Combinator as C import qualified Text.Parsec as Parsec +data ParseOpts = ParseOpts {+  drCrColors :: Col.DrCrColors+  , baseColors :: Col.BaseColors+  , colorPref :: Chk.Colors+  , showZeroBalances :: CO.ShowZeroBalances+  , convert :: Maybe (L.Commodity, L.DateTime)+  }++ data Error = BadColorName String            | BadBackground String            | BadCommodity String            | BadDate String              deriving Show -parser ::-  Parser (S.Runtime-          -> O.Options-          -> [L.Box Ly.LibertyMeta]-          -> [L.PricePoint]-          -> Ex.Exceptional X.Text XL.Text)-parser = do-  ls <- many opts-  let f rt opInit bs ps = do-        let ls' = map (\fn -> fn rt) ls-            errOpParsed = (foldl (>=>) return ls') opInit-        opParsed <- case errOpParsed of-          Ex.Exception e -> Ex.throw . X.pack . show $ e-          Ex.Success g -> return g-        bits <- Tree.report opParsed bs ps-        return-          . Chk.chunksToText (O.colorPref opParsed)-          . concat-          $ bits-  return f  processColorArg ::   S.Runtime@@ -63,13 +52,13 @@ parseOpt ss cs a = C.parseOption [C.OptSpec ss cs a]  color :: Parser (S.Runtime-                 -> O.Options-                 -> Ex.Exceptional Error O.Options)+                 -> ParseOpts+                 -> Ex.Exceptional Error ParseOpts) color = parseOpt ["color"] "" (C.OneArg f)   where     f a1 rt op = case processColorArg rt a1 of       Nothing -> Ex.throw . BadColorName $ a1-      Just c -> return (op { O.colorPref = c })+      Just c -> return (op { colorPref = c })  processBackgroundArg ::   String@@ -80,47 +69,48 @@   | otherwise = Nothing  -background :: Parser (O.Options -> Ex.Exceptional Error O.Options)+background :: Parser (ParseOpts -> Ex.Exceptional Error ParseOpts) background = parseOpt ["background"] "" (C.OneArg f)   where     f a1 op = case processBackgroundArg a1 of       Nothing -> Ex.throw . BadBackground $ a1       Just (dc, base) ->-        return op { O.drCrColors = dc-                  , O.baseColors = base }+        return op { drCrColors = dc+                  , baseColors = base } -showZeroBalances ::-  Parser (O.Options -> Ex.Exceptional a O.Options)-showZeroBalances = parseOpt ["show-zero-balances"] "" (C.NoArg f)+parseShowZeroBalances :: Parser (ParseOpts -> ParseOpts)+parseShowZeroBalances = parseOpt opt "" (C.NoArg f)   where+    opt = ["show-zero-balances"]      f op =-      return (op {O.showZeroBalances = CO.ShowZeroBalances True })+      op {showZeroBalances = CO.ShowZeroBalances True } -hideZeroBalances ::-  Parser (O.Options -> Ex.Exceptional a O.Options)+hideZeroBalances :: Parser (ParseOpts -> ParseOpts) hideZeroBalances = parseOpt ["hide-zero-balances"] "" (C.NoArg f)   where     f op =-      return (op {O.showZeroBalances = CO.ShowZeroBalances False })+      op {showZeroBalances = CO.ShowZeroBalances False }  convertLong ::-  Parser (O.Options -> Ex.Exceptional Error O.Options)+  Parser (CD.DefaultTimeZone+          -> ParseOpts+          -> Ex.Exceptional Error ParseOpts) convertLong = parseOpt ["convert"] "" (C.TwoArg f)   where-    f a1 a2 op = do+    f a1 a2 dtz op = do       cty <- case Parsec.parse CC.lvl1Cmdty "" (X.pack a1) of         Left _ -> Ex.throw . BadCommodity $ a1         Right g -> return g-      let parseDate = CD.dateTime (O.defaultTimeZone op)+      let parseDate = CD.dateTime dtz       dt <- case Parsec.parse parseDate "" (X.pack a2) of         Left _ -> Ex.throw . BadDate $ a2         Right g -> return g-      let op' = op { O.convert = Just (cty, dt) }+      let op' = op { convert = Just (cty, dt) }       return op'  convertShort :: Parser (S.Runtime-                        -> O.Options-                        -> Ex.Exceptional Error O.Options)+                        -> ParseOpts+                        -> Ex.Exceptional Error ParseOpts) convertShort = parseOpt [] ['c'] (C.OneArg f)   where     f a1 rt op = do@@ -128,21 +118,39 @@         Left _ -> Ex.throw . BadCommodity $ a1         Right g -> return g       let dt = S.currentTime rt-          op' = op { O.convert = Just (cty, dt) }+          op' = op { convert = Just (cty, dt) }       return op'          -opts :: Parser (S.Runtime-                -> O.Options-                -> Ex.Exceptional Error O.Options)-opts =-  color-  <|> mkTwoArg background-  <|> mkTwoArg showZeroBalances-  <|> mkTwoArg hideZeroBalances-  <|> mkTwoArg convertLong-  <|> convertShort+parseOptions :: Parser (S.Runtime+                        -> CD.DefaultTimeZone+                        -> ParseOpts+                        -> Ex.Exceptional Error ParseOpts)+parseOptions = do+  fns <- many parseOption+  let f rt dtz o1 =+        let fns' = map (\fn -> fn rt dtz) fns+        in foldl (>=>) return fns' o1+  return f++parseOption :: Parser (S.Runtime+                       -> CD.DefaultTimeZone+                       -> ParseOpts+                       -> Ex.Exceptional Error ParseOpts)+parseOption =+  (do { f <- color; return (\rt _ o -> f rt o )})+  <|> wrap background+  <|> wrap (impurify parseShowZeroBalances)+  <|> wrap (impurify hideZeroBalances)+  <|> (do { f <- convertLong; return (\_ dtz o -> f dtz o )})+  <|> (do { f <- convertShort; return (\rt _ o -> f rt o )})   where-    mkTwoArg p = do+    wrap p = do       f <- p-      return (\_ op -> f op)+      return (\_ _ op -> f op)++impurify ::+  (Applicative m, Functor f)+  => f (a -> a)+  -> f (a -> m a)+impurify = fmap (\f -> pure . f)
Penny/Cabin/Balance/Tree.hs view
@@ -20,7 +20,13 @@ -- * 8. [Columns PreSpec] -> [Columns R.ColumnSpec] (strict) -- -- * 9. [Columns R.ColumnSpec] -> [[Chunk.Bit]] (lazy)-module Penny.Cabin.Balance.Tree (report) where+module Penny.Cabin.Balance.Tree (+  report+  , TreeOpts(..)+  , PriceConverteds+  , nullConvert+  , converter+  ) where  import Control.Applicative(Applicative(pure, (<*>)), (<$>)) import qualified Control.Monad.Exception.Synchronous as Ex@@ -34,7 +40,6 @@ import qualified Data.Text as X import qualified Data.Traversable as Tr import qualified Penny.Cabin.Options as CO-import qualified Penny.Cabin.Balance.Options as O import qualified Penny.Cabin.Chunk as Chunk import qualified Penny.Cabin.Colors as C import qualified Penny.Liberty as Ly@@ -44,10 +49,14 @@ import qualified Data.Semigroup as S  -- Step 1. Convert prices.+ data PriceConverted = PriceConverted {   pcEntry :: L.Entry   , pcAccount :: L.Account } +newtype PriceConverteds =+  PriceConverteds { unPriceConverteds :: [PriceConverted] }+ convertOne ::   L.PriceDb   -> (L.Commodity, L.DateTime)@@ -92,27 +101,33 @@ buildDb = foldl f L.emptyDb where   f db pb = L.addPrice db pb -converter ::-  O.Options-  -> [L.PricePoint]-  -> [L.Box Ly.LibertyMeta]-  -> Ex.Exceptional X.Text [PriceConverted]-converter os pbs bs = case O.convert os of-  Nothing ->-    let f b = PriceConverted en ac where+-- | Makes PriceConverteds where there is no target commodity.+nullConvert :: [L.Box Ly.LibertyMeta] -> PriceConverteds+nullConvert =+  let f b = PriceConverted en ac+        where           p = L.boxPostFam b           en = Q.entry p           ac = Q.account p-    in return . map f $ bs-  Just pair ->+    in PriceConverteds . map f++-- | Makes PriceConverteds where commodities will have to be changed+-- to a target commodity. This will fail if necessary price data is+-- lacking.+converter ::+  (L.Commodity, L.DateTime)+  -> [L.PricePoint]+  -> [L.Box Ly.LibertyMeta]+  -> Ex.Exceptional X.Text PriceConverteds+converter conv pbs bs =     let f b = let p = L.boxPostFam b                   en = Q.entry p                   ac = Q.account p                  in do-                   en' <- convertOne db pair en+                   en' <- convertOne db conv en                    return (PriceConverted en' ac)         db = buildDb pbs-    in mapM f bs+    in fmap PriceConverteds $ mapM f bs   -- Step 2. This puts all the PriceConverteds into a flat map, where@@ -120,9 +135,9 @@ -- the user desired, zero balances are eliminated from the flat map. newtype FlatMap = FlatMap { _unFlatMap :: M.Map L.Account Bal.Balance } -toFlatMap :: O.Options -> [PriceConverted] -> FlatMap-toFlatMap o = FlatMap . foldr f M.empty where-  remove = not . CO.unShowZeroBalances . O.showZeroBalances $ o+toFlatMap :: TreeOpts -> PriceConverteds -> FlatMap+toFlatMap o = FlatMap . foldr f M.empty . unPriceConverteds where+  remove = not . CO.unShowZeroBalances . showZeroBalances $ o   f pc m =     let a = pcAccount pc         bal = Bal.entryToBalance . pcEntry $ pc@@ -236,7 +251,7 @@ -- | Returns a triple (x, y, z), where x is the DrCr chunk, y is the -- commodity chunk, and z is the qty chunk. bottomLineBalChunks ::-  O.Options+  TreeOpts   -> IsEven   -> (L.Commodity, Bal.BottomLine)   -> (Chunk.Chunk, Chunk.Chunk, Chunk.Chunk)@@ -250,7 +265,7 @@       getTs = if isEven then C.evenZero else C.oddZero       dcT = X.pack "--"       qtyT = dcT-      in (getTs . O.drCrColors $ os, dcT, qtyT)+      in (getTs . drCrColors $ os, dcT, qtyT)     Bal.NonZero clm -> let       (getTs, dcT) = case Bal.drCr clm of         L.Debit ->@@ -259,29 +274,29 @@         L.Credit ->           (if isEven then C.evenCredit else C.oddCredit,            X.pack "Cr")-      qTxt = (O.balanceFormat os) bl-      in (getTs . O.drCrColors $ os, dcT, qTxt)+      qTxt = (balanceFormat os) bl+      in (getTs . drCrColors $ os, dcT, qTxt)   fillTextSpec ::-  O.Options+  TreeOpts   -> IsEven   -> Chunk.TextSpec fillTextSpec os isEven = let   getTs = if isEven then C.evenColors else C.oddColors-  in getTs . O.baseColors $ os+  in getTs . baseColors $ os     bottomLineCells ::-  O.Options+  TreeOpts   -> IsEven   -> SummedBal   -> (PreSpec, PreSpec, PreSpec) bottomLineCells os isEven mayBal = let   fill = fillTextSpec os isEven   tsZero = if isEven-           then C.evenZero . O.drCrColors $ os-           else C.oddZero . O.drCrColors $ os+           then C.evenZero . drCrColors $ os+           else C.oddZero . drCrColors $ os   zeroSpec =     PreSpec R.LeftJustify     tsZero [Chunk.chunk tsZero (X.pack "--")]@@ -298,7 +313,7 @@ padding = 2  accountPreSpec ::-  O.Options+  TreeOpts   -> IsEven   -> Int   -> L.SubAccountName@@ -306,15 +321,15 @@ accountPreSpec os isEven lvl acct = PreSpec j ts [bit] where   j = R.LeftJustify   ts = if isEven-       then C.evenColors . O.baseColors $ os-       else C.oddColors . O.baseColors $ os+       then C.evenColors . baseColors $ os+       else C.oddColors . baseColors $ os   bit = Chunk.chunk ts txt where     txt = pad `X.append` (L.text acct)     pad = X.replicate (padding * lvl) (X.singleton ' ')   makePreSpec ::-  O.Options+  TreeOpts   -> [(L.SubAccountName, (SummedBal, Bool))]   -> L.SubAccountName   -> (SummedBal, Bool)@@ -325,7 +340,7 @@   (dc, com, qt) = bottomLineCells os isEven mayBal  traverser ::-  O.Options+  TreeOpts   -> [(L.SubAccountName, (SummedBal, Bool))]   -> L.SubAccountName   -> (SummedBal, Bool)@@ -335,7 +350,7 @@   return (Just $ makePreSpec os hist a mayBal)  makePreSpecMap ::-  O.Options+  TreeOpts   -> (SummedWithIsEven, TotalBal)   -> (PreSpecMap, TotalBal) makePreSpecMap os (sb, tb) = (cim, tb) where@@ -343,7 +358,7 @@  -- Step 7 makeTotalCells ::-  O.Options+  TreeOpts   -> SummedBal   -> Columns PreSpec makeTotalCells os mayBal = Columns act dc com qt where@@ -351,7 +366,7 @@   tot = L.SubAccountName $ L.TextNonEmpty 'T' (X.pack "otal")   (dc, com, qt) = bottomLineCells os True mayBal -makeColumnList :: O.Options -> (PreSpecMap, TotalBal) -> [Columns PreSpec]+makeColumnList :: TreeOpts -> (PreSpecMap, TotalBal) -> [Columns PreSpec] makeColumnList os (cim, tb) = totCols : restCols where   totCols = makeTotalCells os tb   restCols = Fdbl.toList cim@@ -398,14 +413,14 @@ widthSpacerCommodity = 1  colsToBits ::-  O.Options+  TreeOpts   -> IsEven   -> Columns R.ColumnSpec   -> [Chunk.Chunk] colsToBits os isEven (Columns a dc c q) = let   fillSpec = if isEven-             then C.evenColors . O.baseColors $ os-             else C.oddColors . O.baseColors $ os+             then C.evenColors . baseColors $ os+             else C.oddColors . baseColors $ os   spacer w = R.ColumnSpec j (Chunk.Width w) fillSpec []   j = R.LeftJustify   cs = a@@ -419,7 +434,7 @@   in R.row cs  colsListToBits ::-  O.Options+  TreeOpts   -> [Columns R.ColumnSpec]   -> [[Chunk.Chunk]] colsListToBits os = zipWith f bools where@@ -427,17 +442,22 @@   bools = iterate not True  +-- Options+data TreeOpts = TreeOpts {+  drCrColors :: C.DrCrColors+  , baseColors :: C.BaseColors+  , balanceFormat :: L.BottomLine -> X.Text+  , showZeroBalances :: CO.ShowZeroBalances+  }+ -- Tie it all together  report ::-  O.Options-  -> [L.Box Ly.LibertyMeta]-  -> [L.PricePoint]-  -> Ex.Exceptional X.Text [[Chunk.Chunk]]-report os ps rs = do-  pcs <- converter os rs ps-  return-    . colsListToBits os+  TreeOpts+  -> PriceConverteds+  -> [[Chunk.Chunk]]+report os  =+    colsListToBits os     . resizeColumnsInList     . makeColumnList os     . makePreSpecMap os@@ -445,4 +465,4 @@     . sumBalances     . rawBalances     . toFlatMap os-    $ pcs+
Penny/Cabin/Posts.hs view
@@ -34,113 +34,363 @@ -- configurable without editing the source code (sorry).  module Penny.Cabin.Posts (-  -- * Defaults-  defaultPostsReport-  -  -- * Custom report-  , customPostsReport--  -- * Options-  , O.T(..)-  , O.ReportWidth(..)-  , O.ymd, O.qtyAsIs, O.balanceAsIs, O.defaultWidth-  , O.columnsVarToWidth, O.defaultOptions, O.widthFromRuntime-  , O.defaultFields+  postsReport+  , parseReport+  , makeReport+  , defaultOptions+  , ZincOpts(..)+  , ymd+  , qtyAsIs+  , balanceAsIs+  , defaultWidth+  , columnsVarToWidth+  , widthFromRuntime+  , defaultFields+  , defaultSpacerWidth   ) where -import Control.Applicative ((<$>)) import qualified Control.Monad.Exception.Synchronous as Ex import qualified Data.Text as X import qualified Data.Text.Lazy as XL-import qualified Penny.Cabin.Chunk as Chk+import qualified Penny.Cabin.Chunk as CC+import qualified Penny.Cabin.Colors as PC+import qualified Penny.Cabin.Colors.DarkBackground as Dark import qualified Penny.Cabin.Interface as I-import qualified Penny.Cabin.Posts.Options as O+import qualified Penny.Cabin.Options as CO+import qualified Penny.Cabin.Posts.Allocated as A+import qualified Penny.Cabin.Posts.Allocate as Alc+import qualified Penny.Cabin.Posts.Chunk as C+import qualified Penny.Cabin.Posts.Fields as F+import qualified Penny.Cabin.Posts.Help as H import qualified Penny.Cabin.Posts.Meta as M-import Penny.Cabin.Posts.Chunk (makeChunk)-import Penny.Cabin.Posts.Parser (parseOptions)-import Penny.Cabin.Posts.Help (help)-import qualified Penny.Copper as C+import Penny.Cabin.Posts.Meta (Box)+import qualified Penny.Cabin.Posts.Parser as P+import qualified Penny.Cabin.Posts.Spacers as S+import qualified Penny.Cabin.Posts.Types as T++import qualified Penny.Copper as Cop import qualified Penny.Lincoln as L+import qualified Penny.Lincoln.Balance as Bal+import qualified Penny.Lincoln.Queries as Q import qualified Penny.Liberty as Ly-import qualified Penny.Shield as S+import qualified Penny.Shield as Sh++import Data.Time as Time import System.Console.MultiArg.Prim (Parser)+import System.Locale (defaultTimeLocale) import Text.Matchers.Text (CaseSensitive) --- | When applied to a DefaultTimeZone and a RadGroup, returns a--- report with the default options.-defaultPostsReport ::-  C.DefaultTimeZone-  -> C.RadGroup-  -> I.Report-defaultPostsReport dtz rg = makeReport f where-  f = parseReportOpts (\rt -> O.defaultOptions dtz rg rt)+-- | All information needed to make a Posts report. This function+-- never fails.+postsReport ::+  CC.Colors+  -- ^ How many colors to show.+  -> CO.ShowZeroBalances+  -> (L.Box Ly.LibertyMeta -> Bool)+  -- ^ Removes posts from the report if applying this function to the+  -- post returns False. Posts removed still affect the running+  -- balance.+  +  -> [Ly.PostFilterFn]+  -- ^ Applies these post-filters to the list of posts that results+  -- from applying the predicate above. Might remove more+  -- postings. Postings removed still affect the running balance.+    +  -> C.ChunkOpts+  -> [L.Box Ly.LibertyMeta]+  -> XL.Text --- | Generate a custom Posts report.-customPostsReport ::-  (S.Runtime -> O.T)-  -- ^ Function that, when applied to a Runtime, returns the default-  -- options for the posts report. The options will be overridden by-  -- any options on the command line.+postsReport col szb pdct pff co =+  CC.chunksToText col+  . C.makeChunk co+  . M.toBoxList szb pdct pff -  -> I.Report-customPostsReport = makeReport . parseReportOpts --- | When passed a ParseReportOpts, makes a Report.+parseReport ::+  (Sh.Runtime -> ZincOpts)+  -> Parser I.ReportFunc+parseReport frt = do+  getState <- P.parseOptions+  let rf rt cs fty ps _ = do+        let zo = frt rt+            maySt' = getState rt dtz rg st+              where+                dtz = defaultTimeZone zo+                rg = radGroup zo+                st = newParseState cs fty zo+        st' <- Ex.mapException showParserError maySt'+        pdct <- getPredicate . P.tokens $ st'+        return $ postsReport (P.colorPref st')+          (P.showZeroBalances st') pdct+          (P.postFilter st') (chunkOpts st' zo) ps+  return rf+                 +             makeReport ::-  Parser I.ReportFunc+  (Sh.Runtime -> ZincOpts)   -> I.Report-makeReport f =-  I.Report { I.help = help-           , I.name = "posts"-           , I.parseReport = f }+makeReport frt = I.Report {+  I.help = H.help+  , I.name = "postings"+  , I.parseReport = parseReport frt } -type Factory = CaseSensitive -> X.Text-                 -> Ex.Exceptional X.Text (X.Text -> Bool) -parseReportOpts ::-  (S.Runtime -> O.T)-  -> Parser (S.Runtime-             -> CaseSensitive-             -> Factory-             -> [L.Box Ly.LibertyMeta]-             -> a-             -> Ex.Exceptional X.Text XL.Text)-parseReportOpts frt = do-  getOpts <- parseOptions-  let f rt cs fty bs _ = do-        let optsDefault = frt rt-            optsInit = optsDefault { O.sensitive = cs-                                   , O.factory = fty }-        optsParsed <- case getOpts rt optsInit of-          Ex.Exception e -> Ex.throw . X.pack . show $ e-          Ex.Success g -> return g-        makeReportTxt optsParsed bs-  return f-            +defaultOptions ::+  Cop.DefaultTimeZone+  -> Cop.RadGroup+  -> Sh.Runtime+  -> ZincOpts+defaultOptions dtz rg rt = ZincOpts {+  defaultTimeZone = dtz+  , radGroup = rg+  , fields = defaultFields+  , colorPref = CO.maxCapableColors rt+  , drCrColors = Dark.drCrColors+  , baseColors = Dark.baseColors+  , width = widthFromRuntime rt+  , showZeroBalances = CO.ShowZeroBalances False+  , dateFormat = ymd+  , qtyFormat = qtyAsIs+  , balanceFormat = balanceAsIs+  , subAccountLength = A.SubAccountLength 2+  , payeeAllocation = Alc.allocation 60+  , accountAllocation = Alc.allocation 40+  , spacers = defaultSpacerWidth } --- | Using the options parsed from the command line, print out the--- report.-makeReportTxt ::-  O.T-  -> [L.Box Ly.LibertyMeta]-  -> Ex.Exceptional X.Text XL.Text-makeReportTxt op bs = fmap mkText postMetaBoxes-  where-    e = X.pack "posts report: filter expression parse failure"-    postMetaBoxes = Ex.fromMaybe e (filterAndAssignMeta op bs)-    mkText = Chk.chunksToText (O.colorPref op) . makeChunk op-     --- | Takes a list of Box with LibertyMeta and options as processed--- from the command line.  Filters the list of Box and processes the--- post filter, then assigns the post metadata. Fails if the--- expression fails to produce a result.-filterAndAssignMeta ::-  O.T-  -> [L.Box Ly.LibertyMeta]-  -> Maybe [L.Box M.PostMeta]-filterAndAssignMeta op bs =-  M.addMetadata (O.showZeroBalances op)-  <$> M.filterBoxes (O.tokens op) (O.postFilter op) bs+showParserError :: P.Error -> X.Text+showParserError = X.pack . show +getPredicate ::+  [Ly.Token (L.Box Ly.LibertyMeta -> Bool)]+  -> Ex.Exceptional X.Text (L.Box Ly.LibertyMeta -> Bool)+getPredicate ts =+  case ts of+    [] -> return $ const True+    ls ->+      Ex.fromMaybe+        (X.pack "posts report: bad posting filter expression")+        (Ly.parseTokenList ls) ++-- | All the information to configure the postings report if the+-- options will be parsed in from the command line.+data ZincOpts = ZincOpts {+  defaultTimeZone :: Cop.DefaultTimeZone+  -- ^ The postings report takes options to determine which posts will+  -- be visible. This determines the time zone to use when parsing+  -- these options. Does not affect how the resulting report is+  -- formatted. For that, see the dateFormat field.+  +  , radGroup :: Cop.RadGroup+    -- ^ The postings report takes options to determine which posts+    -- will be visible. This determines the radix point and grouping+    -- character to use when parsing these options. Does not affect+    -- how the resulting report is formatted. For that, see the+    -- qtyFormat field.++  , fields :: F.Fields Bool+    -- ^ Default fields to show in the report.+      +  , colorPref :: CC.Colors+    -- ^ How many colors you want to see, or do it+    -- automatically.++  , drCrColors :: PC.DrCrColors+    -- ^ Colors to use when displaying debits, credits, and+    -- when displaying balance totals++  , baseColors :: PC.BaseColors+    -- ^ Colors to use when displaying everything else++  , width :: T.ReportWidth+    -- ^ Gives the default report width. This can be+    -- overridden on the command line. You can use the+    -- information from the Runtime to make this as wide as+    -- the current terminal.++  , showZeroBalances :: CO.ShowZeroBalances+    -- ^ Are commodities that have no balance shown in the Total fields+    -- of the report?++  , dateFormat :: Box -> X.Text+    -- ^ How to display dates. This function is applied to the+    -- a PostingInfo so it has lots of information, but it+    -- should return a date for use in the Date field.++  , qtyFormat :: Box -> X.Text+    -- ^ How to display the quantity of the posting. This+    -- function is applied to a Box so it has lots of+    -- information, but it should return a formatted string of+    -- the quantity. Allows you to format digit grouping,+    -- radix points, perform rounding, etc.++  , balanceFormat :: L.Commodity -> L.BottomLine -> X.Text+    -- ^ How to display balance totals. Similar to+    -- balanceFormat.++  , subAccountLength :: A.SubAccountLength+    -- ^ When shortening the names of sub accounts to make+    -- them fit, they will be this long.++  , payeeAllocation :: Alc.Allocation+    -- ^ This and accountAllocation determine how much space+    -- payees and accounts receive. They divide up the+    -- remaining space after everything else is displayed. For+    -- instance if payeeAllocation is 60 and accountAllocation+    -- is 40, the payee takes about 60 percent of the+    -- remaining space and the account takes about 40 percent.++  , accountAllocation :: Alc.Allocation+    -- ^ See payeeAllocation above++  , spacers :: S.Spacers Int+    -- ^ Default width for spacer fields. If any of these Ints are+    -- less than or equal to zero, there will be no spacer. There is+    -- never a spacer for fields that do not appear in the report.+      +  }++chunkOpts ::+  P.State +  -> ZincOpts+  -> C.ChunkOpts+chunkOpts s z = C.ChunkOpts {+  C.baseColors = P.baseColors s+  , C.drCrColors = P.drCrColors s+  , C.dateFormat = dateFormat z+  , C.qtyFormat = qtyFormat z+  , C.balanceFormat = balanceFormat z+  , C.fields = P.fields s+  , C.subAccountLength = subAccountLength z+  , C.payeeAllocation = payeeAllocation z+  , C.accountAllocation = accountAllocation z+  , C.spacers = spacers z+  , C.reportWidth = P.width s+  }+++newParseState ::+  CaseSensitive+  -> L.Factory+  -> ZincOpts+  -> P.State+newParseState cs fty o = P.State {+  P.sensitive = cs+  , P.factory = fty+  , P.tokens = []+  , P.postFilter = []+  , P.fields = fields o+  , P.colorPref = colorPref o+  , P.drCrColors = drCrColors o+  , P.baseColors = baseColors o+  , P.width = width o+  , P.showZeroBalances = showZeroBalances o+  }++-- | Shows the date of a posting in YYYY-MM-DD format.+ymd :: Box -> X.Text+ymd p = X.pack (Time.formatTime defaultTimeLocale fmt d) where+  d = Time.localDay+      . L.localTime+      . Q.dateTime+      . L.boxPostFam+      $ p+  fmt = "%Y-%m-%d"++-- | Shows the quantity of a posting. Does no rounding or+-- prettification; simply uses show on the underlying Decimal.+qtyAsIs :: Box -> X.Text+qtyAsIs p = X.pack . show . L.unQty . Q.qty . L.boxPostFam $ p++-- | Shows the quantity of a balance. If there is no quantity, shows+-- two dashes.+balanceAsIs :: a -> L.BottomLine -> X.Text+balanceAsIs _ n = case n of+  L.Zero -> X.pack "--"+  L.NonZero c -> X.pack . show . L.unQty . Bal.qty $ c++-- | The default width for the report.+defaultWidth :: T.ReportWidth+defaultWidth = T.ReportWidth 80++-- | Applied to the value of the COLUMNS environment variable, returns+-- an appropriate ReportWidth.+columnsVarToWidth :: Maybe String -> T.ReportWidth+columnsVarToWidth ms = case ms of+  Nothing -> defaultWidth+  Just str -> case reads str of+    [] -> defaultWidth+    (i, []):[] -> if i > 0 then T.ReportWidth i else defaultWidth+    _ -> defaultWidth++-- | Given the Runtime, use the defaultWidth given above to calculate+-- the report's width if COLUMNS does not yield a value. Otherwise,+-- use what is in COLUMNS.+widthFromRuntime :: Sh.Runtime -> T.ReportWidth+widthFromRuntime rt = case Sh.screenWidth rt of+  Nothing -> defaultWidth+  Just w -> T.ReportWidth . Sh.unScreenWidth $ w++-- | Default fields to show in the Postings report.+defaultFields :: F.Fields Bool+defaultFields =+  F.Fields { F.globalTransaction    = False+           , F.revGlobalTransaction = False+           , F.globalPosting        = False+           , F.revGlobalPosting     = False+           , F.fileTransaction      = False+           , F.revFileTransaction   = False+           , F.filePosting          = False+           , F.revFilePosting       = False+           , F.filtered             = False+           , F.revFiltered          = False+           , F.sorted               = False+           , F.revSorted            = False+           , F.visible              = False+           , F.revVisible           = False+           , F.lineNum              = False+           , F.date                 = True+           , F.flag                 = False+           , F.number               = False+           , F.payee                = True+           , F.account              = True+           , F.postingDrCr          = True+           , F.postingCmdty         = True+           , F.postingQty           = True+           , F.totalDrCr            = True+           , F.totalCmdty           = True+           , F.totalQty             = True+           , F.tags                 = False+           , F.memo                 = False+           , F.filename             = False }++-- | Default width of spacers; most are one character wide, but the+-- spacer after payee is 4 characters wide.+defaultSpacerWidth :: S.Spacers Int+defaultSpacerWidth =+  S.Spacers { S.globalTransaction    = 1+            , S.revGlobalTransaction = 1+            , S.globalPosting        = 1+            , S.revGlobalPosting     = 1+            , S.fileTransaction      = 1+            , S.revFileTransaction   = 1+            , S.filePosting          = 1+            , S.revFilePosting       = 1+            , S.filtered             = 1+            , S.revFiltered          = 1+            , S.sorted               = 1+            , S.revSorted            = 1+            , S.visible              = 1+            , S.revVisible           = 1+            , S.lineNum              = 1+            , S.date                 = 1+            , S.flag                 = 1+            , S.number               = 1+            , S.payee                = 4+            , S.account              = 1+            , S.postingDrCr          = 1+            , S.postingCmdty         = 1+            , S.postingQty           = 1+            , S.totalDrCr            = 1+            , S.totalCmdty           = 1 }
Penny/Cabin/Posts/Allocated.hs view
@@ -29,7 +29,12 @@ -- arrangements are made if either field gets an allocation of 0. -- -- 5. Fill cell contents. Return filled cells.-module Penny.Cabin.Posts.Allocated (payeeAndAcct, Fields(..)) where+module Penny.Cabin.Posts.Allocated (+  payeeAndAcct+  , AllocatedOpts(..)+  , Fields(..)+  , SubAccountLength(..)+  ) where  import Control.Applicative(Applicative((<*>), pure), (<$>)) import Data.Maybe (catMaybes, isJust)@@ -42,25 +47,37 @@ import qualified Penny.Cabin.Row as R import qualified Penny.Cabin.Posts.Allocate as A import qualified Penny.Cabin.Colors as PC-import qualified Penny.Cabin.Posts.Fields as F import qualified Penny.Cabin.Posts.Growers as G import qualified Penny.Cabin.Posts.Meta as M-import qualified Penny.Cabin.Posts.Options as Options-import qualified Penny.Cabin.Posts.Options as O+import Penny.Cabin.Posts.Meta (Box) import qualified Penny.Cabin.Posts.Spacers as S-import qualified Penny.Cabin.Posts.Spacers as Spacers+import qualified Penny.Cabin.Posts.Types as Ty import qualified Penny.Cabin.TextFormat as TF import qualified Penny.Lincoln as L import qualified Penny.Lincoln.Queries as Q import qualified Penny.Lincoln.HasText as HT -type Box = L.Box M.PostMeta - data Fields a = Fields {   payee :: a   , account :: a   } deriving (Eq, Show) +newtype SubAccountLength =+  SubAccountLength { unSubAccountLength :: Int }+  deriving Show++-- | All the information needed for allocated cells.+data AllocatedOpts = AllocatedOpts {+  fields :: Fields Bool+  , subAccountLength :: SubAccountLength+  , baseColors :: PC.BaseColors+  , payeeAllocation :: A.Allocation+  , accountAllocation :: A.Allocation+  , spacers :: S.Spacers Int+  , growerWidths :: G.Fields (Maybe Int)+  , reportWidth :: Ty.ReportWidth+  }+ -- | Creates Payee and Account cells. The user must have requested the -- cells. In addition, no cells are created if there is not enough -- space for them in the report. Returns a Fields; each element of the@@ -69,31 +86,36 @@ -- where cs is a list of all the cells, and i is the width of all the -- cells. payeeAndAcct ::-  G.Fields (Maybe Int)-  -> Options.T+  AllocatedOpts   -> [Box]   -> Fields (Maybe ([R.ColumnSpec], Int))-payeeAndAcct fs os = allocateCells os ws where-  ws = fieldWidth os ss fs rw-  ss = O.spacers os-  rw = O.width os+payeeAndAcct as = allocateCells sl bc ws+  where+    sl = subAccountLength as+    bc = baseColors as+    ws = fieldWidth (fields as) (payeeAllocation as)+         (accountAllocation as) (spacers as)+         (growerWidths as) (reportWidth as)   -- | Allocates cells. Returns a pair, with the first element being the -- list of allocated cells, and the second indicating the width of the -- cells, which will be greater than zero. allocateCells ::-  Options.T-  -> Fields Int+  SubAccountLength+  -> PC.BaseColors+  -> Fields UnShrunkWidth   -> [Box]   -> Fields (Maybe ([R.ColumnSpec], Int))-allocateCells os fs is = let-  cellMakers = Fields allocPayee allocAcct-  mkCells width maker =-    if width > 0-    then Just (map (maker width os) is)-    else Nothing-  unShrunkCells = mkCells <$> fs <*> cellMakers+allocateCells sl bc fs bs =+  let mkPayees i b = allocPayee i bc b+      mkAccts i b = allocAcct i sl bc b+      cellMakers = Fields mkPayees mkAccts+      mkCells (UnShrunkWidth width) maker =+        if width > 0+        then Just (map (maker width) bs)+        else Nothing+      unShrunkCells = mkCells <$> fs <*> cellMakers   in fmap (fmap removeExtraSpace) unShrunkCells  @@ -109,32 +131,32 @@   trimmed = map f cs where     f c = c { R.width = C.Width len } +-- | The width of an on-screen field, after accounting for the width+-- of the entire report and the allocations but before shrinking.+newtype UnShrunkWidth = UnShrunkWidth Int+                      deriving Show+ -- | Gets the width of the two allocated fields. fieldWidth ::-  Options.T-  -> Spacers.T Int+  Fields Bool+  -> A.Allocation -- ^ Payee allocation+  -> A.Allocation -- ^ Accout allocation+  -> S.Spacers Int   -> G.Fields (Maybe Int)-  -> O.ReportWidth-  -> Fields Int-fieldWidth os ss fs (O.ReportWidth rw) = let-  flds = optionsToFields os-  grownWidth = sumGrowersAndSpacers fs ss-  widthForCells = rw - grownWidth - allocSpacerWidth-  payeeSpacerWidth = if payee flds then abs (S.payee ss) else 0-  acctSpacerWidth = if account flds then abs (S.account ss) else 0-  allocSpacerWidth = payeeSpacerWidth + acctSpacerWidth-  allocs = (\bool alloc -> if bool then alloc else A.allocation 0)-           <$> flds-           <*> Fields (O.payeeAllocation os) (O.accountAllocation os)+  -> Ty.ReportWidth+  -> Fields UnShrunkWidth+fieldWidth flds pa aa ss fs (Ty.ReportWidth rw) =+  let grownWidth = sumGrowersAndSpacers fs ss+      widthForCells = rw - grownWidth - allocSpacerWidth+      payeeSpacerWidth = if payee flds then abs (S.payee ss) else 0+      acctSpacerWidth = if account flds then abs (S.account ss) else 0+      allocSpacerWidth = payeeSpacerWidth + acctSpacerWidth+      allocs = (\bool alloc -> if bool then alloc else A.allocation 0)+               <$> flds+               <*> Fields pa aa   in if widthForCells < 1-     then pure 0-     else A.allocate allocs widthForCells---optionsToFields :: Options.T -> Fields Bool-optionsToFields os = let f = O.fields os in Fields {-  payee = F.payee f-  , account = F.account f }+     then pure (UnShrunkWidth 0)+     else fmap UnShrunkWidth $ A.allocate allocs widthForCells   -- | Sums spacers for growing cells. This function is intended for use@@ -147,7 +169,7 @@ -- Spacers. sumSpacers ::   G.Fields (Maybe a)-  -> Spacers.T Int+  -> S.Spacers Int   -> Int sumSpacers fs =   sum@@ -201,7 +223,7 @@ -- the GFields, which indicates each particular field. pairedWithSpacers ::   G.Fields a-  -> Spacers.T b+  -> S.Spacers b   -> G.Fields (a, Maybe b, G.EFields) pairedWithSpacers f s =   (\(a, b) c -> (a, b, c))@@ -212,56 +234,67 @@ -- spacers; makes the adjustments described in sumSpacers. sumGrowersAndSpacers ::   G.Fields (Maybe Int)-  -> Spacers.T Int+  -> S.Spacers Int   -> Int-sumGrowersAndSpacers fs ss = spacers + flds where-  spacers = sumSpacers fs ss+sumGrowersAndSpacers fs ss = spcrs + flds where+  spcrs = sumSpacers fs ss   flds = Fdbl.foldr f 0 fs where     f maybeI acc = case maybeI of       Nothing -> acc       Just i -> acc + i  -allocPayee :: Int -> Options.T -> Box -> R.ColumnSpec-allocPayee w os i = let-  pb = L.boxPostFam i-  ts = PC.colors (M.visibleNum . L.boxMeta $ i) (O.baseColors os)-  c = R.ColumnSpec j (C.Width w) ts sq-  j = R.LeftJustify-  sq = case Q.payee pb of-    Nothing -> []-    Just pye -> let-      wrapped =-        Fdbl.toList-        . TF.unLines -        . TF.wordWrap w-        . TF.txtWords-        . HT.text-        $ pye-      toBit (TF.Words seqTxts) =-        C.chunk ts-        . X.unwords-        . Fdbl.toList-        $ seqTxts-      in fmap toBit wrapped+allocPayee ::+  Int+  -- ^ Width that is permitted for this column+  -> PC.BaseColors+  -> Box+  -> R.ColumnSpec+allocPayee w bc i =+  let pb = L.boxPostFam i+      ts = PC.colors (M.visibleNum . L.boxMeta $ i) bc+      c = R.ColumnSpec j (C.Width w) ts sq+      j = R.LeftJustify+      sq = case Q.payee pb of+        Nothing -> []+        Just pye ->+          let wrapped =+                Fdbl.toList+                . TF.unLines +                . TF.wordWrap w+                . TF.txtWords+                . HT.text+                $ pye+              toBit (TF.Words seqTxts) =+                C.chunk ts+                . X.unwords+                . Fdbl.toList+                $ seqTxts+          in fmap toBit wrapped   in c  -allocAcct :: Int -> Options.T -> Box -> R.ColumnSpec-allocAcct aw os i = let-  pb = L.boxPostFam i-  ts = PC.colors (M.visibleNum . L.boxMeta $ i) (O.baseColors os) in-  R.ColumnSpec R.LeftJustify (C.Width aw) ts $ let-    target = TF.Target aw-    shortest = TF.Shortest . O.subAccountLength $ os-    a = Q.account pb-    ws = TF.Words . Seq.fromList . HT.textList $ a-    (TF.Words shortened) = TF.shorten shortest target ws-    in [C.chunk ts-       . X.concat-       . intersperse (X.singleton ':')-       . Fdbl.toList-       $ shortened]+allocAcct ::+  Int+  -- ^ Width that is permitted for this column+  -> SubAccountLength+  -> PC.BaseColors+  -> Box+  -> R.ColumnSpec+allocAcct aw sl bc i =+  let pb = L.boxPostFam i+      ts = PC.colors (M.visibleNum . L.boxMeta $ i) bc+  in R.ColumnSpec R.LeftJustify (C.Width aw) ts $+     let target = TF.Target aw+         shortest = TF.Shortest . unSubAccountLength $ sl+         a = Q.account pb+         ws = TF.Words . Seq.fromList . HT.textList $ a+         (TF.Words shortened) = TF.shorten shortest target ws+     in [C.chunk ts+         . X.concat+         . intersperse (X.singleton ':')+         . Fdbl.toList+         $ shortened]  instance Functor Fields where   fmap f i = Fields {
Penny/Cabin/Posts/BottomRows.hs view
@@ -17,6 +17,7 @@ -- combined. Each bottom row will have one cell.  module Penny.Cabin.Posts.BottomRows (+  BottomOpts(..),   bottomRows, Fields(..), TopRowCells(..), mergeWithSpacers,   topRowCells) where @@ -35,31 +36,34 @@ import qualified Penny.Cabin.TextFormat as TF import qualified Penny.Cabin.Posts.Allocated as A import qualified Penny.Cabin.Colors as PC-import qualified Penny.Cabin.Posts.Fields as Fields import qualified Penny.Cabin.Posts.Fields as F import qualified Penny.Cabin.Posts.Growers as G import qualified Penny.Cabin.Posts.Meta as M-import qualified Penny.Cabin.Posts.Options as Options-import qualified Penny.Cabin.Posts.Options as O-import qualified Penny.Cabin.Posts.Spacers as Spacers+import Penny.Cabin.Posts.Meta (Box) import qualified Penny.Cabin.Posts.Spacers as S+import qualified Penny.Cabin.Posts.Types as Ty import qualified Penny.Lincoln as L import qualified Penny.Lincoln.HasText as HT import qualified Penny.Lincoln.Queries as Q -type Box = L.Box M.PostMeta +data BottomOpts = BottomOpts {+  growingWidths :: G.Fields (Maybe Int)+  , allocatedWidths :: A.Fields (Maybe Int)+  , fields :: F.Fields Bool+  , baseColors :: PC.BaseColors+  , reportWidth :: Ty.ReportWidth+  , spacers :: S.Spacers Int+  }  bottomRows ::-  G.Fields (Maybe Int)-  -> A.Fields (Maybe Int)-  -> Options.T+  BottomOpts   -> [Box]   -> Fields (Maybe [[C.Chunk]])-bottomRows gf af os is = makeRows is pcs where-  pcs = infoProcessors topSpecs rw wanted-  wanted = requestedMakers os-  topSpecs = topCellSpecs gf af (O.spacers os)-  rw = O.width os+bottomRows os bs = makeRows bs pcs where+  pcs = infoProcessors topSpecs (reportWidth os) wanted+  wanted = requestedMakers (fields os) (baseColors os)+  topSpecs = topCellSpecs (growingWidths os) (allocatedWidths os)+             (spacers os)   data Fields a = Fields {@@ -86,7 +90,7 @@     , filename = (filename ff) (filename fa)     } -bottomRowsFields :: Fields.T a -> Fields a+bottomRowsFields :: F.Fields a -> Fields a bottomRowsFields f = Fields {   tags = F.tags f   , memo = F.memo f@@ -137,16 +141,16 @@   widthOfReport ::-  O.ReportWidth+  Ty.ReportWidth   -> (Box -> Int -> (C.TextSpec, R.ColumnSpec))   -> Box   -> [C.Chunk]-widthOfReport (O.ReportWidth rw) fn info =+widthOfReport (Ty.ReportWidth rw) fn info =   makeSpecificWidth rw fn info  chooseProcessor ::   [TopCellSpec]-  -> O.ReportWidth+  -> Ty.ReportWidth   -> (Box -> Int -> (C.TextSpec, R.ColumnSpec))   -> Box   -> [C.Chunk]@@ -159,7 +163,7 @@  infoProcessors ::   [TopCellSpec]-  -> O.ReportWidth+  -> Ty.ReportWidth   -> Fields (Maybe (Box -> Int -> (C.TextSpec, R.ColumnSpec)))   -> Fields (Maybe (Box -> [C.Chunk])) infoProcessors specs rw flds = let@@ -218,7 +222,7 @@  topCellSpecs :: G.Fields (Maybe Int)                 -> A.Fields (Maybe Int)-                -> Spacers.T Int+                -> S.Spacers Int                 -> [TopCellSpec] topCellSpecs gFlds aFlds spcs = let   allFlds = topRowCells gFlds aFlds@@ -236,7 +240,7 @@ -- totalQty has no spacer. mergeWithSpacers ::   TopRowCells a-  -> Spacers.T b+  -> S.Spacers b   -> TopRowCells (a, Maybe b) mergeWithSpacers t s = TopRowCells {   globalTransaction = (globalTransaction t, Just (S.globalTransaction s))@@ -275,7 +279,7 @@   (_, c) = f i w  -type Maker = Options.T -> Box -> Int -> (C.TextSpec, R.ColumnSpec)+type Maker = PC.BaseColors -> Box -> Int -> (C.TextSpec, R.ColumnSpec)  makers :: Fields Maker makers = Fields tagsCell memoCell filenameCell@@ -284,18 +288,19 @@ -- returns a Fields (Maybe Maker) with a Maker in each respective -- field that the user wants to see. requestedMakers ::-  Options.T+  F.Fields Bool+  -> PC.BaseColors   -> Fields (Maybe (Box -> Int -> (C.TextSpec, R.ColumnSpec)))-requestedMakers os = let-  flds = bottomRowsFields (O.fields os)-  filler b mkr = if b then Just $ mkr os else Nothing+requestedMakers allFlds bc =+  let flds = bottomRowsFields allFlds+      filler b mkr = if b then Just $ mkr bc else Nothing   in filler <$> flds <*> makers -tagsCell :: Options.T -> Box -> Int -> (C.TextSpec, R.ColumnSpec)-tagsCell os info w = (ts, cell) where+tagsCell :: PC.BaseColors -> Box -> Int -> (C.TextSpec, R.ColumnSpec)+tagsCell bc info w = (ts, cell) where   vn = M.visibleNum . L.boxMeta $ info   cell = R.ColumnSpec R.LeftJustify (C.Width w) ts cs-  ts = PC.colors vn (O.baseColors os)+  ts = PC.colors vn bc   cs =     Fdbl.toList     . fmap toBit@@ -328,12 +333,12 @@   toBit (TF.Words ws) = C.chunk ts (X.unwords . Fdbl.toList $ ws)  -memoCell :: Options.T -> Box -> Int -> (C.TextSpec, R.ColumnSpec)-memoCell os info width = (ts, cell) where+memoCell :: PC.BaseColors -> Box -> Int -> (C.TextSpec, R.ColumnSpec)+memoCell bc info width = (ts, cell) where   w = C.Width width   vn = M.visibleNum . L.boxMeta $ info   cell = R.ColumnSpec R.LeftJustify w ts cs-  ts = PC.colors vn (O.baseColors os)+  ts = PC.colors vn bc   pm = Q.postingMemo . L.boxPostFam $ info   tm = Q.transactionMemo . L.boxPostFam $ info   nullMemo (L.Memo m) = null m@@ -344,8 +349,8 @@     (False, False) -> memoBits ts pm w `mappend` memoBits ts tm w    -filenameCell :: Options.T -> Box -> Int -> (C.TextSpec, R.ColumnSpec)-filenameCell os info width = (ts, cell) where+filenameCell :: PC.BaseColors -> Box -> Int -> (C.TextSpec, R.ColumnSpec)+filenameCell bc info width = (ts, cell) where   w = C.Width width   vn = M.visibleNum . L.boxMeta $ info   cell = R.ColumnSpec R.LeftJustify w ts cs@@ -354,7 +359,7 @@   cs = case Q.filename . L.boxPostFam $ info of     Nothing -> []     Just fn -> [toBit . L.unFilename $ fn]-  ts = PC.colors vn (O.baseColors os)+  ts = PC.colors vn bc   
Penny/Cabin/Posts/Chunk.hs view
@@ -1,33 +1,90 @@-module Penny.Cabin.Posts.Chunk (makeChunk) where+module Penny.Cabin.Posts.Chunk (ChunkOpts(..), makeChunk) where  import qualified Data.Foldable as Fdbl import Data.List (transpose) import Data.Maybe (isNothing, catMaybes)+import qualified Penny.Cabin.Posts.Fields as F import qualified Penny.Cabin.Posts.Growers as G import qualified Penny.Cabin.Posts.Allocated as A+import qualified Penny.Cabin.Posts.Allocate as Alc import qualified Penny.Cabin.Posts.BottomRows as B-import qualified Penny.Cabin.Posts.Options as Options+import qualified Penny.Cabin.Posts.Spacers as S import qualified Penny.Cabin.Row as R import qualified Penny.Cabin.Chunk as C import qualified Penny.Cabin.Colors as PC+import Penny.Cabin.Posts.Meta (Box) import qualified Penny.Lincoln as L-import qualified Penny.Cabin.Posts.Meta as M+import qualified Data.Text as X+import qualified Penny.Cabin.Posts.Types as Ty -type Box = L.Box M.PostMeta +data ChunkOpts = ChunkOpts {+  baseColors :: PC.BaseColors+  , drCrColors :: PC.DrCrColors+  , dateFormat :: Box -> X.Text+  , qtyFormat :: Box -> X.Text+  , balanceFormat :: L.Commodity -> L.BottomLine -> X.Text+  , fields :: F.Fields Bool+  , subAccountLength :: A.SubAccountLength+  , payeeAllocation :: Alc.Allocation+  , accountAllocation :: Alc.Allocation+  , spacers :: S.Spacers Int+  , reportWidth :: Ty.ReportWidth+  } -makeChunk :: Options.T -> [Box] -> [C.Chunk]-makeChunk os is = let-  fmapSnd flds = fmap (fmap snd) flds-  fmapFst flds = fmap (fmap fst) flds-  gFldW = fmapSnd gFlds-  aFldW = fmapSnd aFlds-  gFlds = G.growCells os is-  aFlds = A.payeeAndAcct gFldW os is-  bFlds = B.bottomRows gFldW aFldW os is-  topCells = B.topRowCells (fmapFst gFlds) (fmapFst aFlds)-  withSpacers = B.mergeWithSpacers topCells (Options.spacers os)-  topRows = makeTopRows (Options.baseColors os) withSpacers-  bottomRows = makeBottomRows bFlds+growOpts :: ChunkOpts -> G.GrowOpts+growOpts c = G.GrowOpts {+  G.baseColors = baseColors c+  , G.drCrColors = drCrColors c+  , G.dateFormat = dateFormat c+  , G.qtyFormat = qtyFormat c+  , G.balanceFormat = balanceFormat c+  , G.fields = fields c+  }++allocatedOpts :: ChunkOpts -> G.Fields (Maybe Int) -> A.AllocatedOpts+allocatedOpts c g = A.AllocatedOpts {+  A.fields = let f = fields c+             in A.Fields { A.payee = F.payee f+                         , A.account = F.account f }+  , A.subAccountLength = subAccountLength c+  , A.baseColors = baseColors c+  , A.payeeAllocation = payeeAllocation c+  , A.accountAllocation = accountAllocation c+  , A.spacers = spacers c+  , A.growerWidths = g+  , A.reportWidth = reportWidth c+  }++bottomOpts ::+  ChunkOpts+  -> G.Fields (Maybe Int)+  -> A.Fields (Maybe Int)+  -> B.BottomOpts+bottomOpts c g a = B.BottomOpts {+  B.growingWidths = g+  , B.allocatedWidths = a+  , B.fields = fields c+  , B.baseColors = baseColors c+  , B.reportWidth = reportWidth c+  , B.spacers = spacers c+  }++makeChunk ::+  ChunkOpts+  -> [Box]+  -> [C.Chunk]+makeChunk c bs =+  let fmapSnd = fmap (fmap snd)+      fmapFst = fmap (fmap fst)+      gFldW = fmap (fmap snd) gFlds+      aFldW = fmapSnd aFlds+      gFlds = G.growCells (growOpts c) bs+      aFlds = A.payeeAndAcct (allocatedOpts c gFldW) bs+      bFlds = B.bottomRows (bottomOpts c gFldW aFldW) bs+      topCells = B.topRowCells (fmapFst gFlds) (fmap (fmap fst) aFlds)+      withSpacers = B.mergeWithSpacers topCells (spacers c)+      topRows = makeTopRows (baseColors c) withSpacers+      bottomRows = makeBottomRows bFlds   in makeAllRows topRows bottomRows  
Penny/Cabin/Posts/Fields.hs view
@@ -4,7 +4,7 @@ import Control.Applicative(Applicative(pure, (<*>))) import qualified Data.Foldable as F -data T a = T {+data Fields a = Fields {   globalTransaction :: a   , revGlobalTransaction :: a   , globalPosting :: a@@ -37,8 +37,8 @@   , filename :: a }   deriving (Show, Eq) -instance Functor T where-  fmap f fa = T {+instance Functor Fields where+  fmap f fa = Fields {     globalTransaction = f (globalTransaction fa)     , revGlobalTransaction = f (revGlobalTransaction fa)     , globalPosting = f (globalPosting fa)@@ -69,8 +69,8 @@     , memo = f (memo fa)     , filename = f (filename fa) } -instance Applicative T where-  pure a = T {+instance Applicative Fields where+  pure a = Fields {     globalTransaction = a     , revGlobalTransaction = a     , globalPosting = a@@ -101,7 +101,7 @@     , memo = a     , filename = a } -  ff <*> fa = T {+  ff <*> fa = Fields {     globalTransaction = globalTransaction ff (globalTransaction fa)     , revGlobalTransaction = revGlobalTransaction ff                              (revGlobalTransaction fa)@@ -133,7 +133,7 @@     , memo = memo ff (memo fa)     , filename = filename ff (filename fa) } -instance F.Foldable T where+instance F.Foldable Fields where   foldr f z t =     f (globalTransaction t)     (f (revGlobalTransaction t)
Penny/Cabin/Posts/Growers.hs view
@@ -2,6 +2,7 @@ -- widest cell in the column. No information is ever truncated from -- these cells (what use is a truncated dollar amount?) module Penny.Cabin.Posts.Growers (+  GrowOpts(..),   growCells, Fields(..), grownWidth,   eFields, EFields(..), pairWithSpacer) where @@ -13,20 +14,26 @@ import Data.Text (Text, pack, empty) import qualified Data.Text as X import qualified Penny.Cabin.Chunk as C-import qualified Penny.Cabin.Colors as PC-import qualified Penny.Cabin.Posts.Options as O-import qualified Penny.Cabin.Posts.Options as Options+import qualified Penny.Cabin.Colors as CC import qualified Penny.Cabin.Posts.Fields as F import qualified Penny.Cabin.Posts.Meta as M+import Penny.Cabin.Posts.Meta (Box) import qualified Penny.Cabin.Posts.Spacers as S-import qualified Penny.Cabin.Posts.Spacers as Spacers import qualified Penny.Cabin.Row as R import qualified Penny.Liberty as Ly import qualified Penny.Lincoln as L import qualified Penny.Lincoln.Queries as Q  -type Box = L.Box M.PostMeta +-- | All the options needed to grow the cells.+data GrowOpts = GrowOpts {+  baseColors :: CC.BaseColors+  , drCrColors :: CC.DrCrColors+  , dateFormat :: Box -> X.Text+  , qtyFormat :: Box -> X.Text+  , balanceFormat :: L.Commodity -> L.BottomLine -> X.Text+  , fields :: F.Fields Bool+  }  -- | Grows the cells that will be GrowToFit cells in the report. First -- this function fills in all visible cells with text, but leaves the@@ -39,19 +46,19 @@ -- the report but that ended up having no width are changed to -- Nothing. growCells ::-  Options.T+  GrowOpts   -> [Box]   -> Fields (Maybe ([R.ColumnSpec], Int)) growCells o infos = toPair <$> wanted <*> growers where   toPair b gwr-    | b = let-      cs = map (gwr o) infos-      w = Fdbl.foldl' f 0 cs where-        f acc c = max acc (widestLine c)-      cs' = map (sizer (R.Width w)) cs+    | b =+      let cs = map (gwr o) infos+          w = Fdbl.foldl' f 0 cs where+            f acc c = max acc (widestLine c)+          cs' = map (sizer (R.Width w)) cs       in if w > 0 then Just (cs', w) else Nothing     | otherwise = Nothing-  wanted = growingFields o+  wanted = growingFields . fields $ o  widestLine :: PreSpec -> Int widestLine (PreSpec _ _ bs) =@@ -70,49 +77,74 @@  -- | Makes a left justified cell that is only one line long. The width -- is unset.-oneLine :: Text -> Options.T -> Box -> PreSpec-oneLine t os b =-  let bc = Options.baseColors os-      ts = PC.colors (M.visibleNum . L.boxMeta $ b) bc+oneLine :: Text -> CC.BaseColors -> Box -> PreSpec+oneLine t bc b =+  let ts = CC.colors (M.visibleNum . L.boxMeta $ b) bc       j = R.LeftJustify       bit = C.chunk ts t   in PreSpec j ts [bit] -growers :: Fields (Options.T -> Box -> PreSpec)+-- | Converts a function that accepts a BaseColors to one that accepts+-- a GrowOpts.+bcToGrowOpts ::+  (CC.BaseColors -> Box -> PreSpec)+  -> GrowOpts -> Box -> PreSpec+bcToGrowOpts f g = f (baseColors g)++-- | Converts a function that accepts a DrCrColors to one that accepts+-- a GrowOpts.+dcToGrowOpts ::+  (CC.DrCrColors -> Box -> PreSpec)+  -> GrowOpts -> Box -> PreSpec+dcToGrowOpts f g = f (drCrColors g)+++-- | Gets a Fields with each field filled with the function that fills+-- the cells for that field.+growers :: Fields (GrowOpts -> Box -> PreSpec) growers = Fields {-  globalTransaction      = getGlobalTransaction-  , revGlobalTransaction = getRevGlobalTransaction-  , globalPosting        = getGlobalPosting-  , revGlobalPosting     = getRevGlobalPosting-  , fileTransaction      = getFileTransaction-  , revFileTransaction   = getRevFileTransaction-  , filePosting          = getFilePosting-  , revFilePosting       = getRevFilePosting-  , filtered             = getFiltered-  , revFiltered          = getRevFiltered-  , sorted               = getSorted-  , revSorted            = getRevSorted-  , visible              = getVisible-  , revVisible           = getRevVisible-  , lineNum              = getLineNum-  , date                 = getDate-  , flag                 = getFlag-  , number               = getNumber-  , postingDrCr          = getPostingDrCr-  , postingCmdty         = getPostingCmdty-  , postingQty           = getPostingQty-  , totalDrCr            = getTotalDrCr-  , totalCmdty           = getTotalCmdty-  , totalQty             = getTotalQty }+  globalTransaction      = bcToGrowOpts getGlobalTransaction+  , revGlobalTransaction = bcToGrowOpts getRevGlobalTransaction+  , globalPosting        = bcToGrowOpts getGlobalPosting+  , revGlobalPosting     = bcToGrowOpts getRevGlobalPosting+  , fileTransaction      = bcToGrowOpts getFileTransaction+  , revFileTransaction   = bcToGrowOpts getRevFileTransaction+  , filePosting          = bcToGrowOpts getFilePosting+  , revFilePosting       = bcToGrowOpts getRevFilePosting+  , filtered             = bcToGrowOpts getFiltered+  , revFiltered          = bcToGrowOpts getRevFiltered+  , sorted               = bcToGrowOpts getSorted+  , revSorted            = bcToGrowOpts getRevSorted+  , visible              = bcToGrowOpts getVisible+  , revVisible           = bcToGrowOpts getRevVisible+  , lineNum              = bcToGrowOpts getLineNum+  , date                 = \o -> getDate (baseColors o) (dateFormat o)+  , flag                 = bcToGrowOpts getFlag+  , number               = bcToGrowOpts getNumber+  , postingDrCr          = dcToGrowOpts getPostingDrCr+  , postingCmdty         = dcToGrowOpts getPostingCmdty+  , postingQty           = let fn o =+                                 let fmt = qtyFormat o+                                     dc = drCrColors o+                                 in getPostingQty fmt dc+                           in fn+  , totalDrCr            = dcToGrowOpts getTotalDrCr+  , totalCmdty           = dcToGrowOpts getTotalCmdty+  , totalQty             = let fn o =+                                 let fmt = balanceFormat o+                                     dc = drCrColors o+                                 in getTotalQty fmt dc+                           in fn } + -- | Make a left justified cell one line long that shows a serial. serialCellMaybe ::   (L.PostFam -> Maybe Int)   -- ^ When applied to a Box, this function returns Just Int if the   -- box has a serial, or Nothing if not.   -  -> Options.T -> Box -> PreSpec-serialCellMaybe f os b = oneLine t os b+  -> CC.BaseColors -> Box -> PreSpec+serialCellMaybe f bc b = oneLine t bc b   where     t = case f (L.boxPostFam b) of       Nothing -> X.empty@@ -120,91 +152,90 @@  serialCell ::   (M.PostMeta -> Int)-  -> Options.T -> Box -> PreSpec-serialCell f os b = oneLine t os b+  -> CC.BaseColors -> Box -> PreSpec+serialCell f bc b = oneLine t bc b   where     t = pack . show . f . L.boxMeta $ b -getGlobalTransaction :: Options.T -> Box -> PreSpec+getGlobalTransaction :: CC.BaseColors -> Box -> PreSpec getGlobalTransaction =   serialCellMaybe (fmap (L.forward . L.unGlobalTransaction)                    . Q.globalTransaction) -getRevGlobalTransaction :: Options.T -> Box -> PreSpec+getRevGlobalTransaction :: CC.BaseColors -> Box -> PreSpec getRevGlobalTransaction =   serialCellMaybe (fmap (L.backward . L.unGlobalTransaction)                    . Q.globalTransaction) -getGlobalPosting :: Options.T -> Box -> PreSpec+getGlobalPosting :: CC.BaseColors -> Box -> PreSpec getGlobalPosting =   serialCellMaybe (fmap (L.forward . L.unGlobalPosting)                    . Q.globalPosting) -getRevGlobalPosting :: Options.T -> Box -> PreSpec+getRevGlobalPosting :: CC.BaseColors -> Box -> PreSpec getRevGlobalPosting =   serialCellMaybe (fmap (L.backward . L.unGlobalPosting)                    . Q.globalPosting) -getFileTransaction :: Options.T -> Box -> PreSpec+getFileTransaction :: CC.BaseColors -> Box -> PreSpec getFileTransaction =   serialCellMaybe (fmap (L.forward . L.unFileTransaction)                    . Q.fileTransaction) -getRevFileTransaction :: Options.T -> Box -> PreSpec+getRevFileTransaction :: CC.BaseColors -> Box -> PreSpec getRevFileTransaction =   serialCellMaybe (fmap (L.backward . L.unFileTransaction)                    . Q.fileTransaction) -getFilePosting :: Options.T -> Box -> PreSpec+getFilePosting :: CC.BaseColors -> Box -> PreSpec getFilePosting =   serialCellMaybe (fmap (L.forward . L.unFilePosting)                    . Q.filePosting) -getRevFilePosting :: Options.T -> Box -> PreSpec+getRevFilePosting :: CC.BaseColors -> Box -> PreSpec getRevFilePosting =   serialCellMaybe (fmap (L.backward . L.unFilePosting)                    . Q.filePosting) -getSorted :: Options.T -> Box -> PreSpec+getSorted :: CC.BaseColors -> Box -> PreSpec getSorted =   serialCell (L.forward . Ly.unSortedNum . M.sortedNum) -getRevSorted :: Options.T -> Box -> PreSpec+getRevSorted :: CC.BaseColors -> Box -> PreSpec getRevSorted =   serialCell (L.backward . Ly.unSortedNum . M.sortedNum) -getFiltered :: Options.T -> Box -> PreSpec+getFiltered :: CC.BaseColors -> Box -> PreSpec getFiltered =   serialCell (L.forward . Ly.unFilteredNum . M.filteredNum) -getRevFiltered :: Options.T -> Box -> PreSpec+getRevFiltered :: CC.BaseColors -> Box -> PreSpec getRevFiltered =   serialCell (L.backward . Ly.unFilteredNum . M.filteredNum) -getVisible :: Options.T -> Box -> PreSpec+getVisible :: CC.BaseColors -> Box -> PreSpec getVisible =   serialCell (L.forward . M.unVisibleNum . M.visibleNum) -getRevVisible :: Options.T -> Box -> PreSpec+getRevVisible :: CC.BaseColors -> Box -> PreSpec getRevVisible =   serialCell (L.backward . M.unVisibleNum . M.visibleNum)  -getLineNum :: Options.T -> Box -> PreSpec-getLineNum os b = oneLine t os b where+getLineNum :: CC.BaseColors -> Box -> PreSpec+getLineNum bc b = oneLine t bc b where   lineTxt = pack . show . L.unPostingLine   t = maybe empty lineTxt (Q.postingLine . L.boxPostFam $ b) -getDate :: Options.T -> Box -> PreSpec-getDate os i = oneLine t os i where-  t = O.dateFormat os i+getDate :: CC.BaseColors -> (Box -> X.Text) -> Box -> PreSpec+getDate bc gd b = oneLine (gd b) bc b -getFlag :: Options.T -> Box -> PreSpec-getFlag os i = oneLine t os i where+getFlag :: CC.BaseColors -> Box -> PreSpec+getFlag bc i = oneLine t bc i where   t = maybe empty L.text (Q.flag . L.boxPostFam $ i) -getNumber :: Options.T -> Box -> PreSpec-getNumber os i = oneLine t os i where+getNumber :: CC.BaseColors -> Box -> PreSpec+getNumber bc i = oneLine t bc i where   t = maybe empty L.text (Q.number . L.boxPostFam $ i)  dcTxt :: L.DrCr -> Text@@ -213,126 +244,131 @@  -- | Gives a one-line cell that is colored according to whether the -- posting is a debit or credit.-coloredPostingCell :: Text -> Options.T -> Box -> PreSpec-coloredPostingCell t os i = PreSpec j ts [bit] where+coloredPostingCell :: Text -> CC.DrCrColors -> Box -> PreSpec+coloredPostingCell t dccol i = PreSpec j ts [bit] where   j = R.LeftJustify   bit = C.chunk ts t   dc = Q.drCr . L.boxPostFam $ i-  ts = PC.colors (M.visibleNum . L.boxMeta $ i)-       . PC.drCrToBaseColors dc-       . O.drCrColors-       $ os+  ts = CC.colors (M.visibleNum . L.boxMeta $ i)+       . CC.drCrToBaseColors dc+       $ dccol -getPostingDrCr :: Options.T -> Box -> PreSpec-getPostingDrCr os i = coloredPostingCell t os i where++getPostingDrCr :: CC.DrCrColors -> Box -> PreSpec+getPostingDrCr dc i = coloredPostingCell t dc i where   t = dcTxt . Q.drCr . L.boxPostFam $ i -getPostingCmdty :: Options.T -> Box -> PreSpec-getPostingCmdty os i = coloredPostingCell t os i where+getPostingCmdty :: CC.DrCrColors -> Box -> PreSpec+getPostingCmdty dc i = coloredPostingCell t dc i where   t = L.text . L.Delimited (X.singleton ':')        . L.textList . Q.commodity . L.boxPostFam $ i -getPostingQty :: Options.T -> Box -> PreSpec-getPostingQty os i = coloredPostingCell t os i where-  t = O.qtyFormat os i+getPostingQty :: (Box -> X.Text) -> CC.DrCrColors -> Box -> PreSpec+getPostingQty qf dc i = coloredPostingCell (qf i) dc i -getTotalDrCr :: Options.T -> Box -> PreSpec-getTotalDrCr os i = let-  vn = M.visibleNum . L.boxMeta $ i-  ts = PC.colors vn bc-  bc = PC.drCrToBaseColors dc (O.drCrColors os)-  dc = Q.drCr . L.boxPostFam $ i-  bits = case M.balance . L.boxMeta $ i of-    Nothing -> let-      spec = PC.noBalanceColors vn (O.drCrColors os)-      in [C.chunk spec (pack "--")]-    Just bal -> let-      toBit bl = let-        spec = -          PC.colors vn-          . PC.bottomLineToBaseColors (O.drCrColors os)-          $ bl-        txt = case bl of-          L.Zero -> pack "--"-          L.NonZero (L.Column clmDrCr _) -> dcTxt clmDrCr-        in C.chunk spec txt-      in fmap toBit . elems . L.unBalance $ bal-  j = R.LeftJustify+getTotalDrCr :: CC.DrCrColors -> Box -> PreSpec+getTotalDrCr dccol i =+  let vn = M.visibleNum . L.boxMeta $ i+      ts = CC.colors vn bc+      bc = CC.drCrToBaseColors dc dccol+      dc = Q.drCr . L.boxPostFam $ i+      bits = case M.balance . L.boxMeta $ i of+        Nothing ->+          let spec = CC.noBalanceColors vn dccol+          in [C.chunk spec (pack "--")]+        Just bal ->+          let toBit bl =+                let spec = +                      CC.colors vn+                      . CC.bottomLineToBaseColors dccol+                      $ bl+                    txt = case bl of+                      L.Zero -> pack "--"+                      L.NonZero (L.Column clmDrCr _) ->+                        dcTxt clmDrCr+                in C.chunk spec txt+          in fmap toBit . elems . L.unBalance $ bal+      j = R.LeftJustify   in PreSpec j ts bits -getTotalCmdty :: Options.T -> Box -> PreSpec-getTotalCmdty os i = let-  vn = M.visibleNum . L.boxMeta $ i-  j = R.RightJustify-  ts = PC.colors vn bc-  bc = PC.drCrToBaseColors dc (O.drCrColors os)-  dc = Q.drCr . L.boxPostFam $ i-  bits = case M.balance . L.boxMeta $ i of-    Nothing -> let-      spec = PC.noBalanceColors vn (O.drCrColors os)-      in [C.chunk spec (pack "--")]-    Just bal -> let-      toBit (com, nou) = let-        spec =-          PC.colors vn-          . PC.bottomLineToBaseColors (O.drCrColors os)-          $ nou-        txt = L.text-              . L.Delimited (X.singleton ':')-              . L.textList-              $ com-        in C.chunk spec txt-      in fmap toBit . assocs . L.unBalance $ bal+getTotalCmdty :: CC.DrCrColors -> Box -> PreSpec+getTotalCmdty dccol i =+  let vn = M.visibleNum . L.boxMeta $ i+      j = R.RightJustify+      ts = CC.colors vn bc+      bc = CC.drCrToBaseColors dc dccol+      dc = Q.drCr . L.boxPostFam $ i+      bits = case M.balance . L.boxMeta $ i of+        Nothing ->+          let spec = CC.noBalanceColors vn dccol+          in [C.chunk spec (pack "--")]+        Just bal ->+          let toBit (com, nou) =+                let spec =+                      CC.colors vn+                      . CC.bottomLineToBaseColors dccol+                      $ nou+                    txt = L.text+                          . L.Delimited (X.singleton ':')+                          . L.textList+                          $ com+                in C.chunk spec txt+          in fmap toBit . assocs . L.unBalance $ bal   in PreSpec j ts bits -getTotalQty :: Options.T -> Box -> PreSpec-getTotalQty os i = let-  vn = M.visibleNum . L.boxMeta $ i-  j = R.LeftJustify-  ts = PC.colors vn bc-  bc = PC.drCrToBaseColors dc (O.drCrColors os)-  dc = Q.drCr . L.boxPostFam $ i-  bits = case M.balance . L.boxMeta $ i of-    Nothing -> let-      spec = PC.noBalanceColors vn (O.drCrColors os)-      in [C.chunk spec (pack "--")]-    Just bal -> fmap toChunk . assocs . L.unBalance $ bal where-      toChunk (com, nou) = let-        spec = -          PC.colors vn-          . PC.bottomLineToBaseColors (O.drCrColors os)-          $ nou-        txt = O.balanceFormat os com nou-        in C.chunk spec txt+getTotalQty ::+  (L.Commodity -> L.BottomLine -> X.Text)+  -> CC.DrCrColors+  -> Box+  -> PreSpec+getTotalQty balFmt dccol i =+  let vn = M.visibleNum . L.boxMeta $ i+      j = R.LeftJustify+      ts = CC.colors vn bc+      bc = CC.drCrToBaseColors dc dccol+      dc = Q.drCr . L.boxPostFam $ i+      bits = case M.balance . L.boxMeta $ i of+        Nothing ->+          let spec = CC.noBalanceColors vn dccol+          in [C.chunk spec (pack "--")]+        Just bal ->+          fmap toChunk . assocs . L.unBalance $ bal+            where+              toChunk (com, nou) =+                let spec = +                      CC.colors vn+                      . CC.bottomLineToBaseColors dccol+                      $ nou+                    txt = balFmt com nou+                in C.chunk spec txt   in PreSpec j ts bits -growingFields :: Options.T -> Fields Bool-growingFields o = let-  f = O.fields o in Fields {-    globalTransaction      = F.globalTransaction  f-    , revGlobalTransaction = F.revGlobalTransaction  f-    , globalPosting        = F.globalPosting      f-    , revGlobalPosting     = F.revGlobalPosting   f-    , fileTransaction      = F.fileTransaction    f-    , revFileTransaction   = F.revFileTransaction f-    , filePosting          = F.filePosting        f-    , revFilePosting       = F.revFilePosting     f-    , filtered             = F.filtered           f-    , revFiltered          = F.revFiltered        f-    , sorted               = F.sorted             f-    , revSorted            = F.revSorted          f-    , visible              = F.visible            f-    , revVisible           = F.revVisible         f-    , lineNum              = F.lineNum            f-    , date                 = F.date               f-    , flag                 = F.flag               f-    , number               = F.number             f-    , postingDrCr          = F.postingDrCr        f-    , postingCmdty         = F.postingCmdty       f-    , postingQty           = F.postingQty         f-    , totalDrCr            = F.totalDrCr          f-    , totalCmdty           = F.totalCmdty         f-    , totalQty             = F.totalQty           f }+growingFields :: F.Fields Bool -> Fields Bool+growingFields f = Fields {+  globalTransaction      = F.globalTransaction    f+  , revGlobalTransaction = F.revGlobalTransaction f+  , globalPosting        = F.globalPosting        f+  , revGlobalPosting     = F.revGlobalPosting     f+  , fileTransaction      = F.fileTransaction      f+  , revFileTransaction   = F.revFileTransaction   f+  , filePosting          = F.filePosting          f+  , revFilePosting       = F.revFilePosting       f+  , filtered             = F.filtered             f+  , revFiltered          = F.revFiltered          f+  , sorted               = F.sorted               f+  , revSorted            = F.revSorted            f+  , visible              = F.visible              f+  , revVisible           = F.revVisible           f+  , lineNum              = F.lineNum              f+  , date                 = F.date                 f+  , flag                 = F.flag                 f+  , number               = F.number               f+  , postingDrCr          = F.postingDrCr          f+  , postingCmdty         = F.postingCmdty         f+  , postingQty           = F.postingQty           f+  , totalDrCr            = F.totalDrCr            f+  , totalCmdty           = F.totalCmdty           f+  , totalQty             = F.totalQty             f }  -- | All growing fields, as an ADT. data EFields =@@ -529,7 +565,7 @@ -- | Pairs data from a Fields with its matching spacer field. The -- spacer field is returned in a Maybe because the TotalQty field does -- not have a spacer.-pairWithSpacer :: Fields a -> Spacers.T b -> Fields (a, Maybe b)+pairWithSpacer :: Fields a -> S.Spacers b -> Fields (a, Maybe b) pairWithSpacer f s = Fields {   globalTransaction      = (globalTransaction    f, Just (S.globalTransaction    s))   , revGlobalTransaction = (revGlobalTransaction f, Just (S.revGlobalTransaction s))@@ -588,7 +624,7 @@ -- spacer cells. grownWidth ::   Fields (Maybe Int)-  -> Spacers.T Int+  -> S.Spacers Int   -> Int grownWidth fs ss =   Semi.getSum
Penny/Cabin/Posts/Meta.hs view
@@ -1,18 +1,20 @@ module Penny.Cabin.Posts.Meta (   M.VisibleNum(M.unVisibleNum)   , PostMeta(filteredNum, sortedNum, visibleNum, balance)-  , filterBoxes-  , addMetadata+  , Box+  , toBoxList   ) where  import Data.List (mapAccumL) import qualified Penny.Lincoln as L import qualified Penny.Lincoln.Queries as Q import qualified Penny.Liberty as Ly-import qualified Penny.Liberty.Expressions as Exp import qualified Penny.Cabin.Meta as M import qualified Penny.Cabin.Options as CO +-- | The Box type that is used throughout the Posts modules.+type Box = L.Box PostMeta+ data PostMeta =   PostMeta { filteredNum :: Ly.FilteredNum             , sortedNum :: Ly.SortedNum@@ -21,31 +23,38 @@   deriving Show  --- | Takes a list of Box with LibertyMeta, and a list of tokens from--- the command line, and a list of post filters. Filters the list of--- Box and processes the post filter. Fails if the expression fails to--- produce a result.-filterBoxes ::-  [Exp.Token (L.Box Ly.LibertyMeta -> Bool)]-  -> [Ly.PostFilterFn]-  -> [L.Box Ly.LibertyMeta]-  -> Maybe [L.Box Ly.LibertyMeta]-filterBoxes tks pfs bs = fmap fltr (Ly.parsePredicate tks)-  where-    fltr p =-      Ly.processPostFilters pfs . filter p $ bs------ | Applied to a list of Box that have already been filtered, returns--- a list of Box with posting metadata. addMetadata ::-  CO.ShowZeroBalances-  -> [L.Box Ly.LibertyMeta]-  -> [L.Box PostMeta]-addMetadata szb = M.visibleNums f . addBalances szb where+  [(L.Box (Ly.LibertyMeta, Maybe L.Balance))]+  -> [Box]+addMetadata = M.visibleNums f where   f vn (lm, mb) =     PostMeta (Ly.filteredNum lm) (Ly.sortedNum lm) vn mb++-- | Adds appropriate metadata, including the running balance, to a+-- list of Box. Because all posts are incorporated into the running+-- balance, first calculates the running balance for all posts. Then,+-- removes posts we're not interested in by applying the predicate and+-- the post-filter. Finally, adds on the metadata, which will include+-- the VisibleNum.+toBoxList ::+  CO.ShowZeroBalances+  -> (L.Box Ly.LibertyMeta -> Bool)+  -- ^ Removes posts from the report if applying this function to the+  -- post returns False. Posts removed still affect the running+  -- balance.+  +  -> [Ly.PostFilterFn]+  -- ^ Applies these post-filters to the list of posts that results+  -- from applying the predicate above. Might remove more+  -- postings. Postings removed still affect the running balance.++  -> [L.Box Ly.LibertyMeta]+  -> [Box]+toBoxList szb pdct pff =+  addMetadata+  . Ly.processPostFilters pff+  . filter (pdct . fmap fst)+  . addBalances szb  addBalances ::   CO.ShowZeroBalances
− Penny/Cabin/Posts/Options.hs
@@ -1,247 +0,0 @@--- | Options for the Posts report.-module Penny.Cabin.Posts.Options where---import Control.Monad.Exception.Synchronous (Exceptional)-import Data.Text (Text)-import qualified Data.Text as X-import Data.Time (formatTime)-import System.Locale (defaultTimeLocale)-import qualified Data.Time as Time-import qualified Text.Matchers.Text as M--import qualified Penny.Liberty as Ly-import qualified Penny.Liberty.Expressions as Ex-import qualified Penny.Lincoln as L-import qualified Penny.Lincoln.Balance as Bal-import qualified Penny.Lincoln.Bits as Bits-import qualified Penny.Lincoln.Queries as Q-import qualified Penny.Cabin.Posts.Allocate as A-import qualified Penny.Cabin.Chunk as CC-import qualified Penny.Cabin.Colors as C-import qualified Penny.Cabin.Options as O-import qualified Penny.Cabin.Posts.Fields as Fields-import qualified Penny.Cabin.Posts.Fields as F-import qualified Penny.Cabin.Posts.Meta as Meta-import qualified Penny.Cabin.Posts.Spacers as S-import qualified Penny.Cabin.Posts.Spacers as Spacers-import qualified Penny.Cabin.Colors.DarkBackground as Dark-import Penny.Copper.DateTime (DefaultTimeZone)-import Penny.Copper.Qty (RadGroup)-import qualified Penny.Shield as S---type Box = L.Box Meta.PostMeta--data T =-  T { drCrColors :: C.DrCrColors-      -- ^ Colors to use when displaying debits, credits, and-      -- when displaying balance totals--    , baseColors :: C.BaseColors -      -- ^ Colors to use when displaying everything else--    , dateFormat :: Box -> X.Text-      -- ^ How to display dates. This function is applied to the-      -- a PostingInfo so it has lots of information, but it-      -- should return a date for use in the Date field.-      -    , qtyFormat :: Box -> X.Text-      -- ^ How to display the quantity of the posting. This-      -- function is applied to a PostingInfo so it has lots of-      -- information, but it should return a formatted string of-      -- the quantity. Allows you to format digit grouping,-      -- radix points, perform rounding, etc.-      -    , balanceFormat :: Bits.Commodity -> Bal.BottomLine -> X.Text-      -- ^ How to display balance totals. Similar to-      -- balanceFormat.-      -    , payeeAllocation :: A.Allocation-      -- ^ This and accountAllocation determine how much space-      -- payees and accounts receive. They divide up the-      -- remaining space after everything else is displayed. For-      -- instance if payeeAllocation is 60 and accountAllocation-      -- is 40, the payee takes about 60 percent of the-      -- remaining space and the account takes about 40 percent.-      -    , accountAllocation :: A.Allocation -      -- ^ See payeeAllocation above--    , width :: ReportWidth-      -- ^ Gives the default report width. This can be-      -- overridden on the command line. You can use the-      -- information from the Runtime to make this as wide as-      -- the as the current terminal.--    , subAccountLength :: Int-      -- ^ When shortening the names of sub accounts to make-      -- them fit, they will be this long.--    , colorPref :: CC.Colors-      -- ^ How many colors you want to see, or do it-      -- automatically.--    , timeZone :: DefaultTimeZone-      -- ^ When dates and times are given on the command line-      -- and they have no time zone, they are assumed to be in-      -- this time zone. This has no bearing on how dates are-      -- formatted in the output; for that, see dateFormat-      -- above.--    , radGroup :: RadGroup-      -- ^ The characters used for the radix point for numbers-      -- given on the command line (e.g. a full stop, or a-      -- comma) and for the digit group separator for-      -- numbers parsed from the command line (e.g. a full stop,-      -- or a comma). Affects how inputs are parsed. Has no bearing-      -- on how output is formatted; for that, see qtyFormat and-      -- balanceFormat above.-      -    , sensitive :: M.CaseSensitive-      -- ^ Whether pattern matches are case sensitive by default.-      -    , factory :: M.CaseSensitive-                 -> Text -> Exceptional Text (Text -> Bool)-      -- ^ Default factory for pattern matching-      -    , tokens :: [Ex.Token (L.Box Ly.LibertyMeta -> Bool)]-      -- ^ Default list of tokens used to filter postings.-      -    , postFilter :: [Ly.PostFilterFn]-      -- ^ The entire posting list is transformed by this-      -- function after it is filtered according to the tokens.-      -    , fields :: Fields.T Bool-      -- ^ Default fields to show in the report.-      -    , spacers :: Spacers.T Int-      -- ^ Default width for spacer fields. If any of these Ints are-      -- less than or equal to zero, there will be no spacer. There is-      -- never a spacer for fields that do not appear in the report.-      -    , showZeroBalances :: O.ShowZeroBalances-    }--newtype ReportWidth = ReportWidth { unReportWidth :: Int }-                      deriving (Eq, Show, Ord)--ymd :: Box -> X.Text-ymd p = X.pack (formatTime defaultTimeLocale fmt d) where-  d = Time.localDay-      . Bits.localTime-      . Q.dateTime-      . L.boxPostFam-      $ p-  fmt = "%Y-%m-%d"--qtyAsIs :: Box -> X.Text-qtyAsIs p = X.pack . show . Bits.unQty . Q.qty . L.boxPostFam $ p--balanceAsIs :: Bits.Commodity -> Bal.BottomLine -> X.Text-balanceAsIs _ n = case n of-  Bal.Zero -> X.pack "--"-  Bal.NonZero c -> X.pack . show . Bits.unQty . Bal.qty $ c--defaultWidth :: ReportWidth-defaultWidth = ReportWidth 80--columnsVarToWidth :: Maybe String -> ReportWidth-columnsVarToWidth ms = case ms of-  Nothing -> defaultWidth-  Just str -> case reads str of-    [] -> defaultWidth-    (i, []):[] -> if i > 0 then ReportWidth i else defaultWidth-    _ -> defaultWidth--defaultOptions ::-  DefaultTimeZone-  -> RadGroup-  -> S.Runtime-  -> T-defaultOptions dtz rg rt =-  T { drCrColors = Dark.drCrColors-    , baseColors = Dark.baseColors-    , dateFormat = ymd-    , qtyFormat = qtyAsIs-    , balanceFormat = balanceAsIs-    , payeeAllocation = A.allocation 40-    , accountAllocation = A.allocation 60-    , width = widthFromRuntime rt-    , subAccountLength = 2-    , colorPref = O.autoColors O.PrefAuto rt-    , timeZone = dtz-    , radGroup = rg-    , sensitive = M.Insensitive-    , factory = \s t -> (return (M.within s t))-    , tokens = []-    , postFilter = []-    , fields = defaultFields-    , spacers = defaultSpacerWidth-    , showZeroBalances = O.ShowZeroBalances False }--widthFromRuntime :: S.Runtime -> ReportWidth-widthFromRuntime rt = case S.screenWidth rt of-  Nothing -> defaultWidth-  Just w -> ReportWidth . S.unScreenWidth $ w--defaultFields :: Fields.T Bool-defaultFields =-  Fields.T { F.globalTransaction    = False-           , F.revGlobalTransaction = False-           , F.globalPosting        = False-           , F.revGlobalPosting     = False-           , F.fileTransaction      = False-           , F.revFileTransaction   = False-           , F.filePosting          = False-           , F.revFilePosting       = False-           , F.filtered             = False-           , F.revFiltered          = False-           , F.sorted               = False-           , F.revSorted            = False-           , F.visible              = False-           , F.revVisible           = False-           , F.lineNum              = False-           , F.date                 = True-           , F.flag                 = False-           , F.number               = False-           , F.payee                = True-           , F.account              = True-           , F.postingDrCr          = True-           , F.postingCmdty         = True-           , F.postingQty           = True-           , F.totalDrCr            = True-           , F.totalCmdty           = True-           , F.totalQty             = True-           , F.tags                 = False-           , F.memo                 = False-           , F.filename             = False }--defaultSpacerWidth :: Spacers.T Int-defaultSpacerWidth =-  Spacers.T { S.globalTransaction    = 1-            , S.revGlobalTransaction = 1-            , S.globalPosting        = 1-            , S.revGlobalPosting     = 1-            , S.fileTransaction      = 1-            , S.revFileTransaction   = 1-            , S.filePosting          = 1-            , S.revFilePosting       = 1-            , S.filtered             = 1-            , S.revFiltered          = 1-            , S.sorted               = 1-            , S.revSorted            = 1-            , S.visible              = 1-            , S.revVisible           = 1-            , S.lineNum              = 1-            , S.date                 = 1-            , S.flag                 = 1-            , S.number               = 1-            , S.payee                = 4-            , S.account              = 1-            , S.postingDrCr          = 1-            , S.postingCmdty         = 1-            , S.postingQty           = 1-            , S.totalDrCr            = 1-            , S.totalCmdty           = 1 }-
Penny/Cabin/Posts/Parser.hs view
@@ -1,24 +1,28 @@-module Penny.Cabin.Posts.Parser (parseOptions) where+module Penny.Cabin.Posts.Parser (State(..), parseOptions,+                                 Error(..)) where -import Control.Applicative ((<|>), (<$>), pure, many, (<*>))+import Control.Applicative ((<|>), (<$>), pure, many, (<*>),+                            Applicative) import Control.Monad ((>=>)) import qualified Control.Monad.Exception.Synchronous as Ex import Data.Char (toLower)-import qualified Data.Foldable as F+import qualified Data.Foldable as Fdbl import qualified System.Console.MultiArg.Combinator as C import System.Console.MultiArg.Prim (Parser)  import qualified Penny.Cabin.Chunk as CC import qualified Penny.Cabin.Colors as PC-import qualified Penny.Cabin.Posts.Fields as Fl-import qualified Penny.Cabin.Posts.Options as Op+import qualified Penny.Cabin.Posts.Fields as F+import qualified Penny.Cabin.Posts.Types as Ty import qualified Penny.Cabin.Colors.DarkBackground as DB import qualified Penny.Cabin.Colors.LightBackground as LB import qualified Penny.Cabin.Options as CO+import qualified Penny.Copper as Cop import qualified Penny.Liberty as Ly import qualified Penny.Liberty.Expressions as Exp import qualified Penny.Lincoln as L import qualified Penny.Shield as S+import qualified Text.Matchers.Text as M  data Error = BadColorName String              | BadBackgroundArg String@@ -30,56 +34,85 @@              | BadComparator String              deriving Show +data State = State {+  sensitive :: M.CaseSensitive+  , factory :: L.Factory+  , tokens :: [Ly.Token (L.Box Ly.LibertyMeta -> Bool)]+  , postFilter :: [Ly.PostFilterFn]+  , fields :: F.Fields Bool+  , colorPref :: CC.Colors+  , drCrColors :: PC.DrCrColors+  , baseColors :: PC.BaseColors+  , width :: Ty.ReportWidth+  , showZeroBalances :: CO.ShowZeroBalances+  }+ -- | Parses the command line from the first word remaining up until, -- but not including, the first non-option argment. parseOptions ::-  Parser (S.Runtime -> Op.T -> Ex.Exceptional Error Op.T)+  Parser (S.Runtime+          -> Cop.DefaultTimeZone+          -> Cop.RadGroup+          -> State+          -> Ex.Exceptional Error State) parseOptions = f <$> many parseOption where   f ls =-    let g rt op =-          let ls' = map (\fn -> fn rt) ls-          in (foldl (>=>) return ls') op+    let g rt dtz rg st =+          let ls' = map (\fn -> fn rt dtz rg) ls+          in (foldl (>=>) return ls') st     in g   parseOption ::-  Parser (S.Runtime -> Op.T -> Ex.Exceptional Error Op.T)+  Parser (S.Runtime+          -> Cop.DefaultTimeZone+          -> Cop.RadGroup+          -> State+          -> Ex.Exceptional Error State) parseOption =   operand-  <|> mkTwoArg boxFilters-  <|> mkTwoArg postFilter-  <|> mkTwoArg matcherSelect-  <|> mkTwoArg caseSelect-  <|> mkTwoArg operator-  <|> color-  <|> mkTwoArg background-  <|> mkTwoArg width-  <|> mkTwoArg showField-  <|> mkTwoArg hideField-  <|> mkTwoArg showAllFields-  <|> mkTwoArg hideAllFields-  <|> mkTwoArg showZeroBalances-  <|> mkTwoArg hideZeroBalances+  <|> wrap boxFilters+  <|> wrap parsePostFilter+  <|> wrap (impurify matcherSelect)+  <|> wrap (impurify caseSelect)+  <|> wrap (impurify operator)+  <|> (do { f <- color; return (\rt _ _ st -> f rt st)})+  <|> wrap background+  <|> wrap parseWidth+  <|> wrap showField+  <|> wrap hideField+  <|> wrap (impurify showAllFields)+  <|> wrap (impurify hideAllFields)+  <|> wrap (impurify parseShowZeroBalances)+  <|> wrap (impurify hideZeroBalances)   where-    mkTwoArg p = do+    wrap p = do       f <- p-      return (\_ o -> f o)+      return (\_ _ _ st -> f st) -operand :: Parser (S.Runtime -> Op.T -> Ex.Exceptional Error Op.T)+impurify ::+  (Functor f, Applicative m)+  => f (a -> b)+  -> f (a -> m b)+impurify = fmap (\g -> pure . g)++operand :: Parser (S.Runtime+                   -> Cop.DefaultTimeZone+                   -> Cop.RadGroup+                   -> State+                   -> Ex.Exceptional Error State) operand = f <$> Ly.parseOperand   where-    f lyFn rt op =-      let dtz = Op.timeZone op-          rg = Op.radGroup op-          dt = S.currentTime rt-          cs = Op.sensitive op-          fty = Op.factory op+    f lyFn rt dtz rg st =+      let dt = S.currentTime rt+          cs = sensitive st+          fty = factory st       in case lyFn dt dtz rg cs fty of         Ex.Exception e -> Ex.throw . LibertyError $ e         Ex.Success (Exp.Operand g) ->           let g' = g . L.boxPostFam-              ts' = Op.tokens op ++ [Exp.TokOperand g']-          in return op { Op.tokens = ts' }+              ts' = tokens st ++ [Exp.TokOperand g']+          in return st { tokens = ts' }  -- | Processes a option for box-level serials. optBoxSerial ::@@ -92,35 +125,35 @@   -> (Ly.LibertyMeta -> Int)   -- ^ Pulls the serial from the PostMeta   -  -> Parser (Op.T -> Ex.Exceptional Error Op.T)+  -> Parser (State -> Ex.Exceptional Error State)  optBoxSerial ls ss f = parseOpt ls ss (C.TwoArg g)   where-    g a1 a2 op = do+    g a1 a2 st = do       cmp <- Ex.fromMaybe (BadComparator a1) (Ly.parseComparer a1)       i <- parseInt a2       let h box =             let ser = f . L.boxMeta $ box             in ser `cmp` i           tok = Exp.TokOperand h-      return op { Op.tokens = Op.tokens op ++ [tok] }+      return st { tokens = tokens st ++ [tok] } -optFilteredNum :: Parser (Op.T -> Ex.Exceptional Error Op.T)+optFilteredNum :: Parser (State -> Ex.Exceptional Error State) optFilteredNum = optBoxSerial ["filtered"] "" f   where     f = L.forward . Ly.unFilteredNum . Ly.filteredNum -optRevFilteredNum :: Parser (Op.T -> Ex.Exceptional Error Op.T)+optRevFilteredNum :: Parser (State -> Ex.Exceptional Error State) optRevFilteredNum = optBoxSerial ["revFiltered"] "" f   where     f = L.backward . Ly.unFilteredNum . Ly.filteredNum -optSortedNum :: Parser (Op.T -> Ex.Exceptional Error Op.T)+optSortedNum :: Parser (State -> Ex.Exceptional Error State) optSortedNum = optBoxSerial ["sorted"] "" f   where     f = L.forward . Ly.unSortedNum . Ly.sortedNum -optRevSortedNum :: Parser (Op.T -> Ex.Exceptional Error Op.T)+optRevSortedNum :: Parser (State -> Ex.Exceptional Error State) optRevSortedNum = optBoxSerial ["revSorted"] "" f   where     f = L.backward . Ly.unSortedNum . Ly.sortedNum@@ -130,7 +163,7 @@   (i, ""):[] -> return i   _ -> Ex.throw . BadNumber $ s -boxFilters :: Parser (Op.T -> Ex.Exceptional Error Op.T)+boxFilters :: Parser (State -> Ex.Exceptional Error State) boxFilters =   optFilteredNum   <|> optRevFilteredNum@@ -138,39 +171,39 @@   <|> optRevSortedNum  -postFilter :: Parser (Op.T -> Ex.Exceptional Error Op.T)-postFilter = f <$> Ly.parsePostFilter+parsePostFilter :: Parser (State -> Ex.Exceptional Error State)+parsePostFilter = f <$> Ly.parsePostFilter   where-    f ex op =+    f ex st =       case ex of         Ex.Exception e -> Ex.throw . LibertyError $ e         Ex.Success pf ->-          return op { Op.postFilter = Op.postFilter op ++ [pf] }+          return st { postFilter = postFilter st ++ [pf] } -matcherSelect :: Parser (Op.T -> Ex.Exceptional Error Op.T)+matcherSelect :: Parser (State -> State) matcherSelect = f <$> Ly.parseMatcherSelect   where-    f mf op = return op { Op.factory = mf }+    f mf st = st { factory = mf } -caseSelect :: Parser (Op.T -> Ex.Exceptional Error Op.T)+caseSelect :: Parser (State -> State) caseSelect = f <$> Ly.parseCaseSelect   where-    f cs op = return op { Op.sensitive = cs }+    f cs st = st { sensitive = cs } -operator :: Parser (Op.T -> Ex.Exceptional Error Op.T)+operator :: Parser (State -> State) operator = f <$> Ly.parseOperator   where-    f oo op = return op { Op.tokens = Op.tokens op ++ [oo] }+    f oo st = st { tokens = tokens st ++ [oo] }  parseOpt :: [String] -> [Char] -> C.ArgSpec a -> Parser a parseOpt ss cs a = C.parseOption [C.OptSpec ss cs a] -color :: Parser (S.Runtime -> Op.T -> Ex.Exceptional Error Op.T)+color :: Parser (S.Runtime -> State -> Ex.Exceptional Error State) color = parseOpt ["color"] "" (C.OneArg f)   where-    f a1 rt op = case pickColorArg rt a1 of+    f a1 rt st = case pickColorArg rt a1 of       Nothing -> Ex.throw . BadColorName $ a1-      Just c -> return (op { Op.colorPref = c })+      Just c -> return (st { colorPref = c })  pickColorArg :: S.Runtime -> String -> Maybe CC.Colors pickColorArg rt t@@ -187,84 +220,83 @@   | otherwise = Nothing  -background :: Parser (Op.T -> Ex.Exceptional Error Op.T)+background :: Parser (State -> Ex.Exceptional Error State) background = parseOpt ["background"] "" (C.OneArg f)   where-    f a1 op = case pickBackgroundArg a1 of+    f a1 st = case pickBackgroundArg a1 of       Nothing -> Ex.throw . BadBackgroundArg $ a1-      Just (dc, bc) -> return (op { Op.drCrColors = dc-                                  , Op.baseColors = bc } )+      Just (dc, bc) -> return (st { drCrColors = dc+                                  , baseColors = bc } )  -width :: Parser (Op.T -> Ex.Exceptional Error Op.T)-width = parseOpt ["width"] "" (C.OneArg f)+parseWidth :: Parser (State -> Ex.Exceptional Error State)+parseWidth = parseOpt ["width"] "" (C.OneArg f)   where-    f a1 op = case reads a1 of-      (i, ""):[] -> return (op { Op.width = Op.ReportWidth i })+    f a1 st = case reads a1 of+      (i, ""):[] -> return (st { width = Ty.ReportWidth i })       _ -> Ex.throw . BadWidthArg $ a1 -showField :: Parser (Op.T -> Ex.Exceptional Error Op.T)+showField :: Parser (State -> Ex.Exceptional Error State) showField = parseOpt ["show"] "" (C.OneArg f)   where-    f a1 op = do+    f a1 st = do       fl <- parseField a1-      let newFl = fieldOn (Op.fields op) fl-      return op { Op.fields = newFl }+      let newFl = fieldOn (fields st) fl+      return st { fields = newFl } -hideField :: Parser (Op.T -> Ex.Exceptional Error Op.T)+hideField :: Parser (State -> Ex.Exceptional Error State) hideField = parseOpt ["hide"] "" (C.OneArg f)   where-    f a1 op = do+    f a1 st = do       fl <- parseField a1-      let newFl = fieldOff (Op.fields op) fl-      return op { Op.fields = newFl }+      let newFl = fieldOff (fields st) fl+      return st { fields = newFl } -showAllFields :: Parser (Op.T -> Ex.Exceptional a Op.T)+showAllFields :: Parser (State -> State) showAllFields = parseOpt ["show-all"] "" (C.NoArg f)   where-    f op = return (op {Op.fields = pure True})+    f st = st {fields = pure True} -hideAllFields :: Parser (Op.T -> Ex.Exceptional a Op.T)+hideAllFields :: Parser (State -> State) hideAllFields = parseOpt ["hide-all"] "" (C.NoArg f)   where-    f op = return (op {Op.fields = pure False})+    f st = st {fields = pure False} -showZeroBalances :: Parser (Op.T -> Ex.Exceptional a Op.T)-showZeroBalances = parseOpt ["show-zero-balances"] "" (C.NoArg f)+parseShowZeroBalances :: Parser (State -> State)+parseShowZeroBalances = parseOpt opt "" (C.NoArg f)   where-    f op =-      return (op {Op.showZeroBalances = CO.ShowZeroBalances True })+    opt = ["show-zero-balances"]+    f st = st {showZeroBalances = CO.ShowZeroBalances True } -hideZeroBalances :: Parser (Op.T -> Ex.Exceptional a Op.T)+hideZeroBalances :: Parser (State -> State) hideZeroBalances = parseOpt ["hide-zero-balances"] "" (C.NoArg f)   where-    f op =-      return (op {Op.showZeroBalances = CO.ShowZeroBalances False })+    f st = st {showZeroBalances = CO.ShowZeroBalances False }  -- | Turns a field on if it is True. fieldOn ::-  Fl.T Bool+  F.Fields Bool   -- ^ Fields as seen so far -  -> Fl.T Bool+  -> F.Fields Bool   -- ^ Record that should have one True element indicating a field   -- name seen on the command line; other elements should be False   -  -> Fl.T Bool+  -> F.Fields Bool   -- ^ Fields as seen so far, with new field added  fieldOn old new = (||) <$> old <*> new  -- | Turns off a field if it is True. fieldOff ::-  Fl.T Bool+  F.Fields Bool   -- ^ Fields seen so far   -  -> Fl.T Bool+  -> F.Fields Bool   -- ^ Record that should have one True element indicating a field   -- name seen on the command line; other elements should be False   -  -> Fl.T Bool+  -> F.Fields Bool   -- ^ Fields as seen so far, with new field added  fieldOff old new = f <$> old <*> new@@ -272,7 +304,7 @@     f o False = o     f _ True = False -parseField :: String -> Ex.Exceptional Error (Fl.T Bool)+parseField :: String -> Ex.Exceptional Error (F.Fields Bool) parseField str =   let lower = map toLower str       checkField s =@@ -283,44 +315,44 @@   in checkFields flds  -- | Checks the fields with the True value to ensure there is only one.-checkFields :: Fl.T (String, Bool) -> Ex.Exceptional Error (Fl.T Bool)+checkFields :: F.Fields (String, Bool) -> Ex.Exceptional Error (F.Fields Bool) checkFields fs =   let f (s, b) ls = if b then s:ls else ls-  in case F.foldr f [] fs of+  in case Fdbl.foldr f [] fs of     [] -> Ex.throw NoMatchingFieldName     _:[] -> return (snd <$> fs)     ls -> Ex.throw . MultipleMatchingFieldNames $ ls   -fieldNames :: Fl.T String-fieldNames = Fl.T {-  Fl.globalTransaction = "globalTransaction"-  , Fl.revGlobalTransaction = "revGlobalTransaction"-  , Fl.globalPosting = "globalPosting"-  , Fl.revGlobalPosting = "revGlobalPosting"-  , Fl.fileTransaction = "fileTransaction"-  , Fl.revFileTransaction = "revFileTransaction"-  , Fl.filePosting = "filePosting"-  , Fl.revFilePosting = "revFilePosting"-  , Fl.filtered = "filtered"-  , Fl.revFiltered = "revFiltered"-  , Fl.sorted = "sorted"-  , Fl.revSorted = "revSorted"-  , Fl.visible = "visible"-  , Fl.revVisible = "revVisible"-  , Fl.lineNum = "lineNum"-  , Fl.date = "date"-  , Fl.flag = "flag"-  , Fl.number = "number"-  , Fl.payee = "payee"-  , Fl.account = "account"-  , Fl.postingDrCr = "postingDrCr"-  , Fl.postingCmdty = "postingCmdty"-  , Fl.postingQty = "postingQty"-  , Fl.totalDrCr = "totalDrCr"-  , Fl.totalCmdty = "totalCmdty"-  , Fl.totalQty = "totalQty"-  , Fl.tags = "tags"-  , Fl.memo = "memo"-  , Fl.filename = "filename" }+fieldNames :: F.Fields String+fieldNames = F.Fields {+  F.globalTransaction = "globalTransaction"+  , F.revGlobalTransaction = "revGlobalTransaction"+  , F.globalPosting = "globalPosting"+  , F.revGlobalPosting = "revGlobalPosting"+  , F.fileTransaction = "fileTransaction"+  , F.revFileTransaction = "revFileTransaction"+  , F.filePosting = "filePosting"+  , F.revFilePosting = "revFilePosting"+  , F.filtered = "filtered"+  , F.revFiltered = "revFiltered"+  , F.sorted = "sorted"+  , F.revSorted = "revSorted"+  , F.visible = "visible"+  , F.revVisible = "revVisible"+  , F.lineNum = "lineNum"+  , F.date = "date"+  , F.flag = "flag"+  , F.number = "number"+  , F.payee = "payee"+  , F.account = "account"+  , F.postingDrCr = "postingDrCr"+  , F.postingCmdty = "postingCmdty"+  , F.postingQty = "postingQty"+  , F.totalDrCr = "totalDrCr"+  , F.totalCmdty = "totalCmdty"+  , F.totalQty = "totalQty"+  , F.tags = "tags"+  , F.memo = "memo"+  , F.filename = "filename" }
Penny/Cabin/Posts/Spacers.hs view
@@ -3,7 +3,7 @@ -- field. module Penny.Cabin.Posts.Spacers where -data T a = T {+data Spacers a = Spacers {   globalTransaction :: a   , revGlobalTransaction :: a   , globalPosting :: a@@ -31,78 +31,3 @@   , totalDrCr :: a   , totalCmdty :: a }   deriving (Show, Eq)--t_globalTransaction :: a -> T a -> T a-t_globalTransaction a f = f { globalTransaction = a }--t_revGlobalTransaction :: a -> T a -> T a-t_revGlobalTransaction a f = f { revGlobalTransaction = a }--t_globalPosting :: a -> T a -> T a-t_globalPosting a f = f { globalPosting = a }--t_revGlobalPosting :: a -> T a -> T a-t_revGlobalPosting a f = f { revGlobalPosting = a }--t_fileTransaction :: a -> T a -> T a-t_fileTransaction a f = f { fileTransaction = a }--t_revFileTransaction :: a -> T a -> T a-t_revFileTransaction a f = f { revFileTransaction = a }--t_filePosting :: a -> T a -> T a-t_filePosting a f = f { filePosting = a }--t_revFilePosting :: a -> T a -> T a-t_revFilePosting a f = f { revFilePosting = a }--t_filtered :: a -> T a -> T a-t_filtered a f = f { filtered = a }--t_revFiltered :: a -> T a -> T a-t_revFiltered a f = f { revFiltered = a }--t_sorted :: a -> T a -> T a-t_sorted a f = f { sorted = a }--t_revSorted :: a -> T a -> T a-t_revSorted a f = f { revSorted = a }--t_visible :: a -> T a -> T a-t_visible a f = f { visible = a }--t_revVisible :: a -> T a -> T a-t_revVisible a f = f { revVisible = a }--t_lineNum :: a -> T a -> T a-t_lineNum a f = f { lineNum = a }--t_date :: a -> T a -> T a-t_date a f = f { date = a }--t_flag :: a -> T a -> T a-t_flag a f = f { flag = a }--t_number :: a -> T a -> T a-t_number a f = f { number = a }--t_payee :: a -> T a -> T a-t_payee a f = f { payee = a }--t_account :: a -> T a -> T a-t_account a f = f { account = a }--t_postingDrCr :: a -> T a -> T a-t_postingDrCr a f = f { postingDrCr = a }--t_postingCmdty :: a -> T a -> T a-t_postingCmdty a f = f { postingCmdty = a }--t_postingQty :: a -> T a -> T a-t_postingQty a f = f { postingQty = a }--t_totalDrCr :: a -> T a -> T a-t_totalDrCr a f = f { totalDrCr = a }--t_totalCmdty :: a -> T a -> T a-t_totalCmdty a f = f { totalCmdty = a }
+ Penny/Cabin/Posts/Types.hs view
@@ -0,0 +1,4 @@+module Penny.Cabin.Posts.Types where++newtype ReportWidth = ReportWidth { unReportWidth :: Int }+                      deriving (Eq, Show, Ord)
Penny/Lincoln.hs view
@@ -195,6 +195,10 @@   , S.backward   , S.serials   , S.serialItems+    +    -- * Matchers+  , Matchers.Matcher+  , Matchers.Factory    ) where @@ -203,6 +207,7 @@ import qualified Penny.Lincoln.Builders as Bd import qualified Penny.Lincoln.Family as F import qualified Penny.Lincoln.HasText as HT+import qualified Penny.Lincoln.Matchers as Matchers import qualified Penny.Lincoln.Meta as M import qualified Penny.Lincoln.PriceDb as DB import qualified Penny.Lincoln.Serial as S
+ Penny/Lincoln/Matchers.hs view
@@ -0,0 +1,23 @@+-- | Type synonyms for functions dealing with text matching.++module Penny.Lincoln.Matchers where++import qualified Data.Text as X+import qualified Control.Monad.Exception.Synchronous as Ex+import qualified Text.Matchers.Text as MT++type Matcher = X.Text -> Bool++-- | A function that makes Matchers.+type Factory =+  MT.CaseSensitive+  -- ^ Will this matcher be case sensitive?+  +  -> X.Text+  -- ^ The pattern to use when testing for a match. For example, this+  -- might be a regular expression, or simply the text to be matched.++  -> Ex.Exceptional X.Text Matcher+  -- ^ Sometimes producing a matcher might fail; for example, the user+  -- might have supplied a bad pattern. If so, an exception is+  -- returned. On success, a Matcher is returned.
penny-lib.cabal view
@@ -1,5 +1,5 @@ Name: penny-lib-Version: 0.2.0.0+Version: 0.4.0.0 Cabal-version: >=1.8 Build-Type: Simple License: MIT@@ -191,7 +191,6 @@         Penny.Cabin.Balance,         Penny.Cabin.Balance.Parser,         Penny.Cabin.Balance.Help,-        Penny.Cabin.Balance.Options,         Penny.Cabin.Balance.Tree,         Penny.Cabin.Chunk,         Penny.Cabin.Chunk.Switch,@@ -210,9 +209,9 @@         Penny.Cabin.Posts.Chunk,         Penny.Cabin.Posts.Help,         Penny.Cabin.Posts.Meta,-        Penny.Cabin.Posts.Options,         Penny.Cabin.Posts.Parser,         Penny.Cabin.Posts.Spacers,+        Penny.Cabin.Posts.Types,         Penny.Cabin.Row,         Penny.Cabin.TextFormat,         Penny.Copper,@@ -262,6 +261,7 @@         Penny.Lincoln.Family.Family,         Penny.Lincoln.Family.Siblings,         Penny.Lincoln.HasText,+        Penny.Lincoln.Matchers,         Penny.Lincoln.Meta,         Penny.Lincoln.NestedMap,         Penny.Lincoln.Predicates,