Skip to content

Commit 1715dba

Browse files
committed
cli: support for new layout bare-wide
1 parent 79fbfb9 commit 1715dba

File tree

3 files changed

+103
-35
lines changed

3 files changed

+103
-35
lines changed

hledger-lib/Hledger/Reports/ReportOptions.hs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -120,6 +120,7 @@ instance Default AccountListMode where def = ALFlat
120120
data Layout = LayoutWide (Maybe Int)
121121
| LayoutTall
122122
| LayoutBare
123+
| LayoutBareWide
123124
| LayoutTidy
124125
deriving (Eq, Show)
125126

@@ -374,6 +375,7 @@ layoutopt rawopts = fromMaybe (LayoutWide Nothing) $ layout <|> column
374375
, ("tall", LayoutTall)
375376
, ("bare", LayoutBare)
376377
, ("tidy", LayoutTidy)
378+
, ("bare-wide", LayoutBareWide)
377379
]
378380
-- For `--layout=elided,n`, elide to the given width
379381
(s,n) = break (==',') $ map toLower opt
@@ -382,7 +384,7 @@ layoutopt rawopts = fromMaybe (LayoutWide Nothing) $ layout <|> column
382384
c | Just w' <- readMay c -> Just w'
383385
_ -> usageError "width in --layout=wide,WIDTH must be an integer"
384386

385-
err = usageError "--layout's argument should be \"wide[,WIDTH]\", \"tall\", \"bare\", or \"tidy\""
387+
err = usageError "--layout's argument should be \"wide[,WIDTH]\", \"tall\", \"bare\", \"bare-wide\", or \"tidy\""
386388

387389
-- Get the period specified by any -b/--begin, -e/--end and/or -p/--period
388390
-- options appearing in the command line.

hledger/Hledger/Cli/Commands/Balance.hs

Lines changed: 67 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -307,7 +307,7 @@ import Hledger.Write.Ods (printFods)
307307
import Hledger.Write.Html (Html, styledTableHtml, htmlAsLazyText, toHtml)
308308
import Hledger.Write.Spreadsheet (rawTableContent, headerCell,
309309
addHeaderBorders, addRowSpanHeader,
310-
cellFromMixedAmount, cellsFromMixedAmount)
310+
cellFromMixedAmount, cellsFromMixedAmount, cellFromAmount)
311311
import qualified Hledger.Write.Spreadsheet as Ods
312312

313313

@@ -598,6 +598,9 @@ renderComponent topaligned oneline opts (acctname, dep, total) (FormatField ljus
598598
}
599599

600600

601+
headerWithoutBorders :: [Ods.Cell () text] -> [Ods.Cell Ods.NumLines text]
602+
headerWithoutBorders = map (\c -> c {Ods.cellBorder = Ods.noBorder})
603+
601604
simpleDateSpanCell :: DateSpan -> Ods.Cell Ods.NumLines Text
602605
simpleDateSpanCell = Ods.defaultCell . showDateSpan
603606

@@ -626,8 +629,11 @@ balanceReportAsSpreadsheet opts (items, total) =
626629
headers =
627630
addHeaderBorders $ map headerCell $
628631
"account" : case layout_ opts of
632+
LayoutBareWide -> allCommodities
629633
LayoutBare -> ["commodity", "balance"]
630634
_ -> ["balance"]
635+
allCommodities =
636+
S.toAscList $ foldMap (\(_,_,_,ma) -> maCommodities ma) items
631637
rows ::
632638
RowClass -> BalanceReportItem ->
633639
[[Ods.Cell Ods.NumLines Text]]
@@ -639,6 +645,15 @@ balanceReportAsSpreadsheet opts (items, total) =
639645
cell $ renderBalanceAcct opts nbsp (name, dispName, dep) in
640646
addRowSpanHeader accountCell $
641647
case layout_ opts of
648+
LayoutBareWide ->
649+
let bopts =
650+
machineFmt {
651+
displayCommodity = False,
652+
displayCommodityOrder = Just allCommodities
653+
} in
654+
[map (\bldAmt ->
655+
fmap wbToText $ cellFromAmount bopts (amountClass rc, bldAmt)) $
656+
showMixedAmountLinesPartsB bopts ma]
642657
LayoutBare ->
643658
map (\a -> [cell $ acommodity a, renderAmount rc $ mixedAmount a])
644659
. amounts $ mixedAmountStripCosts ma
@@ -662,29 +677,41 @@ balanceReportAsSpreadsheet opts (items, total) =
662677
multiBalanceReportAsCsv :: ReportOpts -> MultiBalanceReport -> CSV
663678
multiBalanceReportAsCsv opts@ReportOpts{..} report =
664679
(if transpose_ then transpose else id) $
665-
rawTableContent $ header : body ++ totals
680+
rawTableContent $ header ++ body ++ totals
666681
where
667682
(header, body, totals) =
668-
multiBalanceReportAsSpreadsheetParts machineFmt opts report
683+
multiBalanceReportAsSpreadsheetParts machineFmt opts
684+
(allCommoditiesFromPeriodicReport $ prRows report) report
669685

670686
-- | Render the Spreadsheet table rows (CSV, ODS, HTML) for a MultiBalanceReport.
671687
-- Returns the heading row, 0 or more body rows, and the totals row if enabled.
672688
multiBalanceReportAsSpreadsheetParts ::
673-
AmountFormat -> ReportOpts -> MultiBalanceReport ->
674-
([Ods.Cell Ods.NumLines Text],
689+
AmountFormat -> ReportOpts ->
690+
[CommoditySymbol] -> MultiBalanceReport ->
691+
([[Ods.Cell Ods.NumLines Text]],
675692
[[Ods.Cell Ods.NumLines Text]],
676693
[[Ods.Cell Ods.NumLines Text]])
677-
multiBalanceReportAsSpreadsheetParts fmt opts@ReportOpts{..} (PeriodicReport colspans items tr) =
678-
(headers, concatMap fullRowAsTexts items, addTotalBorders totalrows)
694+
multiBalanceReportAsSpreadsheetParts fmt opts@ReportOpts{..}
695+
allCommodities (PeriodicReport colspans items tr) =
696+
(allHeaders, concatMap fullRowAsTexts items, addTotalBorders totalrows)
679697
where
680698
accountCell label =
681699
(Ods.defaultCell label) {Ods.cellClass = Ods.Class "account"}
682700
hCell cls label = (headerCell label) {Ods.cellClass = Ods.Class cls}
701+
allHeaders =
702+
case layout_ of
703+
LayoutBareWide ->
704+
[headerWithoutBorders $
705+
Ods.emptyCell :
706+
concatMap (Ods.horizontalSpan allCommodities) dateHeaders,
707+
headers]
708+
_ -> [headers]
683709
headers =
684710
addHeaderBorders $
685711
hCell "account" "account" :
686712
case layout_ of
687713
LayoutTidy -> map headerCell tidyColumnLabels
714+
LayoutBareWide -> dateHeaders >> map headerCell allCommodities
688715
LayoutBare -> headerCell "commodity" : dateHeaders
689716
_ -> dateHeaders
690717
dateHeaders =
@@ -705,7 +732,7 @@ multiBalanceReportAsSpreadsheetParts fmt opts@ReportOpts{..} (PeriodicReport col
705732
rowAsText Total simpleDateSpanCell tr
706733
rowAsText rc dsCell =
707734
map (map (fmap wbToText)) .
708-
multiBalanceRowAsCellBuilders fmt opts colspans rc dsCell
735+
multiBalanceRowAsCellBuilders fmt opts colspans allCommodities rc dsCell
709736

710737
tidyColumnLabels :: [Text]
711738
tidyColumnLabels =
@@ -725,10 +752,12 @@ multiBalanceReportAsSpreadsheet ::
725752
((Int, Int), [[Ods.Cell Ods.NumLines Text]])
726753
multiBalanceReportAsSpreadsheet ropts mbr =
727754
let (header,body,total) =
728-
multiBalanceReportAsSpreadsheetParts oneLineNoCostFmt ropts mbr
755+
multiBalanceReportAsSpreadsheetParts oneLineNoCostFmt ropts
756+
(allCommoditiesFromPeriodicReport $ prRows mbr) mbr
729757
in (if transpose_ ropts then swap *** Ods.transpose else id) $
730-
((1, case layout_ ropts of LayoutWide _ -> 1; _ -> 0),
731-
header : body ++ total)
758+
((case layout_ ropts of LayoutBareWide -> 2; _ -> 1,
759+
case layout_ ropts of LayoutWide _ -> 1; _ -> 0),
760+
header ++ body ++ total)
732761

733762

734763
-- | Render a multi-column balance report as plain text suitable for console output.
@@ -799,19 +828,24 @@ multiBalanceReportAsTable opts@ReportOpts{summary_only_, average_, balanceaccum_
799828
(concat rows)
800829
where
801830
colheadings = ["Commodity" | layout_ opts == LayoutBare]
802-
++ (if not summary_only_ then map (reportPeriodName balanceaccum_ spans) spans else [])
831+
++ (if not summary_only_
832+
then case layout_ opts of
833+
LayoutBareWide -> spans >> allCommodities
834+
_ -> map (reportPeriodName balanceaccum_ spans) spans
835+
else [])
803836
++ [" Total" | multiBalanceHasTotalsColumn opts]
804837
++ ["Average" | average_]
838+
allCommodities = allCommoditiesFromPeriodicReport items
805839
(accts, rows) = unzip $ fmap fullRowAsTexts items
806840
where
807841
fullRowAsTexts row = (replicate (length rs) (renderacct row), rs)
808842
where
809-
rs = multiBalanceRowAsText opts row
843+
rs = multiBalanceRowAsText opts allCommodities row
810844
renderacct row' = T.replicate (prrIndent row' * 2) " " <> prrDisplayName row'
811845
addtotalrow
812846
| no_total_ opts = id
813847
| otherwise =
814-
let totalrows = multiBalanceRowAsText opts tr
848+
let totalrows = multiBalanceRowAsText opts allCommodities tr
815849
rowhdrs = Group NoLine $ map Header $ totalRowHeadingText : replicate (length totalrows - 1) ""
816850
colhdrs = Header [] -- unused, concatTables will discard
817851
in (flip (concatTables SingleLine) $ Table rowhdrs colhdrs totalrows)
@@ -820,12 +854,17 @@ multiBalanceReportAsTable opts@ReportOpts{summary_only_, average_, balanceaccum_
820854
multiColumnTableInterRowBorder = NoLine
821855
multiColumnTableInterColumnBorder = if pretty_ opts then SingleLine else NoLine
822856

857+
allCommoditiesFromPeriodicReport ::
858+
[PeriodicReportRow a MixedAmount] -> [CommoditySymbol]
859+
allCommoditiesFromPeriodicReport =
860+
S.toAscList . foldMap (foldMap maCommodities . prrAmounts)
861+
823862
multiBalanceRowAsCellBuilders ::
824-
AmountFormat -> ReportOpts -> [DateSpan] ->
863+
AmountFormat -> ReportOpts -> [DateSpan] -> [CommoditySymbol] ->
825864
RowClass -> (DateSpan -> Ods.Cell Ods.NumLines Text) ->
826865
PeriodicReportRow a MixedAmount ->
827866
[[Ods.Cell Ods.NumLines WideBuilder]]
828-
multiBalanceRowAsCellBuilders bopts ropts@ReportOpts{..} colspans
867+
multiBalanceRowAsCellBuilders bopts ropts@ReportOpts{..} colspans allCommodities
829868
rc renderDateSpanCell (PeriodicReportRow _acct as rowtot rowavg) =
830869
case layout_ of
831870
LayoutWide width -> [fmap (cellFromMixedAmount bopts{displayMaxWidth=width}) clsamts]
@@ -836,6 +875,8 @@ multiBalanceRowAsCellBuilders bopts ropts@ReportOpts{..} colspans
836875
. transpose -- each row becomes a list of Text quantities
837876
. map (cellsFromMixedAmount bopts{displayCommodity=False, displayCommodityOrder=Just cs, displayMinWidth=Nothing})
838877
$ clsamts
878+
LayoutBareWide -> [concatMap (cellsFromMixedAmount bopts{displayCommodity=False, displayCommodityOrder=Just allCommodities, displayMinWidth=Nothing})
879+
$ clsamts]
839880
LayoutTidy -> concat
840881
. zipWith (map . addDateColumns) colspans
841882
. map ( zipWith (\c a -> [wbCell c, a]) cs
@@ -878,16 +919,20 @@ multiBalanceHasTotalsColumn :: ReportOpts -> Bool
878919
multiBalanceHasTotalsColumn ropts =
879920
row_total_ ropts && balanceaccum_ ropts `notElem` [Cumulative, Historical]
880921

881-
multiBalanceRowAsText :: ReportOpts -> PeriodicReportRow a MixedAmount -> [[WideBuilder]]
882-
multiBalanceRowAsText opts =
922+
multiBalanceRowAsText ::
923+
ReportOpts -> [CommoditySymbol] -> PeriodicReportRow a MixedAmount -> [[WideBuilder]]
924+
multiBalanceRowAsText opts allCommodities =
883925
rawTableContent .
884-
multiBalanceRowAsCellBuilders oneLineNoCostFmt{displayColour=color_ opts} opts []
926+
multiBalanceRowAsCellBuilders oneLineNoCostFmt{displayColour=color_ opts}
927+
opts [] allCommodities
885928
Value simpleDateSpanCell
886929

887-
multiBalanceRowAsCsvText :: ReportOpts -> [DateSpan] -> PeriodicReportRow a MixedAmount -> [[T.Text]]
888-
multiBalanceRowAsCsvText opts colspans =
930+
multiBalanceRowAsCsvText ::
931+
ReportOpts -> [DateSpan] -> [CommoditySymbol] ->
932+
PeriodicReportRow a MixedAmount -> [[T.Text]]
933+
multiBalanceRowAsCsvText opts colspans allCommodities =
889934
map (map (wbToText . Ods.cellContent)) .
890-
multiBalanceRowAsCellBuilders machineFmt opts colspans
935+
multiBalanceRowAsCellBuilders machineFmt opts colspans allCommodities
891936
Value simpleDateSpanCell
892937

893938

hledger/Hledger/Cli/CompoundBalanceCommand.hs

Lines changed: 33 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ import qualified Data.List.NonEmpty as NonEmpty
2525
import qualified Data.Text as T
2626
import qualified Data.Text.Lazy as TL
2727
import qualified Data.Text.Lazy.Builder as TB
28+
import qualified Data.Set as Set
2829
import Data.Time.Calendar (Day, addDays)
2930
import Lucid as L hiding (Html, value_)
3031
import System.Console.CmdArgs.Explicit as C (Mode, flagNone, flagReq)
@@ -287,12 +288,14 @@ compoundBalanceReportAsText ropts (CompoundPeriodicReport title _colspans subrep
287288
-- [COL1LINE1, COL2LINE1]
288289
-- [COL1LINE2, COL2LINE2]
289290
-- ]
290-
coltotalslines = multiBalanceRowAsText ropts totalsrow
291+
coltotalslines = multiBalanceRowAsText ropts allCommodities totalsrow
291292
totalstable = Table
292293
(Group NoLine $ map Header $ "Net:" : replicate (length coltotalslines - 1) "") -- row headers
293294
(Header []) -- column headers, concatTables will discard these
294295
coltotalslines -- cell values
295296

297+
allCommodities = allCommoditiesFromSubreports subreports
298+
296299
-- | Convert a named multi balance report to a table suitable for
297300
-- concatenating with others to make a compound balance report table.
298301
subreportAsTable ropts1 (title1, r, _) = tablewithtitle
@@ -357,14 +360,21 @@ compoundBalanceReportAsSpreadsheet fmt accountLabel maybeBlank ropts cbr =
357360
_ -> []
358361
dataHeaders =
359362
(guard (layout_ ropts /= LayoutTidy) >>) $
360-
map (Spr.headerCell . reportPeriodName (balanceaccum_ ropts) colspans)
361-
(if not (summary_only_ ropts) then colspans else []) ++
362-
(guard (multiBalanceHasTotalsColumn ropts) >> [Spr.headerCell "Total"]) ++
363-
(guard (average_ ropts) >> [Spr.headerCell "Average"])
363+
map (dataHeaderCell . reportPeriodName (balanceaccum_ ropts) colspans)
364+
(if not (summary_only_ ropts) then colspans else []) ++
365+
(guard (multiBalanceHasTotalsColumn ropts) >> [dataHeaderCell "Total"]) ++
366+
(guard (average_ ropts) >> [dataHeaderCell "Average"])
367+
dataHeaderCell label =
368+
(Spr.headerCell label) {Spr.cellSpan = Spr.SpanHorizontal numSubColumns}
364369
headerrow = leadingHeaders ++ dataHeaders
365370

366371
blankrow =
367372
fmap (Spr.horizontalSpan headerrow . Spr.defaultCell) maybeBlank
373+
numSubColumns =
374+
case layout_ ropts of
375+
LayoutBareWide -> length allCommodities
376+
_ -> 1
377+
allCommodities = allCommoditiesFromSubreports subreports
368378

369379
-- Make rows for a subreport: its title row, not the headings row,
370380
-- the data rows, any totals row, and a blank row for whitespace.
@@ -373,14 +383,18 @@ compoundBalanceReportAsSpreadsheet fmt accountLabel maybeBlank ropts cbr =
373383
subreportrows (subreporttitle, mbr, _increasestotal) =
374384
let
375385
(_, bodyrows, mtotalsrows) =
376-
multiBalanceReportAsSpreadsheetParts fmt ropts mbr
377-
378-
in
379-
Spr.horizontalSpan headerrow
380-
((Spr.defaultCell subreporttitle){
386+
multiBalanceReportAsSpreadsheetParts fmt ropts allCommodities mbr
387+
accountCell =
388+
(Spr.defaultCell subreporttitle) {
381389
Spr.cellStyle = Spr.Body Spr.Total,
382390
Spr.cellClass = Spr.Class "account"
383-
}) :
391+
}
392+
393+
in
394+
(case layout_ ropts of
395+
LayoutBareWide ->
396+
accountCell : map Spr.headerCell (dataHeaders >> allCommodities)
397+
_ -> Spr.horizontalSpan headerrow accountCell) :
384398
bodyrows ++
385399
mtotalsrows ++
386400
maybeToList blankrow ++
@@ -389,7 +403,7 @@ compoundBalanceReportAsSpreadsheet fmt accountLabel maybeBlank ropts cbr =
389403
totalrows =
390404
if no_total_ ropts || length subreports == 1 then []
391405
else
392-
multiBalanceRowAsCellBuilders fmt ropts colspans
406+
multiBalanceRowAsCellBuilders fmt ropts colspans allCommodities
393407
Total simpleDateSpanCell totalrow
394408
-- make a table of rendered lines of the report totals row
395409
& map (map (fmap wbToText))
@@ -401,3 +415,10 @@ compoundBalanceReportAsSpreadsheet fmt accountLabel maybeBlank ropts cbr =
401415
in (title,
402416
((1,1),
403417
headerrow :| concatMap subreportrows subreports ++ totalrows))
418+
419+
allCommoditiesFromSubreports ::
420+
[(text, PeriodicReport a MixedAmount, bool)] -> [CommoditySymbol]
421+
allCommoditiesFromSubreports =
422+
Set.toAscList .
423+
foldMap (\(_,mbr,_) ->
424+
foldMap (foldMap maCommodities . prrAmounts) $ prRows mbr)

0 commit comments

Comments
 (0)