penny-lib-0.2.0.0: Penny/Cabin/Posts.hs
-- | The Penny Postings report
--
-- The Postings report displays postings in a tabular format designed
-- to be read by humans. Some terminology used in the Postings report:
--
-- [@row@] The smallest unit that spans from left to right. A row,
-- however, might consist of more than one screen line. For example,
-- the running balance is shown on the far right side of the Postings
-- report. The running balance might consist of more than one
-- commodity. Each commodity is displayed on its own screen
-- line. However, all these lines put together are displayed in a
-- single row.
--
-- [@column@] The smallest unit that spans from top to bottom.
--
-- [@tranche@] Each posting is displayed in several rows. The group of
-- rows that is displayed for a single posting is called a tranche.
--
-- [@tranche row@] Each tranche has a particular number of rows
-- (currently four); each of these rows is known as a tranche row.
--
-- [@field@] Corresponds to a particular element of the posting, such
-- as whether it is a debit or credit or its payee. The user can
-- select which fields to see.
--
-- [@allocation@] The width of the Payee and Account fields is
-- variable. Generally their width will adjust to fill the entire
-- width of the screen. The allocations of the Payee and Account
-- fields determine how much of the remaining space each field will
-- receive.
--
-- The Postings report is easily customized from the command line to
-- show various fields. However, the order of the fields is not
-- 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
) 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.Interface as I
import qualified Penny.Cabin.Posts.Options as O
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 qualified Penny.Lincoln as L
import qualified Penny.Liberty as Ly
import qualified Penny.Shield as S
import System.Console.MultiArg.Prim (Parser)
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)
-- | 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.
-> I.Report
customPostsReport = makeReport . parseReportOpts
-- | When passed a ParseReportOpts, makes a Report.
makeReport ::
Parser I.ReportFunc
-> I.Report
makeReport f =
I.Report { I.help = help
, I.name = "posts"
, I.parseReport = f }
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
-- | 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