journal: use decimal sep hint for amount parser
Make use of commodity format directive as a hint for parsing amount. Kinda resolves simonmichael/hledger#487
This commit is contained in:
parent
dafdaec1ca
commit
b7dbe044b0
@ -30,6 +30,7 @@ import Data.List.Compat
|
|||||||
import Data.List.NonEmpty (NonEmpty(..))
|
import Data.List.NonEmpty (NonEmpty(..))
|
||||||
import Data.List.Split (wordsBy)
|
import Data.List.Split (wordsBy)
|
||||||
import Data.Maybe
|
import Data.Maybe
|
||||||
|
import qualified Data.Map as M
|
||||||
import Data.Monoid
|
import Data.Monoid
|
||||||
import Data.Text (Text)
|
import Data.Text (Text)
|
||||||
import qualified Data.Text as T
|
import qualified Data.Text as T
|
||||||
@ -145,6 +146,12 @@ setDefaultCommodityAndStyle cs = modify' (\j -> j{jparsedefaultcommodity=Just cs
|
|||||||
getDefaultCommodityAndStyle :: JournalParser m (Maybe (CommoditySymbol,AmountStyle))
|
getDefaultCommodityAndStyle :: JournalParser m (Maybe (CommoditySymbol,AmountStyle))
|
||||||
getDefaultCommodityAndStyle = jparsedefaultcommodity `fmap` get
|
getDefaultCommodityAndStyle = jparsedefaultcommodity `fmap` get
|
||||||
|
|
||||||
|
getDefaultDecimalHint :: JournalParser m (Maybe Char)
|
||||||
|
getDefaultDecimalHint = maybe Nothing (asdecimalpoint . snd) <$> getDefaultCommodityAndStyle
|
||||||
|
|
||||||
|
getDecimalHint :: CommoditySymbol -> JournalParser m (Maybe Char)
|
||||||
|
getDecimalHint commodity = maybe Nothing asdecimalpoint . maybe Nothing cformat . M.lookup commodity . jcommodities <$> get
|
||||||
|
|
||||||
pushAccount :: AccountName -> JournalParser m ()
|
pushAccount :: AccountName -> JournalParser m ()
|
||||||
pushAccount acct = modify' (\j -> j{jaccounts = acct : jaccounts j})
|
pushAccount acct = modify' (\j -> j{jaccounts = acct : jaccounts j})
|
||||||
|
|
||||||
@ -415,8 +422,9 @@ leftsymbolamountp = do
|
|||||||
sign <- lift signp
|
sign <- lift signp
|
||||||
m <- lift multiplierp
|
m <- lift multiplierp
|
||||||
c <- lift commoditysymbolp
|
c <- lift commoditysymbolp
|
||||||
|
decimalHint <- getDecimalHint c
|
||||||
sp <- lift $ many spacenonewline
|
sp <- lift $ many spacenonewline
|
||||||
(q,prec,mdec,mgrps) <- lift numberp
|
(q,prec,mdec,mgrps) <- lift $ numberp decimalHint
|
||||||
let s = amountstyle{ascommodityside=L, ascommodityspaced=not $ null sp, asprecision=prec, asdecimalpoint=mdec, asdigitgroups=mgrps}
|
let s = amountstyle{ascommodityside=L, ascommodityspaced=not $ null sp, asprecision=prec, asdecimalpoint=mdec, asdigitgroups=mgrps}
|
||||||
p <- priceamountp
|
p <- priceamountp
|
||||||
let applysign = if sign=="-" then negate else id
|
let applysign = if sign=="-" then negate else id
|
||||||
@ -426,9 +434,12 @@ leftsymbolamountp = do
|
|||||||
rightsymbolamountp :: Monad m => JournalParser m Amount
|
rightsymbolamountp :: Monad m => JournalParser m Amount
|
||||||
rightsymbolamountp = do
|
rightsymbolamountp = do
|
||||||
m <- lift multiplierp
|
m <- lift multiplierp
|
||||||
(q,prec,mdec,mgrps) <- lift numberp
|
sign <- lift signp
|
||||||
|
rawnum <- lift $ rawnumberp
|
||||||
sp <- lift $ many spacenonewline
|
sp <- lift $ many spacenonewline
|
||||||
c <- lift commoditysymbolp
|
c <- lift commoditysymbolp
|
||||||
|
decimalHint <- getDecimalHint c
|
||||||
|
let (q,prec,mdec,mgrps) = fromRawNumber decimalHint (sign == "-") rawnum
|
||||||
p <- priceamountp
|
p <- priceamountp
|
||||||
let s = amountstyle{ascommodityside=R, ascommodityspaced=not $ null sp, asprecision=prec, asdecimalpoint=mdec, asdigitgroups=mgrps}
|
let s = amountstyle{ascommodityside=R, ascommodityspaced=not $ null sp, asprecision=prec, asdecimalpoint=mdec, asdigitgroups=mgrps}
|
||||||
return $ Amount c q p s m
|
return $ Amount c q p s m
|
||||||
@ -437,7 +448,8 @@ rightsymbolamountp = do
|
|||||||
nosymbolamountp :: Monad m => JournalParser m Amount
|
nosymbolamountp :: Monad m => JournalParser m Amount
|
||||||
nosymbolamountp = do
|
nosymbolamountp = do
|
||||||
m <- lift multiplierp
|
m <- lift multiplierp
|
||||||
(q,prec,mdec,mgrps) <- lift numberp
|
decimalHint <- getDefaultDecimalHint
|
||||||
|
(q,prec,mdec,mgrps) <- lift $ numberp decimalHint
|
||||||
p <- priceamountp
|
p <- priceamountp
|
||||||
-- apply the most recently seen default commodity and style to this commodityless amount
|
-- apply the most recently seen default commodity and style to this commodityless amount
|
||||||
defcs <- getDefaultCommodityAndStyle
|
defcs <- getDefaultCommodityAndStyle
|
||||||
@ -524,25 +536,26 @@ fixedlotpricep =
|
|||||||
-- seen following the decimal point), the decimal point character used if any,
|
-- seen following the decimal point), the decimal point character used if any,
|
||||||
-- and the digit group style if any.
|
-- and the digit group style if any.
|
||||||
--
|
--
|
||||||
numberp :: TextParser m (Quantity, Int, Maybe Char, Maybe DigitGroupStyle)
|
numberp :: Maybe Char -> TextParser m (Quantity, Int, Maybe Char, Maybe DigitGroupStyle)
|
||||||
numberp = do
|
numberp decimalHint = do
|
||||||
-- a number is an optional sign followed by a sequence of digits possibly
|
-- a number is an optional sign followed by a sequence of digits possibly
|
||||||
-- interspersed with periods, commas, or both
|
-- interspersed with periods, commas, or both
|
||||||
-- ptrace "numberp"
|
-- ptrace "numberp"
|
||||||
sign <- signp
|
sign <- signp
|
||||||
raw <- rawnumberp
|
raw <- rawnumberp
|
||||||
dbg8 "numberp parsed" raw `seq` return ()
|
dbg8 "numberp parsed" raw `seq` return ()
|
||||||
return $ dbg8 "numberp quantity,precision,mdecimalpoint,mgrps" (fromRawNumber (sign == "-") raw)
|
return $ dbg8 "numberp quantity,precision,mdecimalpoint,mgrps" (fromRawNumber decimalHint (sign == "-") raw)
|
||||||
<?> "numberp"
|
<?> "numberp"
|
||||||
|
|
||||||
fromRawNumber :: Bool -> (Maybe Char, [String], Maybe (Char, String)) -> (Quantity, Int, Maybe Char, Maybe DigitGroupStyle)
|
fromRawNumber :: Maybe Char -> Bool -> (Maybe Char, [String], Maybe (Char, String)) -> (Quantity, Int, Maybe Char, Maybe DigitGroupStyle)
|
||||||
fromRawNumber negated raw = (quantity, precision, mdecimalpoint, mgrps) where
|
fromRawNumber decimalHint negated raw = (quantity, precision, mdecimalpoint, mgrps) where
|
||||||
-- unpack with a hint if useful
|
-- unpack with a hint if useful
|
||||||
(mseparator, intparts, mdecimalpoint, frac) =
|
(mseparator, intparts, mdecimalpoint, frac) =
|
||||||
case raw of
|
case raw of
|
||||||
-- just a single punctuation between two digits groups, assume it's a decimal point
|
-- just a single punctuation between two digits groups, assume it's a decimal point
|
||||||
(Just s, [firstGroup, lastGroup], Nothing)
|
(Just s, [firstGroup, lastGroup], Nothing)
|
||||||
-> (Nothing, [firstGroup], Just s, lastGroup)
|
-- if have a decimalHint restrict this assumpion only to a matching separator
|
||||||
|
| maybe True (s ==) decimalHint -> (Nothing, [firstGroup], Just s, lastGroup)
|
||||||
|
|
||||||
(firstSep, digitGroups, Nothing) -> (firstSep, digitGroups, Nothing, [])
|
(firstSep, digitGroups, Nothing) -> (firstSep, digitGroups, Nothing, [])
|
||||||
(firstSep, digitGroups, Just (d, frac)) -> (firstSep, digitGroups, Just d, frac)
|
(firstSep, digitGroups, Just (d, frac)) -> (firstSep, digitGroups, Just d, frac)
|
||||||
|
|||||||
@ -141,7 +141,7 @@ timedotdurationp = try timedotnumericp <|> timedotdotsp
|
|||||||
-- @
|
-- @
|
||||||
timedotnumericp :: JournalParser m Quantity
|
timedotnumericp :: JournalParser m Quantity
|
||||||
timedotnumericp = do
|
timedotnumericp = do
|
||||||
(q, _, _, _) <- lift numberp
|
(q, _, _, _) <- lift $ numberp Nothing
|
||||||
msymbol <- optional $ choice $ map (string . fst) timeUnits
|
msymbol <- optional $ choice $ map (string . fst) timeUnits
|
||||||
lift (many spacenonewline)
|
lift (many spacenonewline)
|
||||||
let q' =
|
let q' =
|
||||||
|
|||||||
@ -43,6 +43,22 @@ hledger bal -f -
|
|||||||
>>>
|
>>>
|
||||||
>>>=1
|
>>>=1
|
||||||
|
|
||||||
|
# Default commodity
|
||||||
|
hledger bal -f -
|
||||||
|
<<<
|
||||||
|
D 1,000.00 EUR
|
||||||
|
|
||||||
|
2017/1/1
|
||||||
|
a 1,000
|
||||||
|
b -1,000.00
|
||||||
|
>>>
|
||||||
|
1,000.00 EUR a
|
||||||
|
-1,000.00 EUR b
|
||||||
|
--------------------
|
||||||
|
0
|
||||||
|
>>>2
|
||||||
|
>>>=0
|
||||||
|
|
||||||
# Omitted decimals
|
# Omitted decimals
|
||||||
hledger bal -f -
|
hledger bal -f -
|
||||||
<<<
|
<<<
|
||||||
@ -52,6 +68,38 @@ hledger bal -f -
|
|||||||
>>>
|
>>>
|
||||||
>>>=1
|
>>>=1
|
||||||
|
|
||||||
|
# Omitted decimals with commodity hint
|
||||||
|
hledger bal -f -
|
||||||
|
<<<
|
||||||
|
commodity 1,000.00 EUR
|
||||||
|
|
||||||
|
2017/1/1
|
||||||
|
a 1,000 EUR
|
||||||
|
b -1,000.00 EUR
|
||||||
|
>>>
|
||||||
|
1,000.00 EUR a
|
||||||
|
-1,000.00 EUR b
|
||||||
|
--------------------
|
||||||
|
0
|
||||||
|
>>>2
|
||||||
|
>>>=0
|
||||||
|
|
||||||
|
# Omitted decimals with commodity hint and symbol on left
|
||||||
|
hledger bal -f -
|
||||||
|
<<<
|
||||||
|
commodity €1,000.00
|
||||||
|
|
||||||
|
2017/1/1
|
||||||
|
a €1,000
|
||||||
|
b €-1,000.00
|
||||||
|
>>>
|
||||||
|
€1,000.00 a
|
||||||
|
€-1,000.00 b
|
||||||
|
--------------------
|
||||||
|
0
|
||||||
|
>>>2
|
||||||
|
>>>=0
|
||||||
|
|
||||||
# Big prices
|
# Big prices
|
||||||
hledger bal -f - --no-total
|
hledger bal -f - --no-total
|
||||||
<<<
|
<<<
|
||||||
@ -61,6 +109,20 @@ hledger bal -f - --no-total
|
|||||||
>>>
|
>>>
|
||||||
>>>=1
|
>>>=1
|
||||||
|
|
||||||
|
# Big prices with commodity hint
|
||||||
|
hledger bal -f - --no-total
|
||||||
|
<<<
|
||||||
|
commodity ₴1,000.00
|
||||||
|
|
||||||
|
2017/1/1
|
||||||
|
a -1 BTC @ ₴24,840
|
||||||
|
b ₴24,840.00
|
||||||
|
>>>
|
||||||
|
-1 BTC a
|
||||||
|
₴24,840.00 b
|
||||||
|
>>>2
|
||||||
|
>>>=0
|
||||||
|
|
||||||
# adjacent punctuation chars
|
# adjacent punctuation chars
|
||||||
hledger bal -f -
|
hledger bal -f -
|
||||||
<<<
|
<<<
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user