2010-05-30 23:11:58 +04:00
|
|
|
{-# LANGUAGE CPP #-}
|
|
|
|
{-|
|
|
|
|
|
|
|
|
A reader for the timelog file format generated by timeclock.el.
|
|
|
|
|
|
|
|
From timeclock.el 2.6:
|
|
|
|
|
|
|
|
@
|
|
|
|
A timelog contains data in the form of a single entry per line.
|
|
|
|
Each entry has the form:
|
|
|
|
|
|
|
|
CODE YYYY/MM/DD HH:MM:SS [COMMENT]
|
|
|
|
|
|
|
|
CODE is one of: b, h, i, o or O. COMMENT is optional when the code is
|
|
|
|
i, o or O. The meanings of the codes are:
|
|
|
|
|
|
|
|
b Set the current time balance, or \"time debt\". Useful when
|
|
|
|
archiving old log data, when a debt must be carried forward.
|
|
|
|
The COMMENT here is the number of seconds of debt.
|
|
|
|
|
|
|
|
h Set the required working time for the given day. This must
|
|
|
|
be the first entry for that day. The COMMENT in this case is
|
|
|
|
the number of hours in this workday. Floating point amounts
|
|
|
|
are allowed.
|
|
|
|
|
|
|
|
i Clock in. The COMMENT in this case should be the name of the
|
|
|
|
project worked on.
|
|
|
|
|
|
|
|
o Clock out. COMMENT is unnecessary, but can be used to provide
|
|
|
|
a description of how the period went, for example.
|
|
|
|
|
|
|
|
O Final clock out. Whatever project was being worked on, it is
|
|
|
|
now finished. Useful for creating summary reports.
|
|
|
|
@
|
|
|
|
|
|
|
|
Example:
|
|
|
|
|
|
|
|
@
|
|
|
|
i 2007/03/10 12:26:00 hledger
|
|
|
|
o 2007/03/10 17:26:02
|
|
|
|
@
|
|
|
|
|
|
|
|
-}
|
|
|
|
|
2010-11-15 10:01:46 +03:00
|
|
|
module Hledger.Read.TimelogReader (
|
|
|
|
tests_TimelogReader,
|
2010-06-25 18:56:48 +04:00
|
|
|
reader,
|
2010-05-31 05:15:18 +04:00
|
|
|
)
|
2010-05-30 23:11:58 +04:00
|
|
|
where
|
2010-05-31 05:15:18 +04:00
|
|
|
import Control.Monad.Error (ErrorT(..))
|
2010-06-25 18:56:48 +04:00
|
|
|
import Text.ParserCombinators.Parsec hiding (parse)
|
2010-05-30 23:11:58 +04:00
|
|
|
import Hledger.Data
|
2010-11-15 10:18:35 +03:00
|
|
|
import Hledger.Read.Utils
|
2010-11-15 10:01:46 +03:00
|
|
|
import Hledger.Read.JournalReader (ledgerExclamationDirective, ledgerHistoricalPrice,
|
2010-11-15 10:18:35 +03:00
|
|
|
ledgerDefaultYear, emptyLine, ledgerdatetime)
|
2010-05-30 23:11:58 +04:00
|
|
|
|
|
|
|
|
2010-06-25 18:56:48 +04:00
|
|
|
reader :: Reader
|
|
|
|
reader = Reader format detect parse
|
|
|
|
|
|
|
|
format :: String
|
|
|
|
format = "timelog"
|
|
|
|
|
|
|
|
-- | Does the given file path and data provide timeclock.el's timelog format ?
|
|
|
|
detect :: FilePath -> String -> Bool
|
|
|
|
detect f _ = fileSuffix f == format
|
|
|
|
|
2010-05-30 23:11:58 +04:00
|
|
|
-- | Parse and post-process a "Journal" from timeclock.el's timelog
|
|
|
|
-- format, saving the provided file path and the current time, or give an
|
|
|
|
-- error.
|
2010-06-25 18:56:48 +04:00
|
|
|
parse :: FilePath -> String -> ErrorT String IO Journal
|
|
|
|
parse = parseJournalWith timelogFile
|
2010-05-30 23:11:58 +04:00
|
|
|
|
2010-11-13 18:03:40 +03:00
|
|
|
timelogFile :: GenParser Char JournalContext (JournalUpdate,JournalContext)
|
2010-05-30 23:11:58 +04:00
|
|
|
timelogFile = do items <- many timelogItem
|
|
|
|
eof
|
2010-11-13 18:03:40 +03:00
|
|
|
ctx <- getState
|
|
|
|
return (liftM (foldr (.) id) $ sequence items, ctx)
|
2010-05-30 23:11:58 +04:00
|
|
|
where
|
|
|
|
-- As all ledger line types can be distinguished by the first
|
|
|
|
-- character, excepting transactions versus empty (blank or
|
|
|
|
-- comment-only) lines, can use choice w/o try
|
|
|
|
timelogItem = choice [ ledgerExclamationDirective
|
|
|
|
, liftM (return . addHistoricalPrice) ledgerHistoricalPrice
|
|
|
|
, ledgerDefaultYear
|
|
|
|
, emptyLine >> return (return id)
|
|
|
|
, liftM (return . addTimeLogEntry) timelogentry
|
|
|
|
] <?> "timelog entry, or default year or historical price directive"
|
|
|
|
|
|
|
|
-- | Parse a timelog entry.
|
2010-07-13 10:30:06 +04:00
|
|
|
timelogentry :: GenParser Char JournalContext TimeLogEntry
|
2010-05-30 23:11:58 +04:00
|
|
|
timelogentry = do
|
|
|
|
code <- oneOf "bhioO"
|
|
|
|
many1 spacenonewline
|
|
|
|
datetime <- ledgerdatetime
|
|
|
|
comment <- optionMaybe (many1 spacenonewline >> liftM2 (++) getParentAccount restofline)
|
2010-07-08 07:08:28 +04:00
|
|
|
return $ TimeLogEntry (read [code]) datetime (maybe "" rstrip comment)
|
2010-05-30 23:11:58 +04:00
|
|
|
|
2010-11-15 10:01:46 +03:00
|
|
|
tests_TimelogReader = TestList [
|
2010-05-30 23:11:58 +04:00
|
|
|
]
|
|
|
|
|