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