fix: non-print-like reports no longer add trailing decimal marks (fix #2115)
That 1.31 change was advertised as being for the print command only, but it affected all commands. Now it affects only print and other "print-like" commands (ie all commands that show whole journal entries that we might want to re-parse). Also three classes of hledger output, and how they modify the commodity display styles' digit group marks and decimal marks to suit different consumers, have been identified and documented (under REPORTING CONCEPTS).
This commit is contained in:
parent
ef2f3e1607
commit
1744021986
@ -221,7 +221,9 @@ quoteCommoditySymbolIfNeeded s
|
||||
data AmountDisplayOpts = AmountDisplayOpts
|
||||
{ displayPrice :: Bool -- ^ Whether to display the Price of an Amount.
|
||||
, displayZeroCommodity :: Bool -- ^ If the Amount rounds to 0, whether to display its commodity string.
|
||||
, displayThousandsSep :: Bool -- ^ Whether to display thousands separators.
|
||||
, displayThousandsSep :: Bool -- ^ Whether to display digit group marks (eg thousands separators)
|
||||
, displayAddDecimalMark :: Bool -- ^ Whether to add a trailing decimal mark when there are no decimal digits
|
||||
-- and there are digit group marks, to disambiguate
|
||||
, displayColour :: Bool -- ^ Whether to colourise negative Amounts.
|
||||
, displayOneLine :: Bool -- ^ Whether to display on one line.
|
||||
, displayMinWidth :: Maybe Int -- ^ Minimum width to pad to
|
||||
@ -240,6 +242,7 @@ noColour = AmountDisplayOpts { displayPrice = True
|
||||
, displayColour = False
|
||||
, displayZeroCommodity = False
|
||||
, displayThousandsSep = True
|
||||
, displayAddDecimalMark = False
|
||||
, displayOneLine = False
|
||||
, displayMinWidth = Just 0
|
||||
, displayMaxWidth = Nothing
|
||||
@ -645,22 +648,25 @@ showAmount = wbUnpack . showAmountB noColour
|
||||
--
|
||||
showAmountB :: AmountDisplayOpts -> Amount -> WideBuilder
|
||||
showAmountB _ Amount{acommodity="AUTO"} = mempty
|
||||
showAmountB opts a@Amount{astyle=style} =
|
||||
showAmountB
|
||||
AmountDisplayOpts{displayPrice, displayColour, displayZeroCommodity,
|
||||
displayThousandsSep, displayAddDecimalMark, displayOrder}
|
||||
a@Amount{astyle=style} =
|
||||
color $ case ascommodityside style of
|
||||
L -> showC (wbFromText comm) space <> quantity' <> price
|
||||
R -> quantity' <> showC space (wbFromText comm) <> price
|
||||
where
|
||||
color = if displayColour opts && isNegativeAmount a then colorB Dull Red else id
|
||||
quantity = showamountquantity $
|
||||
if displayThousandsSep opts then a else a{astyle=(astyle a){asdigitgroups=Nothing}}
|
||||
color = if displayColour && isNegativeAmount a then colorB Dull Red else id
|
||||
quantity = showAmountQuantity displayAddDecimalMark $
|
||||
if displayThousandsSep then a else a{astyle=(astyle a){asdigitgroups=Nothing}}
|
||||
(quantity', comm)
|
||||
| amountLooksZero a && not (displayZeroCommodity opts) = (WideBuilder (TB.singleton '0') 1, "")
|
||||
| amountLooksZero a && not displayZeroCommodity = (WideBuilder (TB.singleton '0') 1, "")
|
||||
| otherwise = (quantity, quoteCommoditySymbolIfNeeded $ acommodity a)
|
||||
space = if not (T.null comm) && ascommodityspaced style then WideBuilder (TB.singleton ' ') 1 else mempty
|
||||
-- concatenate these texts,
|
||||
-- or return the empty text if there's a commodity display order. XXX why ?
|
||||
showC l r = if isJust (displayOrder opts) then mempty else l <> r
|
||||
price = if displayPrice opts then showAmountPrice a else mempty
|
||||
showC l r = if isJust displayOrder then mempty else l <> r
|
||||
price = if displayPrice then showAmountPrice a else mempty
|
||||
|
||||
-- | Colour version. For a negative amount, adds ANSI codes to change the colour,
|
||||
-- currently to hard-coded red.
|
||||
@ -691,10 +697,10 @@ showAmountDebug Amount{..} =
|
||||
|
||||
-- | Get a Text Builder for the string representation of the number part of of an amount,
|
||||
-- using the display settings from its commodity. Also returns the width of the number.
|
||||
-- A special case: if it is showing digit group separators but no decimal places,
|
||||
-- show a decimal mark (with nothing after it) to make it easier to parse correctly.
|
||||
showamountquantity :: Amount -> WideBuilder
|
||||
showamountquantity amt@Amount{astyle=AmountStyle{asdecimalmark=mdec, asdigitgroups=mgrps}} =
|
||||
-- With a true first argument, if there are no decimal digits but there are digit group separators,
|
||||
-- it shows the amount with a trailing decimal mark to help disambiguate it for parsing.
|
||||
showAmountQuantity :: Bool -> Amount -> WideBuilder
|
||||
showAmountQuantity disambiguate amt@Amount{astyle=AmountStyle{asdecimalmark=mdec, asdigitgroups=mgrps}} =
|
||||
signB <> intB <> fracB
|
||||
where
|
||||
Decimal decplaces mantissa = amountRoundedQuantity amt
|
||||
@ -706,13 +712,13 @@ showamountquantity amt@Amount{astyle=AmountStyle{asdecimalmark=mdec, asdigitgrou
|
||||
(intPart, fracPart) = T.splitAt intLen numtxtwithzero
|
||||
intB = applyDigitGroupStyle mgrps intLen $ if decplaces == 0 then numtxt else intPart
|
||||
signB = if mantissa < 0 then WideBuilder (TB.singleton '-') 1 else mempty
|
||||
fracB = if decplaces > 0 || isshowingdigitgroupseparator
|
||||
fracB = if decplaces > 0 || (isshowingdigitgroupseparator && disambiguate)
|
||||
then WideBuilder (TB.singleton dec <> TB.fromText fracPart) (1 + fromIntegral decplaces)
|
||||
else mempty
|
||||
|
||||
isshowingdigitgroupseparator = case mgrps of
|
||||
Just (DigitGroups _ (rightmostgrplen:_)) -> intLen > fromIntegral rightmostgrplen
|
||||
_ -> False
|
||||
where
|
||||
isshowingdigitgroupseparator = case mgrps of
|
||||
Just (DigitGroups _ (rightmostgrplen:_)) -> intLen > fromIntegral rightmostgrplen
|
||||
_ -> False
|
||||
|
||||
-- | Given an integer as text, and its length, apply the given DigitGroupStyle,
|
||||
-- inserting digit group separators between digit groups where appropriate.
|
||||
|
||||
@ -287,7 +287,10 @@ postingAsLines elideamount onelineamounts acctwidth amtwidth p =
|
||||
-- amtwidth at all.
|
||||
shownAmounts
|
||||
| elideamount = [mempty]
|
||||
| otherwise = showMixedAmountLinesB noColour{displayZeroCommodity=True, displayOneLine=onelineamounts} $ pamount p
|
||||
| otherwise = showMixedAmountLinesB displayopts $ pamount p
|
||||
where displayopts = noColour{
|
||||
displayZeroCommodity=True, displayAddDecimalMark=True, displayOneLine=onelineamounts
|
||||
}
|
||||
thisamtwidth = maximumBound 0 $ map wbWidth shownAmounts
|
||||
|
||||
-- when there is a balance assertion, show it only on the last posting line
|
||||
|
||||
@ -4340,6 +4340,32 @@ file.
|
||||
|
||||
# PART 3: REPORTING CONCEPTS
|
||||
|
||||
|
||||
# Amount formatting
|
||||
|
||||
When displaying amounts, digit group marks and decimal marks are
|
||||
handled a little differently depending on the report and output format
|
||||
and intended consumer. hledger output falls into three rough categories:
|
||||
|
||||
**1. "hledger-readable output" should be readable by hledger and by humans**
|
||||
- produced by reports that show full journal entries: `print`, `import`, `close`, `rewrite`..
|
||||
- shows amounts with their original journal precisions, which may not be consistent
|
||||
- adds a trailing decimal mark when needed to disambiguate [ambiguous amounts](decimal-marks-digit-group-marks)
|
||||
(amounts with one digit group mark and no decimal digits)
|
||||
- can be parsed reliably
|
||||
|
||||
**2. "human-readable output" - usually for humans**
|
||||
- produced by all other reports
|
||||
- shows amounts with standard display precisions, which will be consistent within each commodity
|
||||
- can show ambiguous amounts
|
||||
- can be parsed reliably in the context of a known report (because of consistent style)
|
||||
|
||||
**3. "machine-readable output" - usually for other software**
|
||||
- produced by all reports when an output format like `csv`/`tsv`/`json`/`sql` is selected
|
||||
- shows no digit group marks
|
||||
- shows a period decimal mark (.) when there are decimal digits
|
||||
- can be parsed reliably
|
||||
|
||||
# Time periods
|
||||
|
||||
<a name="report-period"></a>
|
||||
|
||||
@ -147,3 +147,44 @@ $ hledger -f- print --explicit
|
||||
$ hledger -f- reg
|
||||
2023-01-01 (a) 1.0 A 1.0 A
|
||||
2023-01-02 (a) 1.2 A 2.2 A
|
||||
|
||||
# ** 10. print-like reports add a trailing decimal mark, when amounts have digit group marks but no decimal digits.
|
||||
<
|
||||
commodity 1.000, JPY
|
||||
|
||||
2023-01-01
|
||||
(a) 1 JPY
|
||||
|
||||
2023-01-02
|
||||
(b) 1,2 JPY
|
||||
|
||||
2023-01-03
|
||||
(c) 1.000 JPY
|
||||
|
||||
$ hledger -f - print
|
||||
2023-01-01
|
||||
(a) 1 JPY
|
||||
|
||||
2023-01-02
|
||||
(b) 1,2 JPY
|
||||
|
||||
2023-01-03
|
||||
(c) 1.000, JPY
|
||||
|
||||
>=
|
||||
|
||||
# ** 11. Non-print-like reports show all amounts with consistent display precision
|
||||
$ hledger -f - bal
|
||||
1 JPY a
|
||||
1 JPY b
|
||||
1.000 JPY c
|
||||
--------------------
|
||||
1.002 JPY
|
||||
|
||||
# ** 12. csv, json and other machine-readable formats show all amounts without digit groups and with period decimal marks.
|
||||
$ hledger -f - bal -O csv
|
||||
"account","balance"
|
||||
"a","1 JPY"
|
||||
"b","1 JPY"
|
||||
"c","1000 JPY"
|
||||
"total","1002 JPY"
|
||||
|
||||
Loading…
Reference in New Issue
Block a user