hledger-lib 1.3 → 1.3.1
raw patch · 26 files changed
+425/−310 lines, 26 filesdep ~megaparsecdep ~timePVP: major bump suggested
API removals or changes: PVP suggests a major version bump
Dependency ranges changed: megaparsec, time
API changes (from Hackage documentation)
- Hledger.Utils.Parse: type JournalStateParser m a = StateT Journal (ParsecT Dec Text m) a
+ Hledger.Utils.Parse: type SimpleStringParser a = Parsec MPErr String a
+ Hledger.Utils.Parse: type SimpleTextParser = Parsec MPErr Text
+ Text.Megaparsec.Compat: mpMkParseError :: FilePath -> String -> ParseError Char String
+ Text.Megaparsec.Compat: mpMkPos :: Int -> Pos
+ Text.Megaparsec.Compat: mpUnPos :: Pos -> Int
+ Text.Megaparsec.Compat: mptext :: MonadParsec e Text m => Tokens Text -> m (Tokens Text)
+ Text.Megaparsec.Compat: type MPErr = Void
- Hledger.Data.Dates: fixSmartDateStrEither :: Day -> Text -> Either (ParseError Char Dec) String
+ Hledger.Data.Dates: fixSmartDateStrEither :: Day -> Text -> Either (ParseError Char MPErr) String
- Hledger.Data.Dates: fixSmartDateStrEither' :: Day -> Text -> Either (ParseError Char Dec) Day
+ Hledger.Data.Dates: fixSmartDateStrEither' :: Day -> Text -> Either (ParseError Char MPErr) Day
- Hledger.Data.Dates: parsePeriodExpr :: Day -> Text -> Either (ParseError Char Dec) (Interval, DateSpan)
+ Hledger.Data.Dates: parsePeriodExpr :: Day -> Text -> Either (ParseError Char MPErr) (Interval, DateSpan)
- Hledger.Data.Dates: smartdate :: Parser SmartDate
+ Hledger.Data.Dates: smartdate :: SimpleTextParser SmartDate
- Hledger.Read.Common: amountp :: Monad m => JournalStateParser m Amount
+ Hledger.Read.Common: amountp :: Monad m => JournalParser m Amount
- Hledger.Read.Common: commentStartingWithp :: [Char] -> JournalStateParser m Text
+ Hledger.Read.Common: commentStartingWithp :: [Char] -> JournalParser m Text
- Hledger.Read.Common: commentp :: JournalStateParser m Text
+ Hledger.Read.Common: commentp :: JournalParser m Text
- Hledger.Read.Common: datep :: JournalStateParser m Day
+ Hledger.Read.Common: datep :: JournalParser m Day
- Hledger.Read.Common: datetimep :: JournalStateParser m LocalTime
+ Hledger.Read.Common: datetimep :: JournalParser m LocalTime
- Hledger.Read.Common: descriptionp :: JournalStateParser m String
+ Hledger.Read.Common: descriptionp :: JournalParser m String
- Hledger.Read.Common: emptyorcommentlinep :: JournalStateParser m ()
+ Hledger.Read.Common: emptyorcommentlinep :: JournalParser m ()
- Hledger.Read.Common: fixedlotpricep :: Monad m => JournalStateParser m (Maybe Amount)
+ Hledger.Read.Common: fixedlotpricep :: Monad m => JournalParser m (Maybe Amount)
- Hledger.Read.Common: followingcommentp :: JournalStateParser m Text
+ Hledger.Read.Common: followingcommentp :: JournalParser m Text
- Hledger.Read.Common: getDefaultCommodityAndStyle :: JournalStateParser m (Maybe (CommoditySymbol, AmountStyle))
+ Hledger.Read.Common: getDefaultCommodityAndStyle :: JournalParser m (Maybe (CommoditySymbol, AmountStyle))
- Hledger.Read.Common: getParentAccount :: JournalStateParser m AccountName
+ Hledger.Read.Common: getParentAccount :: JournalParser m AccountName
- Hledger.Read.Common: getYear :: JournalStateParser m (Maybe Year)
+ Hledger.Read.Common: getYear :: JournalParser m (Maybe Year)
- Hledger.Read.Common: leftsymbolamountp :: Monad m => JournalStateParser m Amount
+ Hledger.Read.Common: leftsymbolamountp :: Monad m => JournalParser m Amount
- Hledger.Read.Common: modifiedaccountnamep :: JournalStateParser m AccountName
+ Hledger.Read.Common: modifiedaccountnamep :: JournalParser m AccountName
- Hledger.Read.Common: multilinecommentp :: JournalStateParser m ()
+ Hledger.Read.Common: multilinecommentp :: JournalParser m ()
- Hledger.Read.Common: nontagp :: Parser String
+ Hledger.Read.Common: nontagp :: SimpleTextParser String
- Hledger.Read.Common: nosymbolamountp :: Monad m => JournalStateParser m Amount
+ Hledger.Read.Common: nosymbolamountp :: Monad m => JournalParser m Amount
- Hledger.Read.Common: parseAndFinaliseJournal' :: JournalParser ParsedJournal -> Bool -> FilePath -> Text -> ExceptT String IO Journal
+ Hledger.Read.Common: parseAndFinaliseJournal' :: JournalParser Identity ParsedJournal -> Bool -> FilePath -> Text -> ExceptT String IO Journal
- Hledger.Read.Common: partialbalanceassertionp :: Monad m => JournalStateParser m (Maybe Amount)
+ Hledger.Read.Common: partialbalanceassertionp :: Monad m => JournalParser m (Maybe Amount)
- Hledger.Read.Common: popParentAccount :: JournalStateParser m ()
+ Hledger.Read.Common: popParentAccount :: JournalParser m ()
- Hledger.Read.Common: priceamountp :: Monad m => JournalStateParser m Price
+ Hledger.Read.Common: priceamountp :: Monad m => JournalParser m Price
- Hledger.Read.Common: pushAccount :: AccountName -> JournalStateParser m ()
+ Hledger.Read.Common: pushAccount :: AccountName -> JournalParser m ()
- Hledger.Read.Common: pushParentAccount :: AccountName -> JournalStateParser m ()
+ Hledger.Read.Common: pushParentAccount :: AccountName -> JournalParser m ()
- Hledger.Read.Common: rightsymbolamountp :: Monad m => JournalStateParser m Amount
+ Hledger.Read.Common: rightsymbolamountp :: Monad m => JournalParser m Amount
- Hledger.Read.Common: rjp :: Monad m => TextParser m a -> Text -> m (Either (ParseError Char Dec) a)
+ Hledger.Read.Common: rjp :: Monad m => TextParser m a -> Text -> m (Either (ParseError Char MPErr) a)
- Hledger.Read.Common: rtp :: TextParser Identity a -> Text -> Either (ParseError Char Dec) a
+ Hledger.Read.Common: rtp :: TextParser Identity a -> Text -> Either (ParseError Char MPErr) a
- Hledger.Read.Common: runJournalParser :: Monad m => TextParser m a -> Text -> m (Either (ParseError Char Dec) a)
+ Hledger.Read.Common: runJournalParser :: Monad m => TextParser m a -> Text -> m (Either (ParseError Char MPErr) a)
- Hledger.Read.Common: runTextParser :: TextParser Identity a -> Text -> Either (ParseError Char Dec) a
+ Hledger.Read.Common: runTextParser :: TextParser Identity a -> Text -> Either (ParseError Char MPErr) a
- Hledger.Read.Common: secondarydatep :: Day -> JournalStateParser m Day
+ Hledger.Read.Common: secondarydatep :: Day -> JournalParser m Day
- Hledger.Read.Common: semicoloncommentp :: JournalStateParser m Text
+ Hledger.Read.Common: semicoloncommentp :: JournalParser m Text
- Hledger.Read.Common: setDefaultCommodityAndStyle :: (CommoditySymbol, AmountStyle) -> JournalStateParser m ()
+ Hledger.Read.Common: setDefaultCommodityAndStyle :: (CommoditySymbol, AmountStyle) -> JournalParser m ()
- Hledger.Read.Common: setYear :: Year -> JournalStateParser m ()
+ Hledger.Read.Common: setYear :: Year -> JournalParser m ()
- Hledger.Read.Common: spaceandamountormissingp :: Monad m => JournalStateParser m MixedAmount
+ Hledger.Read.Common: spaceandamountormissingp :: Monad m => JournalParser m MixedAmount
- Hledger.Read.Common: tagnamep :: Parser Text
+ Hledger.Read.Common: tagnamep :: SimpleTextParser Text
- Hledger.Read.Common: tagp :: Parser Tag
+ Hledger.Read.Common: tagp :: SimpleTextParser Tag
- Hledger.Read.Common: tagsp :: Parser [Tag]
+ Hledger.Read.Common: tagsp :: SimpleTextParser [Tag]
- Hledger.Read.JournalReader: datep :: JournalStateParser m Day
+ Hledger.Read.JournalReader: datep :: JournalParser m Day
- Hledger.Read.JournalReader: datetimep :: JournalStateParser m LocalTime
+ Hledger.Read.JournalReader: datetimep :: JournalParser m LocalTime
- Hledger.Read.JournalReader: defaultyeardirectivep :: JournalStateParser m ()
+ Hledger.Read.JournalReader: defaultyeardirectivep :: JournalParser m ()
- Hledger.Read.JournalReader: emptyorcommentlinep :: JournalStateParser m ()
+ Hledger.Read.JournalReader: emptyorcommentlinep :: JournalParser m ()
- Hledger.Read.JournalReader: followingcommentp :: JournalStateParser m Text
+ Hledger.Read.JournalReader: followingcommentp :: JournalParser m Text
- Hledger.Read.JournalReader: getParentAccount :: JournalStateParser m AccountName
+ Hledger.Read.JournalReader: getParentAccount :: JournalParser m AccountName
- Hledger.Read.JournalReader: marketpricedirectivep :: Monad m => JournalStateParser m MarketPrice
+ Hledger.Read.JournalReader: marketpricedirectivep :: Monad m => JournalParser m MarketPrice
- Hledger.Read.JournalReader: modifiedaccountnamep :: JournalStateParser m AccountName
+ Hledger.Read.JournalReader: modifiedaccountnamep :: JournalParser m AccountName
- Hledger.Read.JournalReader: rjp :: Monad m => TextParser m a -> Text -> m (Either (ParseError Char Dec) a)
+ Hledger.Read.JournalReader: rjp :: Monad m => TextParser m a -> Text -> m (Either (ParseError Char MPErr) a)
- Hledger.Read.JournalReader: runJournalParser :: Monad m => TextParser m a -> Text -> m (Either (ParseError Char Dec) a)
+ Hledger.Read.JournalReader: runJournalParser :: Monad m => TextParser m a -> Text -> m (Either (ParseError Char MPErr) a)
- Hledger.Read.TimedotReader: timedotfilep :: JournalStateParser m ParsedJournal
+ Hledger.Read.TimedotReader: timedotfilep :: JournalParser m ParsedJournal
- Hledger.Utils.Parse: choiceInState :: [StateT s (ParsecT Dec Text m) a] -> StateT s (ParsecT Dec Text m) a
+ Hledger.Utils.Parse: choiceInState :: [StateT s (ParsecT MPErr Text m) a] -> StateT s (ParsecT MPErr Text m) a
- Hledger.Utils.Parse: parseWithState :: Monad m => st -> StateT st (ParsecT Dec Text m) a -> Text -> m (Either (ParseError Char Dec) a)
+ Hledger.Utils.Parse: parseWithState :: Monad m => st -> StateT st (ParsecT MPErr Text m) a -> Text -> m (Either (ParseError Char MPErr) a)
- Hledger.Utils.Parse: parseWithState' :: (Stream s, ErrorComponent e) => st -> StateT st (ParsecT e s Identity) a -> s -> (Either (ParseError (Token s) e) a)
+ Hledger.Utils.Parse: parseWithState' :: (Stream s) => st -> StateT st (ParsecT e s Identity) a -> s -> (Either (ParseError (Token s) e) a)
- Hledger.Utils.Parse: spacenonewline :: (Stream s, Char ~ Token s) => ParsecT Dec s m Char
+ Hledger.Utils.Parse: spacenonewline :: (Stream s, Char ~ Token s) => ParsecT MPErr s m Char
- Hledger.Utils.Parse: type ErroringJournalParser m a = StateT Journal (ParsecT Dec Text (ExceptT String m)) a
+ Hledger.Utils.Parse: type ErroringJournalParser m a = StateT Journal (ParsecT MPErr Text (ExceptT String m)) a
- Hledger.Utils.Parse: type JournalParser a = StateT Journal (ParsecT Dec Text Identity) a
+ Hledger.Utils.Parse: type JournalParser m a = StateT Journal (ParsecT MPErr Text m) a
- Hledger.Utils.Parse: type TextParser m a = ParsecT Dec Text m a
+ Hledger.Utils.Parse: type TextParser m a = ParsecT MPErr Text m a
Files
- CHANGES +23/−7
- Hledger/Data/Dates.hs +67/−58
- Hledger/Data/StringFormat.hs +7/−7
- Hledger/Query.hs +12/−13
- Hledger/Read/Common.hs +38/−39
- Hledger/Read/CsvReader.hs +24/−24
- Hledger/Read/JournalReader.hs +16/−16
- Hledger/Read/TimeclockReader.hs +2/−2
- Hledger/Read/TimedotReader.hs +8/−8
- Hledger/Reports/MultiBalanceReports.hs +1/−1
- Hledger/Utils/Parse.hs +26/−17
- Hledger/Utils/String.hs +1/−1
- Text/Megaparsec/Compat.hs +73/−0
- doc/hledger_csv.5 +1/−1
- doc/hledger_csv.5.info +18/−18
- doc/hledger_csv.5.txt +1/−1
- doc/hledger_journal.5 +1/−1
- doc/hledger_journal.5.info +80/−80
- doc/hledger_journal.5.txt +1/−1
- doc/hledger_timeclock.5 +1/−1
- doc/hledger_timeclock.5.info +2/−2
- doc/hledger_timeclock.5.txt +1/−1
- doc/hledger_timedot.5 +1/−1
- doc/hledger_timedot.5.info +4/−4
- doc/hledger_timedot.5.txt +1/−1
- hledger-lib.cabal +15/−5
CHANGES view
@@ -1,23 +1,39 @@ API-ish changes in the hledger-lib package. See also the hledger and project change logs (for user-visible changes). +# 1.3.1 (2017/8/25) -# 1.3 (2017/6/30)+* Fix a bug with -H showing nothing for empty periods (Nicholas Niro)+This patch fixes a bug that happened when using the -H option on+a period without any transaction. Previously, the behavior was no+output at all even though it should have shown the previous ending balances+of past transactions. (This is similar to previously using -H with -E,+but with the extra advantage of not showing empty accounts) -Deps: allow megaparsec 5.3.+* allow megaparsec 6 (#594) -CSV conversion: assigning to the "balance" field name creates balance-assertions (#537, Dmitry Astapov).-Doubled minus signs are handled more robustly (fixes #524, Nicolas Wavrant, Simon Michael)+* allow megaparsec-6.1 (Hans-Peter Deifel) -The "uncleared" transaction/posting status, and associated UI flags+* fix test suite with Cabal 2 (#596)+++# 1.3 (2017/6/30)++journal: The "uncleared" transaction/posting status, and associated UI flags and keys, have been renamed to "unmarked" to remove ambiguity and confusion. This means that we have dropped the `--uncleared` flag, and our `-U` flag now matches only unmarked things and not pending ones. See the issue and linked mail list discussion for more background. (#564) -Multiple status: query terms are now OR'd together. (#564)+csv: assigning to the "balance" field name creates balance+assertions (#537, Dmitry Astapov).++csv: Doubled minus signs are handled more robustly (fixes #524, Nicolas Wavrant, Simon Michael)++Multiple "status:" query terms are now OR'd together. (#564)++deps: allow megaparsec 5.3. # 1.2 (2017/3/31)
Hledger/Data/Dates.hs view
@@ -3,6 +3,7 @@ {-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE TypeFamilies #-} {-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE ScopedTypeVariables #-} {-| Date parsing and utilities for hledger.@@ -86,8 +87,7 @@ import Data.Time.Clock import Data.Time.LocalTime import Safe (headMay, lastMay, readMay)-import Text.Megaparsec-import Text.Megaparsec.Text+import Text.Megaparsec.Compat import Text.Printf import Hledger.Data.Types@@ -256,7 +256,7 @@ -- | Parse a period expression to an Interval and overall DateSpan using -- the provided reference date, or return a parse error.-parsePeriodExpr :: Day -> Text -> Either (ParseError Char Dec) (Interval, DateSpan)+parsePeriodExpr :: Day -> Text -> Either (ParseError Char MPErr) (Interval, DateSpan) parsePeriodExpr refdate = parsewith (periodexpr refdate <* eof) maybePeriod :: Day -> Text -> Maybe (Interval,DateSpan)@@ -316,13 +316,13 @@ fixSmartDateStr d s = either (\e->error' $ printf "could not parse date %s %s" (show s) (show e)) id- $ (fixSmartDateStrEither d s :: Either (ParseError Char Dec) String)+ $ (fixSmartDateStrEither d s :: Either (ParseError Char MPErr) String) -- | A safe version of fixSmartDateStr.-fixSmartDateStrEither :: Day -> Text -> Either (ParseError Char Dec) String+fixSmartDateStrEither :: Day -> Text -> Either (ParseError Char MPErr) String fixSmartDateStrEither d = either Left (Right . showDate) . fixSmartDateStrEither' d -fixSmartDateStrEither' :: Day -> Text -> Either (ParseError Char Dec) Day+fixSmartDateStrEither' :: Day -> Text -> Either (ParseError Char MPErr) Day fixSmartDateStrEither' d s = case parsewith smartdateonly (T.toLower s) of Right sd -> Right $ fixSmartDate d sd Left e -> Left e@@ -550,14 +550,14 @@ Returns a SmartDate, to be converted to a full date later (see fixSmartDate). Assumes any text in the parse stream has been lowercased. -}-smartdate :: Parser SmartDate+smartdate :: SimpleTextParser SmartDate smartdate = do -- XXX maybe obscures date errors ? see ledgerdate (y,m,d) <- choice' [yyyymmdd, ymd, ym, md, y, d, month, mon, today, yesterday, tomorrow, lastthisnextthing] return (y,m,d) -- | Like smartdate, but there must be nothing other than whitespace after the date.-smartdateonly :: Parser SmartDate+smartdateonly :: SimpleTextParser SmartDate smartdateonly = do d <- smartdate many spacenonewline@@ -579,7 +579,7 @@ failIfInvalidMonth s = unless (validMonth s) $ fail $ "bad month number: " ++ s failIfInvalidDay s = unless (validDay s) $ fail $ "bad day number: " ++ s -yyyymmdd :: Parser SmartDate+yyyymmdd :: SimpleTextParser SmartDate yyyymmdd = do y <- count 4 digitChar m <- count 2 digitChar@@ -588,7 +588,7 @@ failIfInvalidDay d return (y,m,d) -ymd :: Parser SmartDate+ymd :: SimpleTextParser SmartDate ymd = do y <- some digitChar failIfInvalidYear y@@ -600,7 +600,7 @@ failIfInvalidDay d return $ (y,m,d) -ym :: Parser SmartDate+ym :: SimpleTextParser SmartDate ym = do y <- some digitChar failIfInvalidYear y@@ -609,19 +609,19 @@ failIfInvalidMonth m return (y,m,"") -y :: Parser SmartDate+y :: SimpleTextParser SmartDate y = do y <- some digitChar failIfInvalidYear y return (y,"","") -d :: Parser SmartDate+d :: SimpleTextParser SmartDate d = do d <- some digitChar failIfInvalidDay d return ("","",d) -md :: Parser SmartDate+md :: SimpleTextParser SmartDate md = do m <- some digitChar failIfInvalidMonth m@@ -636,48 +636,54 @@ -- weekdays = ["monday","tuesday","wednesday","thursday","friday","saturday","sunday"] -- weekdayabbrevs = ["mon","tue","wed","thu","fri","sat","sun"] -monthIndex s = maybe 0 (+1) $ lowercase s `elemIndex` months-monIndex s = maybe 0 (+1) $ lowercase s `elemIndex` monthabbrevs+#if MIN_VERSION_megaparsec(6,0,0)+lc = T.toLower+#else+lc = lowercase+#endif -month :: Parser SmartDate+monthIndex t = maybe 0 (+1) $ lc t `elemIndex` months+monIndex t = maybe 0 (+1) $ lc t `elemIndex` monthabbrevs++month :: SimpleTextParser SmartDate month = do m <- choice $ map (try . string) months let i = monthIndex m return ("",show i,"") -mon :: Parser SmartDate+mon :: SimpleTextParser SmartDate mon = do m <- choice $ map (try . string) monthabbrevs let i = monIndex m return ("",show i,"") -today,yesterday,tomorrow :: Parser SmartDate+today,yesterday,tomorrow :: SimpleTextParser SmartDate today = string "today" >> return ("","","today") yesterday = string "yesterday" >> return ("","","yesterday") tomorrow = string "tomorrow" >> return ("","","tomorrow") -lastthisnextthing :: Parser SmartDate+lastthisnextthing :: SimpleTextParser SmartDate lastthisnextthing = do- r <- choice [- string "last"- ,string "this"- ,string "next"+ r <- choice $ map mptext [+ "last"+ ,"this"+ ,"next" ] many spacenonewline -- make the space optional for easier scripting- p <- choice [- string "day"- ,string "week"- ,string "month"- ,string "quarter"- ,string "year"+ p <- choice $ map mptext [+ "day"+ ,"week"+ ,"month"+ ,"quarter"+ ,"year" ] -- XXX support these in fixSmartDate -- ++ (map string $ months ++ monthabbrevs ++ weekdays ++ weekdayabbrevs) - return ("",r,p)+ return ("", T.unpack r, T.unpack p) -- |--- >>> let p = parsewith (periodexpr (parsedate "2008/11/26")) :: T.Text -> Either (ParseError Char Dec) (Interval, DateSpan)+-- >>> let p = parsewith (periodexpr (parsedate "2008/11/26")) :: T.Text -> Either (ParseError Char MPErr) (Interval, DateSpan) -- >>> p "from aug to oct" -- Right (NoInterval,DateSpan 2008/08/01-2008/09/30) -- >>> p "aug to oct"@@ -688,7 +694,7 @@ -- Right (Days 1,DateSpan 2008/08/01-) -- >>> p "every week to 2009" -- Right (Weeks 1,DateSpan -2008/12/31)-periodexpr :: Day -> Parser (Interval, DateSpan)+periodexpr :: Day -> SimpleTextParser (Interval, DateSpan) periodexpr rdate = choice $ map try [ intervalanddateperiodexpr rdate, intervalperiodexpr,@@ -696,7 +702,7 @@ (return (NoInterval,DateSpan Nothing Nothing)) ] -intervalanddateperiodexpr :: Day -> Parser (Interval, DateSpan)+intervalanddateperiodexpr :: Day -> SimpleTextParser (Interval, DateSpan) intervalanddateperiodexpr rdate = do many spacenonewline i <- reportinginterval@@ -704,20 +710,20 @@ s <- periodexprdatespan rdate return (i,s) -intervalperiodexpr :: Parser (Interval, DateSpan)+intervalperiodexpr :: SimpleTextParser (Interval, DateSpan) intervalperiodexpr = do many spacenonewline i <- reportinginterval return (i, DateSpan Nothing Nothing) -dateperiodexpr :: Day -> Parser (Interval, DateSpan)+dateperiodexpr :: Day -> SimpleTextParser (Interval, DateSpan) dateperiodexpr rdate = do many spacenonewline s <- periodexprdatespan rdate return (NoInterval, s) -- Parse a reporting interval.-reportinginterval :: Parser Interval+reportinginterval :: SimpleTextParser Interval reportinginterval = choice' [ tryinterval "day" "daily" Days, tryinterval "week" "weekly" Weeks,@@ -757,25 +763,28 @@ thsuffix = choice' $ map string ["st","nd","rd","th"] -- Parse any of several variants of a basic interval, eg "daily", "every day", "every N days".- tryinterval :: String -> String -> (Int -> Interval) -> Parser Interval+ tryinterval :: String -> String -> (Int -> Interval) -> SimpleTextParser Interval tryinterval singular compact intcons =- choice' [- do string compact- return $ intcons 1,- do string "every"- many spacenonewline- string singular- return $ intcons 1,- do string "every"- many spacenonewline- n <- fmap read $ some digitChar- many spacenonewline- string plural- return $ intcons n- ]- where plural = singular ++ "s"+ choice' [+ do mptext compact'+ return $ intcons 1,+ do mptext "every"+ many spacenonewline+ mptext singular'+ return $ intcons 1,+ do mptext "every"+ many spacenonewline+ n <- fmap read $ some digitChar+ many spacenonewline+ mptext plural'+ return $ intcons n+ ]+ where+ compact' = T.pack compact+ singular' = T.pack singular+ plural' = T.pack $ singular ++ "s" -periodexprdatespan :: Day -> Parser DateSpan+periodexprdatespan :: Day -> SimpleTextParser DateSpan periodexprdatespan rdate = choice $ map try [ doubledatespan rdate, fromdatespan rdate,@@ -783,7 +792,7 @@ justdatespan rdate ] -doubledatespan :: Day -> Parser DateSpan+doubledatespan :: Day -> SimpleTextParser DateSpan doubledatespan rdate = do optional (string "from" >> many spacenonewline) b <- smartdate@@ -792,7 +801,7 @@ e <- smartdate return $ DateSpan (Just $ fixSmartDate rdate b) (Just $ fixSmartDate rdate e) -fromdatespan :: Day -> Parser DateSpan+fromdatespan :: Day -> SimpleTextParser DateSpan fromdatespan rdate = do b <- choice [ do@@ -806,13 +815,13 @@ ] return $ DateSpan (Just $ fixSmartDate rdate b) Nothing -todatespan :: Day -> Parser DateSpan+todatespan :: Day -> SimpleTextParser DateSpan todatespan rdate = do choice [string "to", string "-"] >> many spacenonewline e <- smartdate return $ DateSpan Nothing (Just $ fixSmartDate rdate e) -justdatespan :: Day -> Parser DateSpan+justdatespan :: Day -> SimpleTextParser DateSpan justdatespan rdate = do optional (string "in" >> many spacenonewline) d <- smartdate
Hledger/Data/StringFormat.hs view
@@ -19,9 +19,9 @@ import Data.Char (isPrint) import Data.Maybe import Test.HUnit-import Text.Megaparsec-import Text.Megaparsec.String+import Text.Megaparsec.Compat +import Hledger.Utils.Parse import Hledger.Utils.String (formatString) -- | A format specification/template to use when rendering a report line item as text.@@ -86,7 +86,7 @@ defaultStringFormatStyle = BottomAligned -stringformatp :: Parser StringFormat+stringformatp :: SimpleStringParser StringFormat stringformatp = do alignspec <- optional (try $ char '%' >> oneOf "^_,") let constructor =@@ -97,10 +97,10 @@ _ -> defaultStringFormatStyle constructor <$> many componentp -componentp :: Parser StringFormatComponent+componentp :: SimpleStringParser StringFormatComponent componentp = formatliteralp <|> formatfieldp -formatliteralp :: Parser StringFormatComponent+formatliteralp :: SimpleStringParser StringFormatComponent formatliteralp = do s <- some c return $ FormatLiteral s@@ -109,7 +109,7 @@ c = (satisfy isPrintableButNotPercentage <?> "printable character") <|> try (string "%%" >> return '%') -formatfieldp :: Parser StringFormatComponent+formatfieldp :: SimpleStringParser StringFormatComponent formatfieldp = do char '%' leftJustified <- optional (char '-')@@ -124,7 +124,7 @@ Just text -> Just m where ((m,_):_) = readDec text _ -> Nothing -fieldp :: Parser ReportItemField+fieldp :: SimpleStringParser ReportItemField fieldp = do try (string "account" >> return AccountField) <|> try (string "depth_spacer" >> return DepthSpacerField)
Hledger/Query.hs view
@@ -1,7 +1,7 @@ {-| A general query system for matching things (accounts, postings,-transactions..) by various criteria, and a parser for query expressions.+transactions..) by various criteria, and a SimpleTextParser for query expressions. -} @@ -55,8 +55,7 @@ import Data.Time.Calendar import Safe (readDef, headDef) import Test.HUnit-import Text.Megaparsec-import Text.Megaparsec.Text+import Text.Megaparsec.Compat import Hledger.Utils hiding (words') import Hledger.Data.Types@@ -185,23 +184,23 @@ words'' :: [T.Text] -> T.Text -> [T.Text] words'' prefixes = fromparse . parsewith maybeprefixedquotedphrases -- XXX where- maybeprefixedquotedphrases :: Parser [T.Text]+ maybeprefixedquotedphrases :: SimpleTextParser [T.Text] maybeprefixedquotedphrases = choice' [prefixedQuotedPattern, singleQuotedPattern, doubleQuotedPattern, pattern] `sepBy` some spacenonewline- prefixedQuotedPattern :: Parser T.Text+ prefixedQuotedPattern :: SimpleTextParser T.Text prefixedQuotedPattern = do- not' <- fromMaybe "" `fmap` (optional $ string "not:")- let allowednexts | null not' = prefixes- | otherwise = prefixes ++ [""]- next <- fmap T.pack $ choice' $ map (string . T.unpack) allowednexts+ not' <- fromMaybe "" `fmap` (optional $ mptext "not:")+ let allowednexts | T.null not' = prefixes+ | otherwise = prefixes ++ [""]+ next <- choice' $ map mptext allowednexts let prefix :: T.Text- prefix = T.pack not' <> next+ prefix = not' <> next p <- singleQuotedPattern <|> doubleQuotedPattern return $ prefix <> stripquotes p- singleQuotedPattern :: Parser T.Text+ singleQuotedPattern :: SimpleTextParser T.Text singleQuotedPattern = between (char '\'') (char '\'') (many $ noneOf ("'" :: [Char])) >>= return . stripquotes . T.pack- doubleQuotedPattern :: Parser T.Text+ doubleQuotedPattern :: SimpleTextParser T.Text doubleQuotedPattern = between (char '"') (char '"') (many $ noneOf ("\"" :: [Char])) >>= return . stripquotes . T.pack- pattern :: Parser T.Text+ pattern :: SimpleTextParser T.Text pattern = fmap T.pack $ many (noneOf (" \n\r" :: [Char])) tests_words'' = [
Hledger/Read/Common.hs view
@@ -36,8 +36,7 @@ import Data.Time.LocalTime import Safe import System.Time (getClockTime)-import Text.Megaparsec hiding (parse,State)-import Text.Megaparsec.Text+import Text.Megaparsec.Compat import Hledger.Data import Hledger.Utils@@ -47,12 +46,12 @@ --- * parsing utils -- | Run a string parser with no state in the identity monad.-runTextParser, rtp :: TextParser Identity a -> Text -> Either (ParseError Char Dec) a+runTextParser, rtp :: TextParser Identity a -> Text -> Either (ParseError Char MPErr) a runTextParser p t = runParser p "" t rtp = runTextParser -- | Run a journal parser with a null journal-parsing state.-runJournalParser, rjp :: Monad m => TextParser m a -> Text -> m (Either (ParseError Char Dec) a)+runJournalParser, rjp :: Monad m => TextParser m a -> Text -> m (Either (ParseError Char MPErr) a) runJournalParser p t = runParserT p "" t rjp = runJournalParser @@ -89,7 +88,7 @@ Left e -> throwError e Left e -> throwError $ parseErrorPretty e -parseAndFinaliseJournal' :: JournalParser ParsedJournal -> Bool -> FilePath -> Text -> ExceptT String IO Journal+parseAndFinaliseJournal' :: JournalParser Identity ParsedJournal -> Bool -> FilePath -> Text -> ExceptT String IO Journal parseAndFinaliseJournal' parser assrt f txt = do t <- liftIO getClockTime y <- liftIO getCurrentYear@@ -100,32 +99,32 @@ Left e -> throwError e Left e -> throwError $ parseErrorPretty e -setYear :: Year -> JournalStateParser m ()+setYear :: Year -> JournalParser m () setYear y = modify' (\j -> j{jparsedefaultyear=Just y}) -getYear :: JournalStateParser m (Maybe Year)+getYear :: JournalParser m (Maybe Year) getYear = fmap jparsedefaultyear get -setDefaultCommodityAndStyle :: (CommoditySymbol,AmountStyle) -> JournalStateParser m ()+setDefaultCommodityAndStyle :: (CommoditySymbol,AmountStyle) -> JournalParser m () setDefaultCommodityAndStyle cs = modify' (\j -> j{jparsedefaultcommodity=Just cs}) -getDefaultCommodityAndStyle :: JournalStateParser m (Maybe (CommoditySymbol,AmountStyle))+getDefaultCommodityAndStyle :: JournalParser m (Maybe (CommoditySymbol,AmountStyle)) getDefaultCommodityAndStyle = jparsedefaultcommodity `fmap` get -pushAccount :: AccountName -> JournalStateParser m ()+pushAccount :: AccountName -> JournalParser m () pushAccount acct = modify' (\j -> j{jaccounts = acct : jaccounts j}) -pushParentAccount :: AccountName -> JournalStateParser m ()+pushParentAccount :: AccountName -> JournalParser m () pushParentAccount acct = modify' (\j -> j{jparseparentaccounts = acct : jparseparentaccounts j}) -popParentAccount :: JournalStateParser m ()+popParentAccount :: JournalParser m () popParentAccount = do j <- get case jparseparentaccounts j of [] -> unexpected (Tokens ('E' :| "nd of apply account block with no beginning")) (_:rest) -> put j{jparseparentaccounts=rest} -getParentAccount :: JournalStateParser m AccountName+getParentAccount :: JournalParser m AccountName getParentAccount = fmap (concatAccountNames . reverse . jparseparentaccounts) get addAccountAlias :: MonadState Journal m => AccountAlias -> m ()@@ -181,7 +180,7 @@ codep :: TextParser m String codep = try (do { some spacenonewline; char '(' <?> "codep"; anyChar `manyTill` char ')' } ) <|> return "" -descriptionp :: JournalStateParser m String+descriptionp :: JournalParser m String descriptionp = many (noneOf (";\n" :: [Char])) --- ** dates@@ -190,7 +189,7 @@ -- Hyphen (-) and period (.) are also allowed as separators. -- The year may be omitted if a default year has been set. -- Leading zeroes may be omitted.-datep :: JournalStateParser m Day+datep :: JournalParser m Day datep = do -- hacky: try to ensure precise errors for invalid dates -- XXX reported error position is not too good@@ -220,7 +219,7 @@ -- Seconds are optional. -- The timezone is optional and ignored (the time is always interpreted as a local time). -- Leading zeroes may be omitted (except in a timezone).-datetimep :: JournalStateParser m LocalTime+datetimep :: JournalParser m LocalTime datetimep = do day <- datep lift $ some spacenonewline@@ -248,7 +247,7 @@ -- return $ localTimeToUTC tz' $ LocalTime day $ TimeOfDay h' m' (fromIntegral s') return $ LocalTime day $ TimeOfDay h' m' (fromIntegral s') -secondarydatep :: Day -> JournalStateParser m Day+secondarydatep :: Day -> JournalParser m Day secondarydatep primarydate = do char '=' -- kludgy way to use primary date for default year@@ -274,7 +273,7 @@ --- ** account names -- | Parse an account name, then apply any parent account prefix and/or account aliases currently in effect.-modifiedaccountnamep :: JournalStateParser m AccountName+modifiedaccountnamep :: JournalParser m AccountName modifiedaccountnamep = do parent <- getParentAccount aliases <- getAccountAliases@@ -313,7 +312,7 @@ -- | Parse whitespace then an amount, with an optional left or right -- currency symbol and optional price, or return the special -- "missing" marker amount.-spaceandamountormissingp :: Monad m => JournalStateParser m MixedAmount+spaceandamountormissingp :: Monad m => JournalParser m MixedAmount spaceandamountormissingp = try (do lift $ some spacenonewline@@ -337,7 +336,7 @@ -- | Parse a single-commodity amount, with optional symbol on the left or -- right, optional unit or total price, and optional (ignored) -- ledger-style balance assertion or fixed lot price declaration.-amountp :: Monad m => JournalStateParser m Amount+amountp :: Monad m => JournalParser m Amount amountp = try leftsymbolamountp <|> try rightsymbolamountp <|> nosymbolamountp #ifdef TESTS@@ -377,7 +376,7 @@ return $ case multiplier of Just '*' -> True _ -> False -leftsymbolamountp :: Monad m => JournalStateParser m Amount+leftsymbolamountp :: Monad m => JournalParser m Amount leftsymbolamountp = do sign <- lift signp m <- lift multiplierp@@ -390,7 +389,7 @@ return $ applysign $ Amount c q p s m <?> "left-symbol amount" -rightsymbolamountp :: Monad m => JournalStateParser m Amount+rightsymbolamountp :: Monad m => JournalParser m Amount rightsymbolamountp = do m <- lift multiplierp (q,prec,mdec,mgrps) <- lift numberp@@ -401,7 +400,7 @@ return $ Amount c q p s m <?> "right-symbol amount" -nosymbolamountp :: Monad m => JournalStateParser m Amount+nosymbolamountp :: Monad m => JournalParser m Amount nosymbolamountp = do m <- lift multiplierp (q,prec,mdec,mgrps) <- lift numberp@@ -427,7 +426,7 @@ simplecommoditysymbolp :: TextParser m CommoditySymbol simplecommoditysymbolp = T.pack <$> some (noneOf nonsimplecommoditychars) -priceamountp :: Monad m => JournalStateParser m Price+priceamountp :: Monad m => JournalParser m Price priceamountp = try (do lift (many spacenonewline)@@ -443,7 +442,7 @@ return $ UnitPrice a)) <|> return NoPrice -partialbalanceassertionp :: Monad m => JournalStateParser m (Maybe Amount)+partialbalanceassertionp :: Monad m => JournalParser m (Maybe Amount) partialbalanceassertionp = try (do lift (many spacenonewline)@@ -464,7 +463,7 @@ -- <|> return Nothing -- http://ledger-cli.org/3.0/doc/ledger3.html#Fixing-Lot-Prices-fixedlotpricep :: Monad m => JournalStateParser m (Maybe Amount)+fixedlotpricep :: Monad m => JournalParser m (Maybe Amount) fixedlotpricep = try (do lift (many spacenonewline)@@ -564,7 +563,7 @@ --- ** comments -multilinecommentp :: JournalStateParser m ()+multilinecommentp :: JournalParser m () multilinecommentp = do string "comment" >> lift (many spacenonewline) >> newline go@@ -573,13 +572,13 @@ <|> (anyLine >> go) anyLine = anyChar `manyTill` newline -emptyorcommentlinep :: JournalStateParser m ()+emptyorcommentlinep :: JournalParser m () emptyorcommentlinep = do lift (many spacenonewline) >> (commentp <|> (lift (many spacenonewline) >> newline >> return "")) return () -- | Parse a possibly multi-line comment following a semicolon.-followingcommentp :: JournalStateParser m Text+followingcommentp :: JournalParser m Text followingcommentp = -- ptrace "followingcommentp" do samelinecomment <- lift (many spacenonewline) >> (try semicoloncommentp <|> (newline >> return ""))@@ -641,16 +640,16 @@ return (comment, tags, mdate, mdate2) -commentp :: JournalStateParser m Text+commentp :: JournalParser m Text commentp = commentStartingWithp commentchars commentchars :: [Char] commentchars = "#;*" -semicoloncommentp :: JournalStateParser m Text+semicoloncommentp :: JournalParser m Text semicoloncommentp = commentStartingWithp ";" -commentStartingWithp :: [Char] -> JournalStateParser m Text+commentStartingWithp :: [Char] -> JournalParser m Text commentStartingWithp cs = do -- ptrace "commentStartingWith" oneOf cs@@ -681,7 +680,7 @@ Left _ -> [] -- shouldn't happen -- | Parse all tags found in a string.-tagsp :: Parser [Tag]+tagsp :: SimpleTextParser [Tag] tagsp = -- do -- pdbg 0 $ "tagsp" many (try (nontagp >> tagp))@@ -690,7 +689,7 @@ -- -- >>> rtp nontagp "\na b:, \nd:e, f" -- Right "\na "-nontagp :: Parser String+nontagp :: SimpleTextParser String nontagp = -- do -- pdbg 0 "nontagp" -- anyChar `manyTill` (lookAhead (try (tagorbracketeddatetagsp Nothing >> return ()) <|> eof))@@ -704,7 +703,7 @@ -- >>> rtp tagp "a:b b , c AuxDate: 4/2" -- Right ("a","b b") ---tagp :: Parser Tag+tagp :: SimpleTextParser Tag tagp = do -- pdbg 0 "tagp" n <- tagnamep@@ -714,7 +713,7 @@ -- | -- >>> rtp tagnamep "a:" -- Right "a"-tagnamep :: Parser Text+tagnamep :: SimpleTextParser Text tagnamep = -- do -- pdbg 0 "tagnamep" T.pack <$> some (noneOf (": \t\n" :: [Char])) <* char ':'@@ -761,13 +760,13 @@ datetagp mdefdate = do -- pdbg 0 "datetagp" string "date"- n <- T.pack . fromMaybe "" <$> optional (string "2")+ n <- fromMaybe "" <$> optional (mptext "2") char ':' startpos <- getPosition v <- lift tagvaluep -- re-parse value as a date. j <- get- let ep :: Either (ParseError Char Dec) Day+ let ep :: Either (ParseError Char MPErr) Day ep = parseWithState' j{jparsedefaultyear=first3.toGregorian <$> mdefdate} -- The value extends to a comma, newline, or end of file.@@ -827,7 +826,7 @@ -- looks sufficiently like a bracketed date, now we -- re-parse as dates and throw any errors j <- get- let ep :: Either (ParseError Char Dec) (Maybe Day, Maybe Day)+ let ep :: Either (ParseError Char MPErr) (Maybe Day, Maybe Day) ep = parseWithState' j{jparsedefaultyear=first3.toGregorian <$> mdefdate} (do
Hledger/Read/CsvReader.hs view
@@ -38,7 +38,6 @@ import Data.List.Compat import Data.Maybe import Data.Ord-import qualified Data.Set as S import Data.Text (Text) import qualified Data.Text as T import Data.Time.Calendar (Day)@@ -54,8 +53,7 @@ import System.IO (stderr) import Test.HUnit hiding (State) import Text.CSV (parseCSV, CSV)-import Text.Megaparsec hiding (parse, State)-import Text.Megaparsec.Text+import Text.Megaparsec.Compat hiding (parse) import qualified Text.Parsec as Parsec import Text.Printf (hPrintf,printf) @@ -130,21 +128,24 @@ -- let (headerlines, datalines) = identifyHeaderLines records -- mfieldnames = lastMay headerlines - -- convert to transactions and return as a journal- let txns = snd $ mapAccumL- (\pos r -> (pos,- transactionFromCsvRecord- (let SourcePos name line col = pos in- SourcePos name (unsafePos $ unPos line + 1) col)- rules- r))- (initialPos parsecfilename) records+ let + -- convert CSV records to transactions+ txns = snd $ mapAccumL+ (\pos r -> + let+ SourcePos name line col = pos+ line' = (mpMkPos . (+1) . mpUnPos) line+ pos' = SourcePos name line' col+ in+ (pos, transactionFromCsvRecord pos' rules r)+ )+ (initialPos parsecfilename) records -- heuristic: if the records appear to have been in reverse date order, -- reverse them all as well as doing a txn date sort, -- so that same-day txns' original order is preserved- txns' | length txns > 1 && tdate (head txns) > tdate (last txns) = reverse txns- | otherwise = txns+ txns' | length txns > 1 && tdate (head txns) > tdate (last txns) = reverse txns+ | otherwise = txns when (not rulesfileexists) $ do hPrintf stderr "created default conversion rules file %s, edit this for better results\n" rulesfile@@ -300,7 +301,7 @@ rconditionalblocks :: [ConditionalBlock] } deriving (Show, Eq) -type CsvRulesParser a = StateT CsvRules Parser a+type CsvRulesParser a = StateT CsvRules SimpleTextParser a type DirectiveName = String type CsvFieldName = String@@ -382,14 +383,11 @@ Right r -> do r_ <- liftIO $ runExceptT $ validateRules r ExceptT $ case r_ of- Left e -> return $ Left $ parseErrorPretty $ toParseError e+ Left s -> return $ Left $ parseErrorPretty $ mpMkParseError rulesfile s Right r -> return $ Right r- where- toParseError :: forall s. Ord s => s -> ParseError Char s- toParseError s = (mempty :: ParseError Char s) { errorCustom = S.singleton s} -- | Parse this text as CSV conversion rules. The file path is for error messages.-parseCsvRules :: FilePath -> T.Text -> Either (ParseError Char Dec) CsvRules+parseCsvRules :: FilePath -> T.Text -> Either (ParseError Char MPErr) CsvRules -- parseCsvRules rulesfile s = runParser csvrulesfile nullrules{baseAccount=takeBaseName rulesfile} rulesfile s parseCsvRules rulesfile s = runParser (evalStateT rulesp rules) rulesfile s@@ -441,10 +439,10 @@ directivep :: CsvRulesParser (DirectiveName, String) directivep = (do lift $ pdbg 3 "trying directive"- d <- choiceInState $ map string directives+ d <- fmap T.unpack $ choiceInState $ map (lift . mptext . T.pack) directives v <- (((char ':' >> lift (many spacenonewline)) <|> lift (some spacenonewline)) >> directivevalp) <|> (optional (char ':') >> lift (many spacenonewline) >> lift eolof >> return "")- return (d,v)+ return (d, v) ) <?> "directive" directives =@@ -496,7 +494,9 @@ <?> "field assignment" journalfieldnamep :: CsvRulesParser String-journalfieldnamep = lift (pdbg 2 "trying journalfieldnamep") >> choiceInState (map string journalfieldnames)+journalfieldnamep = do+ lift (pdbg 2 "trying journalfieldnamep")+ T.unpack <$> choiceInState (map (lift . mptext . T.pack) journalfieldnames) -- Transaction fields and pseudo fields for CSV conversion. -- Names must precede any other name they contain, for the parser @@ -556,7 +556,7 @@ <?> "record matcher" matchoperatorp :: CsvRulesParser String-matchoperatorp = choiceInState $ map string+matchoperatorp = fmap T.unpack $ choiceInState $ map mptext ["~" -- ,"!~" -- ,"="
Hledger/Read/JournalReader.hs view
@@ -90,7 +90,7 @@ import Test.Framework import Text.Megaparsec.Error #endif-import Text.Megaparsec hiding (parse)+import Text.Megaparsec.Compat hiding (parse) import Text.Printf import System.FilePath @@ -187,7 +187,7 @@ let curdir = takeDirectory (sourceName parentpos) filepath <- expandPath curdir filename `orRethrowIOError` (show parentpos ++ " locating " ++ filename) txt <- readFileAnyLineEnding filepath `orRethrowIOError` (show parentpos ++ " reading " ++ filepath)- (ej1::Either (ParseError Char Dec) ParsedJournal) <-+ (ej1::Either (ParseError Char MPErr) ParsedJournal) <- runParserT (evalStateT (choiceInState@@ -227,7 +227,7 @@ (Right <$> io) `C.catch` \(e::C.IOException) -> return $ Left $ printf "%s:\n%s" msg (show e) -accountdirectivep :: JournalStateParser m ()+accountdirectivep :: JournalParser m () accountdirectivep = do string "account" lift (some spacenonewline)@@ -237,7 +237,7 @@ modify' (\j -> j{jaccounts = acct : jaccounts j}) -indentedlinep :: JournalStateParser m String+indentedlinep :: JournalParser m String indentedlinep = lift (some spacenonewline) >> (rstrip <$> lift restofline) -- | Parse a one-line or multi-line commodity directive.@@ -253,7 +253,7 @@ -- -- >>> Right _ <- rejp commoditydirectiveonelinep "commodity $1.00" -- >>> Right _ <- rejp commoditydirectiveonelinep "commodity $1.00 ; blah\n"-commoditydirectiveonelinep :: Monad m => JournalStateParser m ()+commoditydirectiveonelinep :: Monad m => JournalParser m () commoditydirectiveonelinep = do string "commodity" lift (some spacenonewline)@@ -292,7 +292,7 @@ else parserErrorAt pos $ printf "commodity directive symbol \"%s\" and format directive symbol \"%s\" should be the same" expectedsym acommodity -applyaccountdirectivep :: JournalStateParser m ()+applyaccountdirectivep :: JournalParser m () applyaccountdirectivep = do string "apply" >> lift (some spacenonewline) >> string "account" lift (some spacenonewline)@@ -300,12 +300,12 @@ newline pushParentAccount parent -endapplyaccountdirectivep :: JournalStateParser m ()+endapplyaccountdirectivep :: JournalParser m () endapplyaccountdirectivep = do string "end" >> lift (some spacenonewline) >> string "apply" >> lift (some spacenonewline) >> string "account" popParentAccount -aliasdirectivep :: JournalStateParser m ()+aliasdirectivep :: JournalParser m () aliasdirectivep = do string "alias" lift (some spacenonewline)@@ -336,12 +336,12 @@ repl <- rstrip <$> anyChar `manyTill` eolof return $ RegexAlias re repl -endaliasesdirectivep :: JournalStateParser m ()+endaliasesdirectivep :: JournalParser m () endaliasesdirectivep = do string "end aliases" clearAccountAliases -tagdirectivep :: JournalStateParser m ()+tagdirectivep :: JournalParser m () tagdirectivep = do string "tag" <?> "tag directive" lift (some spacenonewline)@@ -349,13 +349,13 @@ lift restofline return () -endtagdirectivep :: JournalStateParser m ()+endtagdirectivep :: JournalParser m () endtagdirectivep = do (string "end tag" <|> string "pop") <?> "end tag or pop directive" lift restofline return () -defaultyeardirectivep :: JournalStateParser m ()+defaultyeardirectivep :: JournalParser m () defaultyeardirectivep = do char 'Y' <?> "default year" lift (many spacenonewline)@@ -364,7 +364,7 @@ failIfInvalidYear y setYear y' -defaultcommoditydirectivep :: Monad m => JournalStateParser m ()+defaultcommoditydirectivep :: Monad m => JournalParser m () defaultcommoditydirectivep = do char 'D' <?> "default commodity" lift (some spacenonewline)@@ -372,7 +372,7 @@ lift restofline setDefaultCommodityAndStyle (acommodity, astyle) -marketpricedirectivep :: Monad m => JournalStateParser m MarketPrice+marketpricedirectivep :: Monad m => JournalParser m MarketPrice marketpricedirectivep = do char 'P' <?> "market price" lift (many spacenonewline)@@ -384,7 +384,7 @@ lift restofline return $ MarketPrice date symbol price -ignoredpricecommoditydirectivep :: JournalStateParser m ()+ignoredpricecommoditydirectivep :: JournalParser m () ignoredpricecommoditydirectivep = do char 'N' <?> "ignored-price commodity" lift (some spacenonewline)@@ -392,7 +392,7 @@ lift restofline return () -commodityconversiondirectivep :: Monad m => JournalStateParser m ()+commodityconversiondirectivep :: Monad m => JournalParser m () commodityconversiondirectivep = do char 'C' <?> "commodity conversion" lift (some spacenonewline)
Hledger/Read/TimeclockReader.hs view
@@ -60,7 +60,7 @@ import Data.Text (Text) import qualified Data.Text as T import Test.HUnit-import Text.Megaparsec hiding (parse)+import Text.Megaparsec.Compat hiding (parse) import Hledger.Data -- XXX too much reuse ?@@ -105,7 +105,7 @@ ] <?> "timeclock entry, or default year or historical price directive" -- | Parse a timeclock entry.-timeclockentryp :: JournalStateParser m TimeclockEntry+timeclockentryp :: JournalParser m TimeclockEntry timeclockentryp = do sourcepos <- genericSourcePos <$> lift getPosition code <- oneOf ("bhioO" :: [Char])
Hledger/Read/TimedotReader.hs view
@@ -42,7 +42,7 @@ import Data.Maybe import Data.Text (Text) import Test.HUnit-import Text.Megaparsec hiding (parse)+import Text.Megaparsec.Compat hiding (parse) import Hledger.Data import Hledger.Read.Common@@ -66,12 +66,12 @@ parse :: Maybe FilePath -> Bool -> FilePath -> Text -> ExceptT String IO Journal parse _ = parseAndFinaliseJournal timedotfilep -timedotfilep :: JournalStateParser m ParsedJournal+timedotfilep :: JournalParser m ParsedJournal timedotfilep = do many timedotfileitemp eof get where- timedotfileitemp :: JournalStateParser m ()+ timedotfileitemp :: JournalParser m () timedotfileitemp = do ptrace "timedotfileitemp" choice [@@ -89,7 +89,7 @@ -- biz.research . -- inc.client1 .... .... .... .... .... .... -- @-timedotdayp :: JournalStateParser m [Transaction]+timedotdayp :: JournalParser m [Transaction] timedotdayp = do ptrace " timedotdayp" d <- datep <* lift eolof@@ -101,7 +101,7 @@ -- @ -- fos.haskell .... .. -- @-timedotentryp :: JournalStateParser m Transaction+timedotentryp :: JournalParser m Transaction timedotentryp = do ptrace " timedotentryp" pos <- genericSourcePos <$> getPosition@@ -125,14 +125,14 @@ } return t -timedotdurationp :: JournalStateParser m Quantity+timedotdurationp :: JournalParser m Quantity timedotdurationp = try timedotnumberp <|> timedotdotsp -- | Parse a duration written as a decimal number of hours (optionally followed by the letter h). -- @ -- 1.5h -- @-timedotnumberp :: JournalStateParser m Quantity+timedotnumberp :: JournalParser m Quantity timedotnumberp = do (q, _, _, _) <- lift numberp lift (many spacenonewline)@@ -144,7 +144,7 @@ -- @ -- .... .. -- @-timedotdotsp :: JournalStateParser m Quantity+timedotdotsp :: JournalParser m Quantity timedotdotsp = do dots <- filter (not.isSpace) <$> many (oneOf (". " :: [Char])) return $ (/4) $ fromIntegral $ length dots
Hledger/Reports/MultiBalanceReports.hs view
@@ -155,7 +155,7 @@ dbg1 "displayedAccts" $ (if tree_ opts then expandAccountNames else id) $ nub $ map (clipOrEllipsifyAccountName depth) $- if empty_ opts then nub $ sort $ startAccts ++ postedAccts else postedAccts+ if empty_ opts || (balancetype_ opts) == HistoricalBalance then nub $ sort $ startAccts ++ postedAccts else postedAccts acctBalChangesPerSpan :: [[(ClippedAccountName, MixedAmount)]] = dbg1 "acctBalChangesPerSpan"
Hledger/Utils/Parse.hs view
@@ -1,38 +1,42 @@-{-# LANGUAGE FlexibleContexts, TypeFamilies #-}+{-# LANGUAGE CPP, TypeFamilies #-} module Hledger.Utils.Parse where import Control.Monad.Except+import Control.Monad.State.Strict (StateT, evalStateT) import Data.Char+import Data.Functor.Identity (Identity(..)) import Data.List import Data.Text (Text)-import Text.Megaparsec hiding (State)-import Data.Functor.Identity (Identity(..))+import Text.Megaparsec.Compat import Text.Printf -import Control.Monad.State.Strict (StateT, evalStateT)- import Hledger.Data.Types import Hledger.Utils.UTF8IOCompat (error') --- | A parser of strict text with generic user state, monad and return type.-type TextParser m a = ParsecT Dec Text m a+-- | A parser of string to some type.+type SimpleStringParser a = Parsec MPErr String a -type JournalStateParser m a = StateT Journal (ParsecT Dec Text m) a+-- | A parser of strict text to some type.+type SimpleTextParser = Parsec MPErr Text -- XXX an "a" argument breaks the CsvRulesParser declaration somehow -type JournalParser a = StateT Journal (ParsecT Dec Text Identity) a+-- | A parser of text in some monad.+type TextParser m a = ParsecT MPErr Text m a --- | A journal parser that runs in IO and can throw an error mid-parse.-type ErroringJournalParser m a = StateT Journal (ParsecT Dec Text (ExceptT String m)) a+-- | A parser of text in some monad, with a journal as state.+type JournalParser m a = StateT Journal (ParsecT MPErr Text m) a +-- | A parser of text in some monad, with a journal as state, that can throw an error string mid-parse.+type ErroringJournalParser m a = StateT Journal (ParsecT MPErr Text (ExceptT String m)) a+ -- | Backtracking choice, use this when alternatives share a prefix. -- Consumes no input if all choices fail. choice' :: [TextParser m a] -> TextParser m a-choice' = choice . map Text.Megaparsec.try+choice' = choice . map try -- | Backtracking choice, use this when alternatives share a prefix. -- Consumes no input if all choices fail.-choiceInState :: [StateT s (ParsecT Dec Text m) a] -> StateT s (ParsecT Dec Text m) a-choiceInState = choice . map Text.Megaparsec.try+choiceInState :: [StateT s (ParsecT MPErr Text m) a] -> StateT s (ParsecT MPErr Text m) a+choiceInState = choice . map try parsewith :: Parsec e Text a -> Text -> Either (ParseError Char e) a parsewith p = runParser p ""@@ -40,10 +44,15 @@ parsewithString :: Parsec e String a -> String -> Either (ParseError Char e) a parsewithString p = runParser p "" -parseWithState :: Monad m => st -> StateT st (ParsecT Dec Text m) a -> Text -> m (Either (ParseError Char Dec) a)+parseWithState :: Monad m => st -> StateT st (ParsecT MPErr Text m) a -> Text -> m (Either (ParseError Char MPErr) a) parseWithState ctx p s = runParserT (evalStateT p ctx) "" s -parseWithState' :: (Stream s, ErrorComponent e) => st -> StateT st (ParsecT e s Identity) a -> s -> (Either (ParseError (Token s) e) a)+parseWithState' :: (+ Stream s +#if !MIN_VERSION_megaparsec(6,0,0)+ ,ErrorComponent e+#endif+ ) => st -> StateT st (ParsecT e s Identity) a -> s -> (Either (ParseError (Token s) e) a) parseWithState' ctx p s = runParser (evalStateT p ctx) "" s fromparse :: (Show t, Show e) => Either (ParseError t e) a -> a@@ -61,7 +70,7 @@ nonspace :: TextParser m Char nonspace = satisfy (not . isSpace) -spacenonewline :: (Stream s, Char ~ Token s) => ParsecT Dec s m Char+spacenonewline :: (Stream s, Char ~ Token s) => ParsecT MPErr s m Char spacenonewline = satisfy (`elem` " \v\f\t") restofline :: TextParser m String
Hledger/Utils/String.hs view
@@ -49,7 +49,7 @@ import Data.Char import Data.List-import Text.Megaparsec+import Text.Megaparsec.Compat import Text.Printf (printf) import Hledger.Utils.Parse
+ Text/Megaparsec/Compat.hs view
@@ -0,0 +1,73 @@+-- | Paper over some differences between megaparsec 5 and 6,+-- making it possible to write code that supports both.++{-# LANGUAGE CPP, FlexibleContexts #-}++module Text.Megaparsec.Compat (+ module Text.Megaparsec+#if MIN_VERSION_megaparsec(6,0,0)+ ,module Text.Megaparsec.Char+#endif+ ,MPErr+ ,mptext+ ,mpMkPos+ ,mpUnPos+ ,mpMkParseError+ )+where++import qualified Data.Set as S+import Data.Text+import Text.Megaparsec++#if MIN_VERSION_megaparsec(6,0,0)++import Text.Megaparsec.Char+import Data.List.NonEmpty (fromList)+import Data.Void (Void)++-- | A basic parse error type.+type MPErr = Void++-- | Make a simple parse error.+mpMkParseError :: FilePath -> String -> ParseError Char String+mpMkParseError f s = FancyError (fromList [initialPos f]) (S.singleton $ ErrorFail s)++-- | Make a Pos. With a negative argument, throws InvalidPosException (megaparsec >= 6)+-- or calls error (megaparsec < 6).+mpMkPos :: Int -> Pos+mpMkPos = mkPos ++-- | Unmake a Pos.+mpUnPos :: Pos -> Int+mpUnPos = unPos++-- | Parse and return some Text. +mptext :: MonadParsec e Text m => Tokens Text -> m (Tokens Text) +mptext = string++#else++import Text.Megaparsec.Prim (MonadParsec)++-- | A basic parse error type.+type MPErr = Dec++-- | Make a simple parse error.+mpMkParseError :: FilePath -> String -> ParseError Char String+mpMkParseError f s = (mempty :: ParseError Char String){errorCustom = S.singleton $ f ++ ": " ++ s}++-- | Make a Pos. With a negative argument, throws InvalidPosException (megaparsec >= 6)+-- or calls error (megaparsec < 6).+mpMkPos :: Int -> Pos+mpMkPos = unsafePos . fromIntegral ++-- | Unmake a Pos.+mpUnPos :: Pos -> Int+mpUnPos = fromIntegral . unPos ++-- | Parse and return some Text. +mptext :: MonadParsec e Text m => Text -> m Text+mptext = fmap pack . string . unpack++#endif
doc/hledger_csv.5 view
@@ -1,5 +1,5 @@ -.TH "hledger_csv" "5" "June 2017" "hledger 1.3" "hledger User Manuals"+.TH "hledger_csv" "5" "August 2017" "hledger 1.3.1" "hledger User Manuals"
doc/hledger_csv.5.info view
@@ -3,8 +3,8 @@ File: hledger_csv.5.info, Node: Top, Next: CSV RULES, Up: (dir) -hledger_csv(5) hledger 1.3-**************************+hledger_csv(5) hledger 1.3.1+**************************** hledger can read CSV files, converting each CSV record into a journal entry (transaction), if you provide some conversion hints in a "rules@@ -201,21 +201,21 @@ Tag Table: Node: Top74-Node: CSV RULES810-Ref: #csv-rules920-Node: skip1163-Ref: #skip1259-Node: date-format1431-Ref: #date-format1560-Node: field list2066-Ref: #field-list2205-Node: field assignment2910-Ref: #field-assignment3067-Node: conditional block3571-Ref: #conditional-block3727-Node: include4623-Ref: #include4734-Node: CSV TIPS4965-Ref: #csv-tips5061+Node: CSV RULES814+Ref: #csv-rules924+Node: skip1167+Ref: #skip1263+Node: date-format1435+Ref: #date-format1564+Node: field list2070+Ref: #field-list2209+Node: field assignment2914+Ref: #field-assignment3071+Node: conditional block3575+Ref: #conditional-block3731+Node: include4627+Ref: #include4738+Node: CSV TIPS4969+Ref: #csv-tips5065 End Tag Table
doc/hledger_csv.5.txt view
@@ -171,4 +171,4 @@ -hledger 1.3 June 2017 hledger_csv(5)+hledger 1.3.1 August 2017 hledger_csv(5)
doc/hledger_journal.5 view
@@ -1,6 +1,6 @@ .\"t -.TH "hledger_journal" "5" "June 2017" "hledger 1.3" "hledger User Manuals"+.TH "hledger_journal" "5" "August 2017" "hledger 1.3.1" "hledger User Manuals"
doc/hledger_journal.5.info view
@@ -4,8 +4,8 @@ File: hledger_journal.5.info, Node: Top, Next: FILE FORMAT, Up: (dir) -hledger_journal(5) hledger 1.3-******************************+hledger_journal(5) hledger 1.3.1+******************************** hledger's usual data source is a plain text file containing journal entries in hledger journal format. This file represents a standard@@ -1047,83 +1047,83 @@ Tag Table: Node: Top78-Node: FILE FORMAT2292-Ref: #file-format2418-Node: Transactions2625-Ref: #transactions2748-Node: Postings3313-Ref: #postings3442-Node: Dates4437-Ref: #dates4554-Node: Simple dates4619-Ref: #simple-dates4747-Node: Secondary dates5113-Ref: #secondary-dates5269-Node: Posting dates6832-Ref: #posting-dates6963-Node: Status8337-Ref: #status8461-Node: Account names10175-Ref: #account-names10315-Node: Amounts10802-Ref: #amounts10940-Node: Virtual Postings13041-Ref: #virtual-postings13202-Node: Balance Assertions14422-Ref: #balance-assertions14599-Node: Assertions and ordering15495-Ref: #assertions-and-ordering15683-Node: Assertions and included files16383-Ref: #assertions-and-included-files16626-Node: Assertions and multiple -f options16959-Ref: #assertions-and-multiple--f-options17215-Node: Assertions and commodities17347-Ref: #assertions-and-commodities17584-Node: Assertions and subaccounts18280-Ref: #assertions-and-subaccounts18514-Node: Assertions and virtual postings19035-Ref: #assertions-and-virtual-postings19244-Node: Balance Assignments19386-Ref: #balance-assignments19555-Node: Prices20674-Ref: #prices20809-Node: Transaction prices20860-Ref: #transaction-prices21007-Node: Market prices23163-Ref: #market-prices23300-Node: Comments24260-Ref: #comments24384-Node: Tags25497-Ref: #tags25617-Node: Implicit tags27046-Ref: #implicit-tags27154-Node: Directives27671-Ref: #directives27786-Node: Account aliases27979-Ref: #account-aliases28125-Node: Basic aliases28729-Ref: #basic-aliases28874-Node: Regex aliases29564-Ref: #regex-aliases29734-Node: Multiple aliases30449-Ref: #multiple-aliases30623-Node: end aliases31121-Ref: #end-aliases31263-Node: account directive31364-Ref: #account-directive31546-Node: apply account directive31842-Ref: #apply-account-directive32040-Node: Multi-line comments32699-Ref: #multi-line-comments32891-Node: commodity directive33019-Ref: #commodity-directive33205-Node: Default commodity34077-Ref: #default-commodity34252-Node: Default year34789-Ref: #default-year34956-Node: Including other files35379-Ref: #including-other-files35538-Node: EDITOR SUPPORT35935-Ref: #editor-support36055+Node: FILE FORMAT2296+Ref: #file-format2422+Node: Transactions2629+Ref: #transactions2752+Node: Postings3317+Ref: #postings3446+Node: Dates4441+Ref: #dates4558+Node: Simple dates4623+Ref: #simple-dates4751+Node: Secondary dates5117+Ref: #secondary-dates5273+Node: Posting dates6836+Ref: #posting-dates6967+Node: Status8341+Ref: #status8465+Node: Account names10179+Ref: #account-names10319+Node: Amounts10806+Ref: #amounts10944+Node: Virtual Postings13045+Ref: #virtual-postings13206+Node: Balance Assertions14426+Ref: #balance-assertions14603+Node: Assertions and ordering15499+Ref: #assertions-and-ordering15687+Node: Assertions and included files16387+Ref: #assertions-and-included-files16630+Node: Assertions and multiple -f options16963+Ref: #assertions-and-multiple--f-options17219+Node: Assertions and commodities17351+Ref: #assertions-and-commodities17588+Node: Assertions and subaccounts18284+Ref: #assertions-and-subaccounts18518+Node: Assertions and virtual postings19039+Ref: #assertions-and-virtual-postings19248+Node: Balance Assignments19390+Ref: #balance-assignments19559+Node: Prices20678+Ref: #prices20813+Node: Transaction prices20864+Ref: #transaction-prices21011+Node: Market prices23167+Ref: #market-prices23304+Node: Comments24264+Ref: #comments24388+Node: Tags25501+Ref: #tags25621+Node: Implicit tags27050+Ref: #implicit-tags27158+Node: Directives27675+Ref: #directives27790+Node: Account aliases27983+Ref: #account-aliases28129+Node: Basic aliases28733+Ref: #basic-aliases28878+Node: Regex aliases29568+Ref: #regex-aliases29738+Node: Multiple aliases30453+Ref: #multiple-aliases30627+Node: end aliases31125+Ref: #end-aliases31267+Node: account directive31368+Ref: #account-directive31550+Node: apply account directive31846+Ref: #apply-account-directive32044+Node: Multi-line comments32703+Ref: #multi-line-comments32895+Node: commodity directive33023+Ref: #commodity-directive33209+Node: Default commodity34081+Ref: #default-commodity34256+Node: Default year34793+Ref: #default-year34960+Node: Including other files35383+Ref: #including-other-files35542+Node: EDITOR SUPPORT35939+Ref: #editor-support36059 End Tag Table
doc/hledger_journal.5.txt view
@@ -835,4 +835,4 @@ -hledger 1.3 June 2017 hledger_journal(5)+hledger 1.3.1 August 2017 hledger_journal(5)
doc/hledger_timeclock.5 view
@@ -1,5 +1,5 @@ -.TH "hledger_timeclock" "5" "June 2017" "hledger 1.3" "hledger User Manuals"+.TH "hledger_timeclock" "5" "August 2017" "hledger 1.3.1" "hledger User Manuals"
doc/hledger_timeclock.5.info view
@@ -4,8 +4,8 @@ File: hledger_timeclock.5.info, Node: Top, Up: (dir) -hledger_timeclock(5) hledger 1.3-********************************+hledger_timeclock(5) hledger 1.3.1+********************************** hledger can read timeclock files. As with Ledger, these are (a subset of) timeclock.el's format, containing clock-in and clock-out entries as
doc/hledger_timeclock.5.txt view
@@ -79,4 +79,4 @@ -hledger 1.3 June 2017 hledger_timeclock(5)+hledger 1.3.1 August 2017 hledger_timeclock(5)
doc/hledger_timedot.5 view
@@ -1,5 +1,5 @@ -.TH "hledger_timedot" "5" "June 2017" "hledger 1.3" "hledger User Manuals"+.TH "hledger_timedot" "5" "August 2017" "hledger 1.3.1" "hledger User Manuals"
doc/hledger_timedot.5.info view
@@ -4,8 +4,8 @@ File: hledger_timedot.5.info, Node: Top, Next: FILE FORMAT, Up: (dir) -hledger_timedot(5) hledger 1.3-******************************+hledger_timedot(5) hledger 1.3.1+******************************** Timedot is a plain text format for logging dated, categorised quantities (eg time), supported by hledger. It is convenient for approximate and@@ -106,7 +106,7 @@ Tag Table: Node: Top78-Node: FILE FORMAT882-Ref: #file-format985+Node: FILE FORMAT886+Ref: #file-format989 End Tag Table
doc/hledger_timedot.5.txt view
@@ -120,4 +120,4 @@ -hledger 1.3 June 2017 hledger_timedot(5)+hledger 1.3.1 August 2017 hledger_timedot(5)
hledger-lib.cabal view
@@ -1,9 +1,9 @@--- This file has been generated from package.yaml by hpack version 0.17.0.+-- This file has been generated from package.yaml by hpack version 0.17.1. -- -- see: https://github.com/sol/hpack name: hledger-lib-version: 1.3+version: 1.3.1 synopsis: Core data types, parsers and functionality for the hledger accounting tools description: This is a reusable library containing hledger's core functionality. .@@ -72,7 +72,7 @@ , directory , filepath , hashtables >= 1.2- , megaparsec >=5.0 && < 5.4+ , megaparsec >=5.0 && < 6.2 , mtl , mtl-compat , old-time@@ -141,6 +141,7 @@ Hledger.Utils.Text Hledger.Utils.Tree Hledger.Utils.UTF8IOCompat+ Text.Megaparsec.Compat other-modules: Paths_hledger_lib default-language: Haskell2010@@ -168,7 +169,7 @@ , directory , filepath , hashtables >= 1.2- , megaparsec >=5.0 && < 5.4+ , megaparsec >=5.0 && < 6.2 , mtl , mtl-compat , old-time@@ -186,6 +187,13 @@ if impl(ghc <7.6) build-depends: ghc-prim+ if flag(oldtime)+ build-depends:+ time <1.5+ , old-locale+ else+ build-depends:+ time >=1.5 other-modules: Hledger Hledger.Data@@ -230,6 +238,7 @@ Hledger.Utils.Text Hledger.Utils.Tree Hledger.Utils.UTF8IOCompat+ Text.Megaparsec.Compat default-language: Haskell2010 test-suite hunittests@@ -255,7 +264,7 @@ , directory , filepath , hashtables >= 1.2- , megaparsec >=5.0 && < 5.4+ , megaparsec >=5.0 && < 6.2 , mtl , mtl-compat , old-time@@ -326,4 +335,5 @@ Hledger.Utils.Text Hledger.Utils.Tree Hledger.Utils.UTF8IOCompat+ Text.Megaparsec.Compat default-language: Haskell2010