Skip to content

Commit c954353

Browse files
committed
cli: support for new layout bare-wide
1 parent a57db5f commit c954353

File tree

3 files changed

+142
-49
lines changed

3 files changed

+142
-49
lines changed

hledger-lib/Hledger/Reports/ReportOptions.hs

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

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

384-
err = usageError "--layout's argument should be \"wide[,WIDTH]\", \"tall\", \"bare\", or \"tidy\""
386+
err = usageError "--layout's argument should be \"wide[,WIDTH]\", \"tall\", \"bare\", \"bare-wide\", or \"tidy\""
385387

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

hledger/Hledger/Cli/Commands/Balance.hs

Lines changed: 95 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -584,15 +584,8 @@ renderComponent topaligned oneline opts (acctname, dep, total) (FormatField ljus
584584
}
585585

586586

587-
headerCell :: Text -> Ods.Cell Ods.NumLines Text
588-
headerCell text =
589-
let deflt = Ods.defaultCell text
590-
in
591-
deflt {
592-
Ods.cellStyle = Ods.Head,
593-
Ods.cellBorder =
594-
(Ods.cellBorder deflt) {Ods.borderBottom = Ods.DoubleLine}
595-
}
587+
headerCell :: (Ods.Lines borders) => Text -> Ods.Cell borders Text
588+
headerCell text = (Ods.defaultCell text) {Ods.cellStyle = Ods.Head}
596589

597590
registerQueryUrl :: [Text] -> Text
598591
registerQueryUrl query =
@@ -634,13 +627,30 @@ replaceDate :: Text -> [Text] -> [Text]
634627
replaceDate prd query = "date:"<>prd : removeDates query
635628

636629
headerDateSpanCell ::
637-
Maybe Text -> [Text] -> DateSpan -> Ods.Cell Ods.NumLines Text
630+
Maybe Text -> [Text] -> DateSpan -> Ods.Cell () Text
638631
headerDateSpanCell base query spn =
639632
let prd = showDateSpan spn in
640633
(headerCell prd) {
641634
Ods.cellAnchor = composeAnchor base $ replaceDate prd query
642635
}
643636

637+
headerWithoutBorders :: [Ods.Cell () text] -> [Ods.Cell Ods.NumLines text]
638+
headerWithoutBorders = map (\c -> c {Ods.cellBorder = Ods.noBorder})
639+
640+
addHeaderBorders :: [Ods.Cell () text] -> [Ods.Cell Ods.NumLines text]
641+
addHeaderBorders =
642+
map (\c -> c {Ods.cellBorder =
643+
Ods.noBorder {Ods.borderBottom = Ods.DoubleLine}})
644+
645+
groupHeaderCells ::
646+
(Ods.Lines border, Monoid text) =>
647+
[a] -> Ods.Cell border text -> [Ods.Cell border text]
648+
groupHeaderCells subCells cell =
649+
zipWith const
650+
(cell{Ods.cellSpan = Ods.SpanHorizontal $ length subCells}
651+
: repeat (Ods.emptyCell {Ods.cellSpan = Ods.Covered}))
652+
subCells
653+
644654
simpleDateSpanCell :: DateSpan -> Ods.Cell Ods.NumLines Text
645655
simpleDateSpanCell = Ods.defaultCell . showDateSpan
646656

@@ -698,10 +708,13 @@ balanceReportAsSpreadsheet opts (items, total) =
698708
where
699709
cell = Ods.defaultCell
700710
headers =
701-
map headerCell $
711+
addHeaderBorders $ map headerCell $
702712
"account" : case layout_ opts of
713+
LayoutBareWide -> allCommodities
703714
LayoutBare -> ["commodity", "balance"]
704715
_ -> ["balance"]
716+
allCommodities =
717+
S.toAscList $ foldMap (\(_,_,_,ma) -> maCommodities ma) items
705718
rows ::
706719
RowClass -> BalanceReportItem ->
707720
[[Ods.Cell Ods.NumLines Text]]
@@ -713,6 +726,15 @@ balanceReportAsSpreadsheet opts (items, total) =
713726
cell $ renderBalanceAcct opts nbsp (name, dispName, dep) in
714727
addRowSpanHeader accountCell $
715728
case layout_ opts of
729+
LayoutBareWide ->
730+
let bopts =
731+
machineFmt {
732+
displayCommodity = False,
733+
displayCommodityOrder = Just allCommodities
734+
} in
735+
[map (\bldAmt ->
736+
fmap wbToText $ cellFromAmount bopts (amountClass rc, bldAmt)) $
737+
showMixedAmountLinesPartsB bopts ma]
716738
LayoutBare ->
717739
map (\a -> [cell $ acommodity a, renderAmount rc $ mixedAmount a])
718740
. amounts $ mixedAmountStripCosts ma
@@ -750,6 +772,15 @@ cellsFromMixedAmount bopts (cls, mixedAmt) =
750772
})
751773
(showMixedAmountLinesPartsB bopts mixedAmt)
752774

775+
cellFromAmount ::
776+
(Ods.Lines border) =>
777+
AmountFormat -> (Ods.Class, (wb, Amount)) -> Ods.Cell border wb
778+
cellFromAmount bopts (cls, (str,amt)) =
779+
(Ods.defaultCell str) {
780+
Ods.cellClass = cls,
781+
Ods.cellType = amountType bopts amt
782+
}
783+
753784
amountType :: AmountFormat -> Amount -> Ods.Type
754785
amountType bopts amt =
755786
Ods.TypeAmount $
@@ -772,30 +803,43 @@ multiBalanceReportAsCsv opts@ReportOpts{..} report = maybeTranspose allRows
772803
case layout_ of
773804
LayoutTidy -> rows -- tidy csv should not include totals or averages
774805
_ -> rows ++ totals
775-
rows = header:body
806+
rows = header++body
776807
(header, body, totals) =
777-
multiBalanceReportAsSpreadsheetParts machineFmt opts report
808+
multiBalanceReportAsSpreadsheetParts machineFmt opts
809+
(allCommoditiesFromPeriodicReport $ prRows report) report
778810
maybeTranspose = if transpose_ then transpose else id
779811

780812
-- | Render the Spreadsheet table rows (CSV, ODS, HTML) for a MultiBalanceReport.
781813
-- Returns the heading row, 0 or more body rows, and the totals row if enabled.
782814
multiBalanceReportAsSpreadsheetParts ::
783-
AmountFormat -> ReportOpts -> MultiBalanceReport ->
784-
([Ods.Cell Ods.NumLines Text],
815+
AmountFormat -> ReportOpts ->
816+
[CommoditySymbol] -> MultiBalanceReport ->
817+
([[Ods.Cell Ods.NumLines Text]],
785818
[[Ods.Cell Ods.NumLines Text]],
786819
[[Ods.Cell Ods.NumLines Text]])
787-
multiBalanceReportAsSpreadsheetParts fmt opts@ReportOpts{..} (PeriodicReport colspans items tr) =
788-
(headers, concatMap fullRowAsTexts items, addTotalBorders totalrows)
820+
multiBalanceReportAsSpreadsheetParts fmt opts@ReportOpts{..}
821+
allCommodities (PeriodicReport colspans items tr) =
822+
(allHeaders, concatMap fullRowAsTexts items, addTotalBorders totalrows)
789823
where
790824
accountCell label =
791825
(Ods.defaultCell label) {Ods.cellClass = Ods.Class "account"}
792826
hCell cls label = (headerCell label) {Ods.cellClass = Ods.Class cls}
827+
allHeaders =
828+
case layout_ of
829+
LayoutBareWide ->
830+
[headerWithoutBorders $
831+
Ods.emptyCell :
832+
concatMap (groupHeaderCells allCommodities) dateHeaders,
833+
headers]
834+
_ -> [headers]
793835
headers =
836+
addHeaderBorders $
794837
hCell "account" "account" :
795838
case layout_ of
796839
LayoutTidy ->
797840
map headerCell
798841
["period", "start_date", "end_date", "commodity", "value"]
842+
LayoutBareWide -> dateHeaders >> map headerCell allCommodities
799843
LayoutBare -> headerCell "commodity" : dateHeaders
800844
_ -> dateHeaders
801845
dateHeaders =
@@ -816,7 +860,7 @@ multiBalanceReportAsSpreadsheetParts fmt opts@ReportOpts{..} (PeriodicReport col
816860
rowAsText Total simpleDateSpanCell tr
817861
rowAsText rc dsCell =
818862
map (map (fmap wbToText)) .
819-
multiBalanceRowAsCellBuilders fmt opts colspans rc dsCell
863+
multiBalanceRowAsCellBuilders fmt opts colspans allCommodities rc dsCell
820864

821865

822866
-- | Render a multi-column balance report as HTML.
@@ -834,10 +878,12 @@ multiBalanceReportAsSpreadsheet ::
834878
((Maybe Int, Maybe Int), [[Ods.Cell Ods.NumLines Text]])
835879
multiBalanceReportAsSpreadsheet ropts mbr =
836880
let (header,body,total) =
837-
multiBalanceReportAsSpreadsheetParts oneLineNoCostFmt ropts mbr
881+
multiBalanceReportAsSpreadsheetParts oneLineNoCostFmt ropts
882+
(allCommoditiesFromPeriodicReport $ prRows mbr) mbr
838883
in (if transpose_ ropts then swap *** Ods.transpose else id) $
839-
((Just 1, case layout_ ropts of LayoutWide _ -> Just 1; _ -> Nothing),
840-
header : body ++ total)
884+
((Just $ case layout_ ropts of LayoutBareWide -> 2; _ -> 1,
885+
case layout_ ropts of LayoutWide _ -> Just 1; _ -> Nothing),
886+
header ++ body ++ total)
841887

842888

843889
-- | Render a multi-column balance report as plain text suitable for console output.
@@ -908,19 +954,24 @@ multiBalanceReportAsTable opts@ReportOpts{summary_only_, average_, balanceaccum_
908954
(concat rows)
909955
where
910956
colheadings = ["Commodity" | layout_ opts == LayoutBare]
911-
++ (if not summary_only_ then map (reportPeriodName balanceaccum_ spans) spans else [])
957+
++ (if not summary_only_
958+
then case layout_ opts of
959+
LayoutBareWide -> spans >> allCommodities
960+
_ -> map (reportPeriodName balanceaccum_ spans) spans
961+
else [])
912962
++ [" Total" | multiBalanceHasTotalsColumn opts]
913963
++ ["Average" | average_]
964+
allCommodities = allCommoditiesFromPeriodicReport items
914965
(accts, rows) = unzip $ fmap fullRowAsTexts items
915966
where
916967
fullRowAsTexts row = (replicate (length rs) (renderacct row), rs)
917968
where
918-
rs = multiBalanceRowAsText opts row
969+
rs = multiBalanceRowAsText opts allCommodities row
919970
renderacct row' = T.replicate (prrIndent row' * 2) " " <> prrDisplayName row'
920971
addtotalrow
921972
| no_total_ opts = id
922973
| otherwise =
923-
let totalrows = multiBalanceRowAsText opts tr
974+
let totalrows = multiBalanceRowAsText opts allCommodities tr
924975
rowhdrs = Group NoLine $ map Header $ totalRowHeadingText : replicate (length totalrows - 1) ""
925976
colhdrs = Header [] -- unused, concatTables will discard
926977
in (flip (concatTables SingleLine) $ Table rowhdrs colhdrs totalrows)
@@ -929,12 +980,17 @@ multiBalanceReportAsTable opts@ReportOpts{summary_only_, average_, balanceaccum_
929980
multiColumnTableInterRowBorder = NoLine
930981
multiColumnTableInterColumnBorder = if pretty_ opts then SingleLine else NoLine
931982

983+
allCommoditiesFromPeriodicReport ::
984+
[PeriodicReportRow a MixedAmount] -> [CommoditySymbol]
985+
allCommoditiesFromPeriodicReport =
986+
S.toAscList . foldMap (foldMap maCommodities . prrAmounts)
987+
932988
multiBalanceRowAsCellBuilders ::
933-
AmountFormat -> ReportOpts -> [DateSpan] ->
989+
AmountFormat -> ReportOpts -> [DateSpan] -> [CommoditySymbol] ->
934990
RowClass -> (DateSpan -> Ods.Cell Ods.NumLines Text) ->
935991
PeriodicReportRow a MixedAmount ->
936992
[[Ods.Cell Ods.NumLines WideBuilder]]
937-
multiBalanceRowAsCellBuilders bopts ropts@ReportOpts{..} colspans
993+
multiBalanceRowAsCellBuilders bopts ropts@ReportOpts{..} colspans allCommodities
938994
rc renderDateSpanCell (PeriodicReportRow _acct as rowtot rowavg) =
939995
case layout_ of
940996
LayoutWide width -> [fmap (cellFromMixedAmount bopts{displayMaxWidth=width}) clsamts]
@@ -945,6 +1001,8 @@ multiBalanceRowAsCellBuilders bopts ropts@ReportOpts{..} colspans
9451001
. transpose -- each row becomes a list of Text quantities
9461002
. map (cellsFromMixedAmount bopts{displayCommodity=False, displayCommodityOrder=Just cs, displayMinWidth=Nothing})
9471003
$ clsamts
1004+
LayoutBareWide -> [concatMap (cellsFromMixedAmount bopts{displayCommodity=False, displayCommodityOrder=Just allCommodities, displayMinWidth=Nothing})
1005+
$ clsamts]
9481006
LayoutTidy -> concat
9491007
. zipWith (map . addDateColumns) colspans
9501008
. map ( zipWith (\c a -> [wbCell c, a]) cs
@@ -987,16 +1045,20 @@ multiBalanceHasTotalsColumn :: ReportOpts -> Bool
9871045
multiBalanceHasTotalsColumn ropts =
9881046
row_total_ ropts && balanceaccum_ ropts `notElem` [Cumulative, Historical]
9891047

990-
multiBalanceRowAsText :: ReportOpts -> PeriodicReportRow a MixedAmount -> [[WideBuilder]]
991-
multiBalanceRowAsText opts =
1048+
multiBalanceRowAsText ::
1049+
ReportOpts -> [CommoditySymbol] -> PeriodicReportRow a MixedAmount -> [[WideBuilder]]
1050+
multiBalanceRowAsText opts allCommodities =
9921051
rawTableContent .
993-
multiBalanceRowAsCellBuilders oneLineNoCostFmt{displayColour=color_ opts} opts []
1052+
multiBalanceRowAsCellBuilders oneLineNoCostFmt{displayColour=color_ opts}
1053+
opts [] allCommodities
9941054
Value simpleDateSpanCell
9951055

996-
multiBalanceRowAsCsvText :: ReportOpts -> [DateSpan] -> PeriodicReportRow a MixedAmount -> [[T.Text]]
997-
multiBalanceRowAsCsvText opts colspans =
1056+
multiBalanceRowAsCsvText ::
1057+
ReportOpts -> [DateSpan] -> [CommoditySymbol] ->
1058+
PeriodicReportRow a MixedAmount -> [[T.Text]]
1059+
multiBalanceRowAsCsvText opts colspans allCommodities =
9981060
map (map (wbToText . Ods.cellContent)) .
999-
multiBalanceRowAsCellBuilders machineFmt opts colspans
1061+
multiBalanceRowAsCellBuilders machineFmt opts colspans allCommodities
10001062
Value simpleDateSpanCell
10011063

10021064

@@ -1258,7 +1320,7 @@ budgetReportAsSpreadsheet
12581320
= (if transpose_ then Ods.transpose else id) $
12591321

12601322
-- heading row
1261-
(map headerCell $
1323+
(addHeaderBorders $ map headerCell $
12621324
"Account" :
12631325
["Commodity" | layout_ == LayoutBare ]
12641326
++ concatMap (\spn -> [showDateSpan spn, "budget"]) colspans

0 commit comments

Comments
 (0)