dev: reg: areg: Be more clever about register and aregister alignment.

When rendering register or aregister reports, calculate the amount /
balance width based on the first 100 items, and start rendering in that
way. If you encounter a longer one, update and continue rendering. This
will result in adjustment of column width for long reports, but allows
us to save a lot more performant/efficient.

This can be disabled with the new --align-all flag.

We also only render each amount once, rather than twice as before, by
storing the rendered amount in a tuple.
This commit is contained in:
Stephen Morgan 2022-03-11 17:26:10 +11:00 committed by Simon Michael
parent cbc985d411
commit c0cc9e73c1
3 changed files with 47 additions and 21 deletions

View File

@ -56,6 +56,7 @@ aregistermode = hledgerCommandMode
#endif
++ " or $COLUMNS). -wN,M sets description width as well."
)
,flagNone ["align-all"] (setboolopt "align-all") "truly align to the longest widths"
,outputFormatFlag ["txt","csv","json"]
,outputFileFlag
])
@ -127,12 +128,11 @@ accountTransactionsReportItemAsCsvRecord
-- | Render a register report as plain text suitable for console output.
accountTransactionsReportAsText :: CliOpts -> Query -> Query -> AccountTransactionsReport -> TL.Text
accountTransactionsReportAsText copts reportq thisacctq items = TB.toLazyText $
title <> TB.singleton '\n' <> lines
title <> TB.singleton '\n' <>
postingsOrTransactionsReportAsText alignAll copts itemAsText itemamt itembal items
where
lines = foldMap (accountTransactionsReportItemAsText copts reportq thisacctq amtwidth balwidth) items
amtwidth = maximumStrict $ 12 : widths (map itemamt $ take 1000 items)
balwidth = maximumStrict $ 12 : widths (map itembal $ take 1000 items)
widths = map wbWidth . concatMap (showMixedAmountLinesB oneLine)
alignAll = boolopt "align-all" $ rawopts_ copts
itemAsText = accountTransactionsReportItemAsText copts reportq thisacctq
itemamt (_,_,_,_,a,_) = a
itembal (_,_,_,_,_,a) = a
@ -156,11 +156,13 @@ accountTransactionsReportAsText copts reportq thisacctq items = TB.toLazyText $
-- Returns a string which can be multi-line, eg if the running balance
-- has multiple commodities.
--
accountTransactionsReportItemAsText :: CliOpts -> Query -> Query -> Int -> Int -> AccountTransactionsReportItem -> TB.Builder
accountTransactionsReportItemAsText :: CliOpts -> Query -> Query -> Int -> Int
-> (AccountTransactionsReportItem, [WideBuilder], [WideBuilder])
-> TB.Builder
accountTransactionsReportItemAsText
copts@CliOpts{reportspec_=ReportSpec{_rsReportOpts=ropts@ReportOpts{color_}}}
copts@CliOpts{reportspec_=ReportSpec{_rsReportOpts=ropts}}
reportq thisacctq preferredamtwidth preferredbalwidth
(t@Transaction{tdescription}, _, _issplit, otheracctsstr, change, balance) =
((t@Transaction{tdescription}, _, _issplit, otheracctsstr, _, _), amt, bal) =
-- Transaction -- the transaction, unmodified
-- Transaction -- the transaction, as seen from the current account
-- Bool -- is this a split (more than one posting to other accounts) ?
@ -206,9 +208,6 @@ accountTransactionsReportItemAsText
-- gather content
accts = -- T.unpack $ elideAccountName acctwidth $ T.pack
otheracctsstr
amt = showamt change
bal = showamt balance
showamt = showMixedAmountLinesB noPrice{displayColour=color_}
-- tests

View File

@ -50,6 +50,7 @@ registermode = hledgerCommandMode
#endif
++ " or $COLUMNS). -wN,M sets description width as well."
)
,flagNone ["align-all"] (setboolopt "align-all") "truly align to the longest widths"
,outputFormatFlag ["txt","csv","json"]
,outputFileFlag
])
@ -93,12 +94,10 @@ postingsReportItemAsCsvRecord (_, _, _, p, b) = [idx,date,code,desc,acct,amt,bal
-- | Render a register report as plain text suitable for console output.
postingsReportAsText :: CliOpts -> PostingsReport -> TL.Text
postingsReportAsText opts items = TB.toLazyText lines
postingsReportAsText opts = TB.toLazyText .
postingsOrTransactionsReportAsText alignAll opts (postingsReportItemAsText opts) itemamt itembal
where
lines = foldMap (postingsReportItemAsText opts amtwidth balwidth) items
amtwidth = maximumStrict $ 12 : widths (map itemamt $ take 1000 items)
balwidth = maximumStrict $ 12 : widths (map itembal $ take 1000 items)
widths = map wbWidth . concatMap (showMixedAmountLinesB oneLine)
alignAll = boolopt "align-all" $ rawopts_ opts
itemamt (_,_,_,Posting{pamount=a},_) = a
itembal (_,_,_,_,a) = a
@ -126,8 +125,10 @@ postingsReportAsText opts items = TB.toLazyText lines
--
-- Also returns the natural width (without padding) of the amount and balance
-- fields.
postingsReportItemAsText :: CliOpts -> Int -> Int -> PostingsReportItem -> TB.Builder
postingsReportItemAsText opts preferredamtwidth preferredbalwidth (mdate, mperiod, mdesc, p, b) =
postingsReportItemAsText :: CliOpts -> Int -> Int
-> (PostingsReportItem, [WideBuilder], [WideBuilder])
-> TB.Builder
postingsReportItemAsText opts preferredamtwidth preferredbalwidth ((mdate, mperiod, mdesc, p, _), amt, bal) =
table <> TB.singleton '\n'
where
table = renderRowB def{tableBorders=False, borderSpaces=False} . Group NoLine $ map Header
@ -177,9 +178,6 @@ postingsReportItemAsText opts preferredamtwidth preferredbalwidth (mdate, mperio
BalancedVirtualPosting -> (wrap "[" "]", acctwidth-2)
VirtualPosting -> (wrap "(" ")", acctwidth-2)
_ -> (id,acctwidth)
amt = showamt $ pamount p
bal = showamt b
showamt = showMixedAmountLinesB oneLine{displayColour=color_ . _rsReportOpts $ reportspec_ opts}
-- tests

View File

@ -25,6 +25,7 @@ module Hledger.Cli.Utils
pivotByOpts,
anonymiseByOpts,
journalSimilarTransaction,
postingsOrTransactionsReportAsText,
tests_Cli_Utils,
)
where
@ -35,9 +36,11 @@ import Data.Maybe
import qualified Data.Text as T
import qualified Data.Text.IO as T
import qualified Data.Text.Lazy as TL
import qualified Data.Text.Lazy.Builder as TB
import qualified Data.Text.Lazy.IO as TL
import Data.Time (Day)
import Data.Time.Clock.POSIX (POSIXTime, utcTimeToPOSIXSeconds)
import Lens.Micro ((^.))
import Safe (readMay, headMay)
import System.Console.CmdArgs
import System.Directory (getModificationTime, getDirectoryContents, copyFile, doesFileExist)
@ -256,6 +259,32 @@ journalSimilarTransaction cliopts j desc = mbestmatch
journalTransactionsSimilarTo j q desc 10
q = queryFromFlags $ _rsReportOpts $ reportspec_ cliopts
-- | Render a 'PostingsReport' or 'AccountTransactionsReport' as Text,
-- determining the appropriate starting widths and increasing as necessary.
postingsOrTransactionsReportAsText
:: Bool -> CliOpts -> (Int -> Int -> (a, [WideBuilder], [WideBuilder]) -> TB.Builder)
-> (a -> MixedAmount) -> (a -> MixedAmount) -> [a] -> TB.Builder
postingsOrTransactionsReportAsText alignAll opts itemAsText itemamt itembal report =
mconcat . snd $ mapAccumL renderItem (startWidth amt, startWidth bal) itemsWithAmounts
where
minWidth = 12
chunkSize = 100
renderItem (amtWidth, balWidth) item@(_, amt, bal) = ((amtWidth', balWidth'), itemBuilder)
where
itemBuilder = itemAsText amtWidth' balWidth' item
amtWidth' = if alignAll then amtWidth else maximumStrict $ amtWidth : map wbWidth amt
balWidth' = if alignAll then balWidth else maximumStrict $ balWidth : map wbWidth bal
startWidth f = maximum $ minWidth : map wbWidth (concatMap f startAlign)
where
startAlign = (if alignAll then id else take chunkSize) itemsWithAmounts
itemsWithAmounts = map (\x -> (x, showAmt $ itemamt x, showAmt $ itembal x)) report
showAmt = showMixedAmountLinesB oneLine{displayColour=opts^.color__}
amt = second3
bal = third3
tests_Cli_Utils = testGroup "Utils" [
-- testGroup "journalApplyValue" [