hledger-lib-1.21: A reusable library providing the core functionality of hledger
Safe HaskellNone
LanguageHaskell2010

Hledger.Read.JournalReader

Description

A reader for hledger's journal file format (http://hledger.org/MANUAL.html#the-journal-file). hledger's journal format is a compatible subset of c++ ledger's (http://ledger-cli.org/3.0/doc/ledger3.html#Journal-Format), so this reader should handle many ledger files as well. Example:

2012/3/24 gift
    expenses:gifts  $10
    assets:cash

Journal format supports the include directive which can read files in other formats, so the other file format readers need to be importable and invocable here.

Some important parts of journal parsing are therefore kept in Hledger.Read.Common, to avoid import cycles.

Synopsis

Reader-finding utils

findReader :: MonadIO m => Maybe StorageFormat -> Maybe FilePath -> Maybe (Reader m) Source #

findReader mformat mpath

Find the reader named by mformat, if provided. Or, if a file path is provided, find the first reader that handles its file extension, if any.

splitReaderPrefix :: PrefixedFilePath -> (Maybe String, FilePath) Source #

If a filepath is prefixed by one of the reader names and a colon, split that off. Eg "csv:-" -> (Just "csv", "-").

Reader

Parsing utils

parseAndFinaliseJournal :: ErroringJournalParser IO ParsedJournal -> InputOpts -> FilePath -> Text -> ExceptT String IO Journal Source #

Given a parser to ParsedJournal, input options, file path and content: run the parser on the content, and finalise the result to get a Journal; or throw an error.

runJournalParser :: Monad m => JournalParser m a -> Text -> m (Either (ParseErrorBundle Text CustomErr) a) Source #

Run a journal parser in some monad. See also: parseWithState.

rjp :: Monad m => JournalParser m a -> Text -> m (Either (ParseErrorBundle Text CustomErr) a) Source #

Run a journal parser in some monad. See also: parseWithState.

Parsers used elsewhere

journalp :: MonadIO m => ErroringJournalParser m ParsedJournal Source #

A journal parser. Accumulates and returns a ParsedJournal, which should be finalised/validated before use.

>>> rejp (journalp <* eof) "2015/1/1\n a  0\n"
Right (Right Journal  with 1 transactions, 1 accounts)

datetimep :: JournalParser m LocalTime Source #

Parse a date and time in YYYY-MM-DD HH:MM[:SS][+-ZZZZ] format. Slash (/) and period (.) are also allowed as date separators. The year may be omitted if a default year has been set. 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).

datep :: JournalParser m Day Source #

Parse a date in YYYY-MM-DD format. Slash (/) and period (.) are also allowed as separators. The year may be omitted if a default year has been set. Leading zeroes may be omitted.

modifiedaccountnamep :: JournalParser m AccountName Source #

Parse an account name (plus one following space if present), then apply any parent account prefix and/or account aliases currently in effect, in that order. (Ie first add the parent account prefix, then rewrite with aliases). This calls error if any account alias with an invalid regular expression exists.

emptyorcommentlinep :: TextParser m () Source #

A blank or comment line in journal format: a line that's empty or containing only whitespace or whose first non-whitespace character is semicolon, hash, or star.

followingcommentp :: TextParser m Text Source #

Parse the text of a (possibly multiline) comment following a journal item.

>>> rtp followingcommentp ""   -- no comment
Right ""
>>> rtp followingcommentp ";"    -- just a (empty) same-line comment. newline is added
Right "\n"
>>> rtp followingcommentp ";  \n"
Right "\n"
>>> rtp followingcommentp ";\n ;\n"  -- a same-line and a next-line comment
Right "\n\n"
>>> rtp followingcommentp "\n ;\n"  -- just a next-line comment. Insert an empty same-line comment so the next-line comment doesn't become a same-line comment.
Right "\n\n"

Tests