strip trailing whitespace from all Haskell files
This commit is contained in:
parent
22279978af
commit
d1618aaca8
@ -9,7 +9,7 @@ import Hledger.Cli
|
|||||||
import Text.CSV
|
import Text.CSV
|
||||||
|
|
||||||
|
|
||||||
argsmode =
|
argsmode =
|
||||||
(defCommandMode ["balance-csv"]) {
|
(defCommandMode ["balance-csv"]) {
|
||||||
modeHelp = "show matched postings accounts and their balances as CSV"
|
modeHelp = "show matched postings accounts and their balances as CSV"
|
||||||
,modeGroupFlags = Group {
|
,modeGroupFlags = Group {
|
||||||
|
|||||||
@ -16,7 +16,7 @@ main = do
|
|||||||
opts <- getCliOpts (defCommandMode ["hledger-print-unique"])
|
opts <- getCliOpts (defCommandMode ["hledger-print-unique"])
|
||||||
withJournalDo opts $
|
withJournalDo opts $
|
||||||
\opts j@Journal{jtxns=ts} -> print' opts j{jtxns=uniquify ts}
|
\opts j@Journal{jtxns=ts} -> print' opts j{jtxns=uniquify ts}
|
||||||
where
|
where
|
||||||
uniquify = nubBy (\t1 t2 -> thingToCompare t1 == thingToCompare t2) . sortBy (comparing thingToCompare)
|
uniquify = nubBy (\t1 t2 -> thingToCompare t1 == thingToCompare t2) . sortBy (comparing thingToCompare)
|
||||||
thingToCompare = tdescription
|
thingToCompare = tdescription
|
||||||
-- thingToCompare = tdate
|
-- thingToCompare = tdate
|
||||||
|
|||||||
@ -35,7 +35,7 @@ cmdmode = (defCommandMode ["hledger-rewrite"]) {
|
|||||||
,("Reporting", reportflags)
|
,("Reporting", reportflags)
|
||||||
,("Misc", helpflags)
|
,("Misc", helpflags)
|
||||||
]
|
]
|
||||||
,groupUnnamed = [flagReq ["add-posting"] (\s opts -> Right $ setopt "add-posting" s opts) "'ACCT AMTEXPR'"
|
,groupUnnamed = [flagReq ["add-posting"] (\s opts -> Right $ setopt "add-posting" s opts) "'ACCT AMTEXPR'"
|
||||||
"add a posting to ACCT, which may be parenthesised. AMTEXPR is either a literal amount, or *N which means the transaction's first matched amount multiplied by N (a decimal number). Two spaces separate ACCT and AMTEXPR."]
|
"add a posting to ACCT, which may be parenthesised. AMTEXPR is either a literal amount, or *N which means the transaction's first matched amount multiplied by N (a decimal number). Two spaces separate ACCT and AMTEXPR."]
|
||||||
,groupHidden = []
|
,groupHidden = []
|
||||||
}
|
}
|
||||||
@ -66,7 +66,7 @@ amountexprp =
|
|||||||
|
|
||||||
amountExprRenderer :: Query -> AmountExpr -> (Transaction -> MixedAmount)
|
amountExprRenderer :: Query -> AmountExpr -> (Transaction -> MixedAmount)
|
||||||
amountExprRenderer q aex =
|
amountExprRenderer q aex =
|
||||||
case aex of
|
case aex of
|
||||||
AmountLiteral s -> either parseerror (const . mixed) $ parseWithCtx nullctx amountp s
|
AmountLiteral s -> either parseerror (const . mixed) $ parseWithCtx nullctx amountp s
|
||||||
AmountMultiplier n -> (`divideMixedAmount` (1 / n)) . (`firstAmountMatching` q)
|
AmountMultiplier n -> (`divideMixedAmount` (1 / n)) . (`firstAmountMatching` q)
|
||||||
where
|
where
|
||||||
@ -93,4 +93,4 @@ main = do
|
|||||||
let j' = j{jtxns=map (\t -> if q `matchesTransaction` t then rewriteTransaction t addps else t) ts}
|
let j' = j{jtxns=map (\t -> if q `matchesTransaction` t then rewriteTransaction t addps else t) ts}
|
||||||
-- run the print command, showing all transactions
|
-- run the print command, showing all transactions
|
||||||
print' opts{reportopts_=ropts{query_=""}} j'
|
print' opts{reportopts_=ropts{query_=""}} j'
|
||||||
|
|
||||||
|
|||||||
@ -93,7 +93,7 @@ vty opts j = do
|
|||||||
,abuf=[]
|
,abuf=[]
|
||||||
,alocs=[]
|
,alocs=[]
|
||||||
}
|
}
|
||||||
go a
|
go a
|
||||||
|
|
||||||
-- | Update the screen, wait for the next event, repeat.
|
-- | Update the screen, wait for the next event, repeat.
|
||||||
go :: AppState -> IO ()
|
go :: AppState -> IO ()
|
||||||
@ -101,7 +101,7 @@ go a@AppState{av=av,aopts=opts} = do
|
|||||||
when (not $ debug_vty_ opts) $ update av (renderScreen a)
|
when (not $ debug_vty_ opts) $ update av (renderScreen a)
|
||||||
k <- next_event av
|
k <- next_event av
|
||||||
d <- getCurrentDay
|
d <- getCurrentDay
|
||||||
case k of
|
case k of
|
||||||
EvResize x y -> go $ resize x y a
|
EvResize x y -> go $ resize x y a
|
||||||
EvKey (KASCII 'l') [MCtrl] -> refresh av >> go a{amsg=helpmsg}
|
EvKey (KASCII 'l') [MCtrl] -> refresh av >> go a{amsg=helpmsg}
|
||||||
EvKey (KASCII 'b') [] -> go $ resetTrailAndEnter d BalanceScreen a
|
EvKey (KASCII 'b') [] -> go $ resetTrailAndEnter d BalanceScreen a
|
||||||
@ -151,7 +151,7 @@ setScrollY y a@AppState{alocs=(l:locs)} = a{alocs=(l':locs)} where l' = setLocSc
|
|||||||
|
|
||||||
setPosY _ AppState{alocs=[]} = error' "shouldn't happen" -- silence warnings
|
setPosY _ AppState{alocs=[]} = error' "shouldn't happen" -- silence warnings
|
||||||
setPosY y a@AppState{alocs=(l:locs)} = a{alocs=(l':locs)}
|
setPosY y a@AppState{alocs=(l:locs)} = a{alocs=(l':locs)}
|
||||||
where
|
where
|
||||||
l' = setLocScrollY sy $ setLocCursorY cy l
|
l' = setLocScrollY sy $ setLocCursorY cy l
|
||||||
ph = pageHeight a
|
ph = pageHeight a
|
||||||
cy = y `mod` ph
|
cy = y `mod` ph
|
||||||
@ -186,7 +186,7 @@ moveDownAndPushEdge a
|
|||||||
| sy+cy >= bh = a
|
| sy+cy >= bh = a
|
||||||
| cy < ph-1 = updateCursorY (+1) a
|
| cy < ph-1 = updateCursorY (+1) a
|
||||||
| otherwise = updateScrollY (+1) a
|
| otherwise = updateScrollY (+1) a
|
||||||
where
|
where
|
||||||
Loc{sy=sy,cy=cy} = head $ alocs a
|
Loc{sy=sy,cy=cy} = head $ alocs a
|
||||||
ph = pageHeight a
|
ph = pageHeight a
|
||||||
bh = length $ abuf a
|
bh = length $ abuf a
|
||||||
@ -332,7 +332,7 @@ renderScreen (a@AppState{aw=w,ah=h,abuf=buf,amsg=msg}) =
|
|||||||
renderStatus w msg
|
renderStatus w msg
|
||||||
,pic_background = Background ' ' def_attr
|
,pic_background = Background ' ' def_attr
|
||||||
}
|
}
|
||||||
where
|
where
|
||||||
(cx, cy) = (0, cursorY a)
|
(cx, cy) = (0, cursorY a)
|
||||||
sy = scrollY a
|
sy = scrollY a
|
||||||
-- mainimg = (renderString attr $ unlines $ above)
|
-- mainimg = (renderString attr $ unlines $ above)
|
||||||
@ -381,8 +381,8 @@ theme = Restrained
|
|||||||
|
|
||||||
data UITheme = Restrained | Colorful | Blood
|
data UITheme = Restrained | Colorful | Blood
|
||||||
|
|
||||||
(defaultattr,
|
(defaultattr,
|
||||||
currentlineattr,
|
currentlineattr,
|
||||||
statusattr
|
statusattr
|
||||||
) = case theme of
|
) = case theme of
|
||||||
Restrained -> (def_attr
|
Restrained -> (def_attr
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
{-|
|
{-|
|
||||||
|
|
||||||
The Hledger.Data library allows parsing and querying of C++ ledger-style
|
The Hledger.Data library allows parsing and querying of C++ ledger-style
|
||||||
journal files. It generally provides a compatible subset of C++ ledger's
|
journal files. It generally provides a compatible subset of C++ ledger's
|
||||||
|
|||||||
@ -115,7 +115,7 @@ sumAccounts a
|
|||||||
|
|
||||||
-- | Remove all subaccounts below a certain depth.
|
-- | Remove all subaccounts below a certain depth.
|
||||||
clipAccounts :: Int -> Account -> Account
|
clipAccounts :: Int -> Account -> Account
|
||||||
clipAccounts 0 a = a{asubs=[]}
|
clipAccounts 0 a = a{asubs=[]}
|
||||||
clipAccounts d a = a{asubs=subs}
|
clipAccounts d a = a{asubs=subs}
|
||||||
where
|
where
|
||||||
subs = map (clipAccounts (d-1)) $ asubs a
|
subs = map (clipAccounts (d-1)) $ asubs a
|
||||||
|
|||||||
@ -63,7 +63,7 @@ isAccountNamePrefixOf :: AccountName -> AccountName -> Bool
|
|||||||
isAccountNamePrefixOf = isPrefixOf . (++ [acctsepchar])
|
isAccountNamePrefixOf = isPrefixOf . (++ [acctsepchar])
|
||||||
|
|
||||||
isSubAccountNameOf :: AccountName -> AccountName -> Bool
|
isSubAccountNameOf :: AccountName -> AccountName -> Bool
|
||||||
s `isSubAccountNameOf` p =
|
s `isSubAccountNameOf` p =
|
||||||
(p `isAccountNamePrefixOf` s) && (accountNameLevel s == (accountNameLevel p + 1))
|
(p `isAccountNamePrefixOf` s) && (accountNameLevel s == (accountNameLevel p + 1))
|
||||||
|
|
||||||
-- | From a list of account names, select those which are direct
|
-- | From a list of account names, select those which are direct
|
||||||
@ -73,7 +73,7 @@ subAccountNamesFrom accts a = filter (`isSubAccountNameOf` a) accts
|
|||||||
|
|
||||||
-- | Convert a list of account names to a tree.
|
-- | Convert a list of account names to a tree.
|
||||||
accountNameTreeFrom :: [AccountName] -> Tree AccountName
|
accountNameTreeFrom :: [AccountName] -> Tree AccountName
|
||||||
accountNameTreeFrom accts =
|
accountNameTreeFrom accts =
|
||||||
Node "root" (accounttreesfrom (topAccountNames accts))
|
Node "root" (accounttreesfrom (topAccountNames accts))
|
||||||
where
|
where
|
||||||
accounttreesfrom :: [AccountName] -> [Tree AccountName]
|
accounttreesfrom :: [AccountName] -> [Tree AccountName]
|
||||||
@ -85,7 +85,7 @@ nullaccountnametree = Node "root" []
|
|||||||
|
|
||||||
-- | Elide an account name to fit in the specified width.
|
-- | Elide an account name to fit in the specified width.
|
||||||
-- From the ledger 2.6 news:
|
-- From the ledger 2.6 news:
|
||||||
--
|
--
|
||||||
-- @
|
-- @
|
||||||
-- What Ledger now does is that if an account name is too long, it will
|
-- What Ledger now does is that if an account name is too long, it will
|
||||||
-- start abbreviating the first parts of the account name down to two
|
-- start abbreviating the first parts of the account name down to two
|
||||||
@ -99,7 +99,7 @@ nullaccountnametree = Node "root" []
|
|||||||
-- ..:Af:Lu:Sn:Ca:Ch:Cash ; Abbreviated and elided!
|
-- ..:Af:Lu:Sn:Ca:Ch:Cash ; Abbreviated and elided!
|
||||||
-- @
|
-- @
|
||||||
elideAccountName :: Int -> AccountName -> AccountName
|
elideAccountName :: Int -> AccountName -> AccountName
|
||||||
elideAccountName width s =
|
elideAccountName width s =
|
||||||
elideLeft width $ accountNameFromComponents $ elideparts width [] $ accountNameComponents s
|
elideLeft width $ accountNameFromComponents $ elideparts width [] $ accountNameComponents s
|
||||||
where
|
where
|
||||||
elideparts :: Int -> [String] -> [String] -> [String]
|
elideparts :: Int -> [String] -> [String] -> [String]
|
||||||
|
|||||||
@ -4,13 +4,13 @@ A simple 'Amount' is some quantity of money, shares, or anything else.
|
|||||||
It has a (possibly null) 'Commodity' and a numeric quantity:
|
It has a (possibly null) 'Commodity' and a numeric quantity:
|
||||||
|
|
||||||
@
|
@
|
||||||
$1
|
$1
|
||||||
£-50
|
£-50
|
||||||
EUR 3.44
|
EUR 3.44
|
||||||
GOOG 500
|
GOOG 500
|
||||||
1.5h
|
1.5h
|
||||||
90 apples
|
90 apples
|
||||||
0
|
0
|
||||||
@
|
@
|
||||||
|
|
||||||
It may also have an assigned 'Price', representing this amount's per-unit
|
It may also have an assigned 'Price', representing this amount's per-unit
|
||||||
@ -166,7 +166,7 @@ similarAmountsOp op Amount{acommodity=_, aquantity=q1, astyle=AmountStyle{aspre
|
|||||||
Amount{acommodity=c2, aquantity=q2, astyle=s2@AmountStyle{asprecision=p2}} =
|
Amount{acommodity=c2, aquantity=q2, astyle=s2@AmountStyle{asprecision=p2}} =
|
||||||
-- trace ("a1:"++showAmountDebug a1) $ trace ("a2:"++showAmountDebug a2) $ traceWith (("= :"++).showAmountDebug)
|
-- trace ("a1:"++showAmountDebug a1) $ trace ("a2:"++showAmountDebug a2) $ traceWith (("= :"++).showAmountDebug)
|
||||||
amount{acommodity=c2, aquantity=q1 `op` q2, astyle=s2{asprecision=max p1 p2}}
|
amount{acommodity=c2, aquantity=q1 `op` q2, astyle=s2{asprecision=max p1 p2}}
|
||||||
-- c1==c2 || q1==0 || q2==0 =
|
-- c1==c2 || q1==0 || q2==0 =
|
||||||
-- otherwise = error "tried to do simple arithmetic with amounts in different commodities"
|
-- otherwise = error "tried to do simple arithmetic with amounts in different commodities"
|
||||||
|
|
||||||
-- | Convert an amount to the specified commodity, ignoring and discarding
|
-- | Convert an amount to the specified commodity, ignoring and discarding
|
||||||
@ -605,7 +605,7 @@ tests_Hledger_Data_Amount = TestList $
|
|||||||
,usd (-0.25)
|
,usd (-0.25)
|
||||||
])
|
])
|
||||||
`is` Mixed [usd 0 `withPrecision` 0]
|
`is` Mixed [usd 0 `withPrecision` 0]
|
||||||
|
|
||||||
,"adding mixed amounts with total prices" ~: do
|
,"adding mixed amounts with total prices" ~: do
|
||||||
(sum $ map (Mixed . (:[]))
|
(sum $ map (Mixed . (:[]))
|
||||||
[usd 1 @@ eur 1
|
[usd 1 @@ eur 1
|
||||||
|
|||||||
@ -43,8 +43,8 @@ commoditysymbols =
|
|||||||
|
|
||||||
-- | Look up one of the sample commodities' symbol by name.
|
-- | Look up one of the sample commodities' symbol by name.
|
||||||
comm :: String -> Commodity
|
comm :: String -> Commodity
|
||||||
comm name = snd $ fromMaybe
|
comm name = snd $ fromMaybe
|
||||||
(error' "commodity lookup failed")
|
(error' "commodity lookup failed")
|
||||||
(find (\n -> fst n == name) commoditysymbols)
|
(find (\n -> fst n == name) commoditysymbols)
|
||||||
|
|
||||||
-- | Find the conversion rate between two commodities. Currently returns 1.
|
-- | Find the conversion rate between two commodities. Currently returns 1.
|
||||||
|
|||||||
@ -153,7 +153,7 @@ spanStart (DateSpan d _) = d
|
|||||||
spanEnd :: DateSpan -> Maybe Day
|
spanEnd :: DateSpan -> Maybe Day
|
||||||
spanEnd (DateSpan _ d) = d
|
spanEnd (DateSpan _ d) = d
|
||||||
|
|
||||||
-- might be useful later: http://en.wikipedia.org/wiki/Allen%27s_interval_algebra
|
-- might be useful later: http://en.wikipedia.org/wiki/Allen%27s_interval_algebra
|
||||||
|
|
||||||
-- | Get overall span enclosing multiple sequentially ordered spans.
|
-- | Get overall span enclosing multiple sequentially ordered spans.
|
||||||
spansSpan :: [DateSpan] -> DateSpan
|
spansSpan :: [DateSpan] -> DateSpan
|
||||||
@ -204,7 +204,7 @@ spanContainsDate (DateSpan Nothing Nothing) _ = True
|
|||||||
spanContainsDate (DateSpan Nothing (Just e)) d = d < e
|
spanContainsDate (DateSpan Nothing (Just e)) d = d < e
|
||||||
spanContainsDate (DateSpan (Just b) Nothing) d = d >= b
|
spanContainsDate (DateSpan (Just b) Nothing) d = d >= b
|
||||||
spanContainsDate (DateSpan (Just b) (Just e)) d = d >= b && d < e
|
spanContainsDate (DateSpan (Just b) (Just e)) d = d >= b && d < e
|
||||||
|
|
||||||
-- | Calculate the intersection of a number of datespans.
|
-- | Calculate the intersection of a number of datespans.
|
||||||
spansIntersect [] = nulldatespan
|
spansIntersect [] = nulldatespan
|
||||||
spansIntersect [d] = d
|
spansIntersect [d] = d
|
||||||
@ -255,7 +255,7 @@ maybePeriod refdate = either (const Nothing) Just . parsePeriodExpr refdate
|
|||||||
-- dateSpanAsText (DateSpan Nothing (Just e)) = printf "to %s" (show e)
|
-- dateSpanAsText (DateSpan Nothing (Just e)) = printf "to %s" (show e)
|
||||||
-- dateSpanAsText (DateSpan (Just b) Nothing) = printf "from %s" (show b)
|
-- dateSpanAsText (DateSpan (Just b) Nothing) = printf "from %s" (show b)
|
||||||
-- dateSpanAsText (DateSpan (Just b) (Just e)) = printf "%s to %s" (show b) (show e)
|
-- dateSpanAsText (DateSpan (Just b) (Just e)) = printf "%s to %s" (show b) (show e)
|
||||||
|
|
||||||
-- | Convert a single smart date string to a date span using the provided
|
-- | Convert a single smart date string to a date span using the provided
|
||||||
-- reference date, or raise an error.
|
-- reference date, or raise an error.
|
||||||
-- spanFromSmartDateString :: Day -> String -> DateSpan
|
-- spanFromSmartDateString :: Day -> String -> DateSpan
|
||||||
@ -400,9 +400,9 @@ nthdayofweekcontaining n d | d1 >= d = d1
|
|||||||
|
|
||||||
-- | Parse a couple of date string formats to a time type.
|
-- | Parse a couple of date string formats to a time type.
|
||||||
parsedateM :: String -> Maybe Day
|
parsedateM :: String -> Maybe Day
|
||||||
parsedateM s = firstJust [
|
parsedateM s = firstJust [
|
||||||
parseTime defaultTimeLocale "%Y/%m/%d" s,
|
parseTime defaultTimeLocale "%Y/%m/%d" s,
|
||||||
parseTime defaultTimeLocale "%Y-%m-%d" s
|
parseTime defaultTimeLocale "%Y-%m-%d" s
|
||||||
]
|
]
|
||||||
|
|
||||||
-- -- | Parse a date-time string to a time type, or raise an error.
|
-- -- | Parse a date-time string to a time type, or raise an error.
|
||||||
@ -420,7 +420,7 @@ parsedate s = fromMaybe (error' $ "could not parse date \"" ++ s ++ "\"")
|
|||||||
parsetimewith :: ParseTime t => String -> String -> t -> t
|
parsetimewith :: ParseTime t => String -> String -> t -> t
|
||||||
parsetimewith pat s def = fromMaybe def $ parseTime defaultTimeLocale pat s
|
parsetimewith pat s def = fromMaybe def $ parseTime defaultTimeLocale pat s
|
||||||
|
|
||||||
{-|
|
{-|
|
||||||
Parse a date in any of the formats allowed in ledger's period expressions,
|
Parse a date in any of the formats allowed in ledger's period expressions,
|
||||||
and maybe some others:
|
and maybe some others:
|
||||||
|
|
||||||
@ -557,7 +557,7 @@ lastthisnextthing = do
|
|||||||
]
|
]
|
||||||
-- XXX support these in fixSmartDate
|
-- XXX support these in fixSmartDate
|
||||||
-- ++ (map string $ months ++ monthabbrevs ++ weekdays ++ weekdayabbrevs)
|
-- ++ (map string $ months ++ monthabbrevs ++ weekdays ++ weekdayabbrevs)
|
||||||
|
|
||||||
return ("",r,p)
|
return ("",r,p)
|
||||||
|
|
||||||
periodexpr :: Day -> GenParser Char st (Interval, DateSpan)
|
periodexpr :: Day -> GenParser Char st (Interval, DateSpan)
|
||||||
|
|||||||
@ -463,7 +463,7 @@ splitAssertions ps
|
|||||||
| otherwise = (ps'++[head rest]):splitAssertions (tail rest)
|
| otherwise = (ps'++[head rest]):splitAssertions (tail rest)
|
||||||
where
|
where
|
||||||
(ps',rest) = break (isJust . pbalanceassertion) ps
|
(ps',rest) = break (isJust . pbalanceassertion) ps
|
||||||
|
|
||||||
-- | Fill in any missing amounts and check that all journal transactions
|
-- | Fill in any missing amounts and check that all journal transactions
|
||||||
-- balance, or return an error message. This is done after parsing all
|
-- balance, or return an error message. This is done after parsing all
|
||||||
-- amounts and working out the canonical commodities, since balancing
|
-- amounts and working out the canonical commodities, since balancing
|
||||||
@ -654,7 +654,7 @@ abspat pat = if isnegativepat pat then drop (length negateprefix) pat else pat
|
|||||||
-- liabilities:debts $1
|
-- liabilities:debts $1
|
||||||
-- assets:bank:checking
|
-- assets:bank:checking
|
||||||
--
|
--
|
||||||
Right samplejournal = journalBalanceTransactions $
|
Right samplejournal = journalBalanceTransactions $
|
||||||
nulljournal
|
nulljournal
|
||||||
{jtxns = [
|
{jtxns = [
|
||||||
txnTieKnot $ Transaction {
|
txnTieKnot $ Transaction {
|
||||||
|
|||||||
@ -122,7 +122,7 @@ sumPostings = sum . map pamount
|
|||||||
-- there is no parent transaction.
|
-- there is no parent transaction.
|
||||||
postingDate :: Posting -> Day
|
postingDate :: Posting -> Day
|
||||||
postingDate p = fromMaybe txndate $ pdate p
|
postingDate p = fromMaybe txndate $ pdate p
|
||||||
where
|
where
|
||||||
txndate = maybe nulldate tdate $ ptransaction p
|
txndate = maybe nulldate tdate $ ptransaction p
|
||||||
|
|
||||||
-- | Get a posting's secondary (secondary) date, which is the first of:
|
-- | Get a posting's secondary (secondary) date, which is the first of:
|
||||||
@ -251,4 +251,4 @@ tests_Hledger_Data_Posting = TestList [
|
|||||||
concatAccountNames ["a","(b)","[c:d]"] `is` "(a:b:c:d)"
|
concatAccountNames ["a","(b)","[c:d]"] `is` "(a:b:c:d)"
|
||||||
|
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|||||||
@ -24,17 +24,17 @@ import Hledger.Data.Amount
|
|||||||
import Hledger.Data.Posting
|
import Hledger.Data.Posting
|
||||||
import Hledger.Data.Transaction
|
import Hledger.Data.Transaction
|
||||||
|
|
||||||
instance Show TimeLogEntry where
|
instance Show TimeLogEntry where
|
||||||
show t = printf "%s %s %s" (show $ tlcode t) (show $ tldatetime t) (tlcomment t)
|
show t = printf "%s %s %s" (show $ tlcode t) (show $ tldatetime t) (tlcomment t)
|
||||||
|
|
||||||
instance Show TimeLogCode where
|
instance Show TimeLogCode where
|
||||||
show SetBalance = "b"
|
show SetBalance = "b"
|
||||||
show SetRequiredHours = "h"
|
show SetRequiredHours = "h"
|
||||||
show In = "i"
|
show In = "i"
|
||||||
show Out = "o"
|
show Out = "o"
|
||||||
show FinalOut = "O"
|
show FinalOut = "O"
|
||||||
|
|
||||||
instance Read TimeLogCode where
|
instance Read TimeLogCode where
|
||||||
readsPrec _ ('b' : xs) = [(SetBalance, xs)]
|
readsPrec _ ('b' : xs) = [(SetBalance, xs)]
|
||||||
readsPrec _ ('h' : xs) = [(SetRequiredHours, xs)]
|
readsPrec _ ('h' : xs) = [(SetRequiredHours, xs)]
|
||||||
readsPrec _ ('i' : xs) = [(In, xs)]
|
readsPrec _ ('i' : xs) = [(In, xs)]
|
||||||
@ -72,7 +72,7 @@ timeLogEntriesToTransactions now (i:o:rest)
|
|||||||
entryFromTimeLogInOut :: TimeLogEntry -> TimeLogEntry -> Transaction
|
entryFromTimeLogInOut :: TimeLogEntry -> TimeLogEntry -> Transaction
|
||||||
entryFromTimeLogInOut i o
|
entryFromTimeLogInOut i o
|
||||||
| otime >= itime = t
|
| otime >= itime = t
|
||||||
| otherwise =
|
| otherwise =
|
||||||
error' $ "clock-out time less than clock-in time in:\n" ++ showTransaction t
|
error' $ "clock-out time less than clock-in time in:\n" ++ showTransaction t
|
||||||
where
|
where
|
||||||
t = Transaction {
|
t = Transaction {
|
||||||
@ -119,8 +119,8 @@ tests_Hledger_Data_TimeLog = TestList [
|
|||||||
assertEntriesGiveStrings "split multi-day sessions at each midnight"
|
assertEntriesGiveStrings "split multi-day sessions at each midnight"
|
||||||
[clockin (mktime (addDays (-2) today) "23:00:00") ""]
|
[clockin (mktime (addDays (-2) today) "23:00:00") ""]
|
||||||
["23:00-23:59","00:00-23:59","00:00-"++nowstr]
|
["23:00-23:59","00:00-23:59","00:00-"++nowstr]
|
||||||
assertEntriesGiveStrings "auto-clock-out if needed"
|
assertEntriesGiveStrings "auto-clock-out if needed"
|
||||||
[clockin (mktime today "00:00:00") ""]
|
[clockin (mktime today "00:00:00") ""]
|
||||||
["00:00-"++nowstr]
|
["00:00-"++nowstr]
|
||||||
let future = utcToLocalTime tz $ addUTCTime 100 now'
|
let future = utcToLocalTime tz $ addUTCTime 100 now'
|
||||||
futurestr = showtime future
|
futurestr = showtime future
|
||||||
|
|||||||
@ -50,10 +50,10 @@ import Hledger.Data.Amount
|
|||||||
|
|
||||||
instance Show Transaction where show = showTransactionUnelided
|
instance Show Transaction where show = showTransactionUnelided
|
||||||
|
|
||||||
instance Show ModifierTransaction where
|
instance Show ModifierTransaction where
|
||||||
show t = "= " ++ mtvalueexpr t ++ "\n" ++ unlines (map show (mtpostings t))
|
show t = "= " ++ mtvalueexpr t ++ "\n" ++ unlines (map show (mtpostings t))
|
||||||
|
|
||||||
instance Show PeriodicTransaction where
|
instance Show PeriodicTransaction where
|
||||||
show t = "~ " ++ ptperiodicexpr t ++ "\n" ++ unlines (map show (ptpostings t))
|
show t = "~ " ++ ptperiodicexpr t ++ "\n" ++ unlines (map show (ptpostings t))
|
||||||
|
|
||||||
nullsourcepos :: SourcePos
|
nullsourcepos :: SourcePos
|
||||||
@ -64,9 +64,9 @@ nulltransaction = Transaction {
|
|||||||
tsourcepos=nullsourcepos,
|
tsourcepos=nullsourcepos,
|
||||||
tdate=nulldate,
|
tdate=nulldate,
|
||||||
tdate2=Nothing,
|
tdate2=Nothing,
|
||||||
tstatus=False,
|
tstatus=False,
|
||||||
tcode="",
|
tcode="",
|
||||||
tdescription="",
|
tdescription="",
|
||||||
tcomment="",
|
tcomment="",
|
||||||
ttags=[],
|
ttags=[],
|
||||||
tpostings=[],
|
tpostings=[],
|
||||||
@ -286,7 +286,7 @@ balanceTransaction styles t@Transaction{tpostings=ps}
|
|||||||
ramounts = map pamount rwithamounts
|
ramounts = map pamount rwithamounts
|
||||||
bvamounts = map pamount bvwithamounts
|
bvamounts = map pamount bvwithamounts
|
||||||
t' = t{tpostings=map inferamount ps}
|
t' = t{tpostings=map inferamount ps}
|
||||||
where
|
where
|
||||||
inferamount p | not (hasAmount p) && isReal p = p{pamount = costOfMixedAmount (- sum ramounts)}
|
inferamount p | not (hasAmount p) && isReal p = p{pamount = costOfMixedAmount (- sum ramounts)}
|
||||||
| not (hasAmount p) && isBalancedVirtual p = p{pamount = costOfMixedAmount (- sum bvamounts)}
|
| not (hasAmount p) && isBalancedVirtual p = p{pamount = costOfMixedAmount (- sum bvamounts)}
|
||||||
| otherwise = p
|
| otherwise = p
|
||||||
|
|||||||
@ -45,7 +45,7 @@ type AccountName = String
|
|||||||
data Side = L | R deriving (Eq,Show,Read,Ord,Typeable,Data)
|
data Side = L | R deriving (Eq,Show,Read,Ord,Typeable,Data)
|
||||||
|
|
||||||
type Commodity = String
|
type Commodity = String
|
||||||
|
|
||||||
type Quantity = Double
|
type Quantity = Double
|
||||||
|
|
||||||
-- | An amount's price (none, per unit, or total) in another commodity.
|
-- | An amount's price (none, per unit, or total) in another commodity.
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
{-# LANGUAGE ScopedTypeVariables #-}
|
{-# LANGUAGE ScopedTypeVariables #-}
|
||||||
{-|
|
{-|
|
||||||
|
|
||||||
This is the entry point to hledger's reading system, which can read
|
This is the entry point to hledger's reading system, which can read
|
||||||
Journals from various data formats. Use this module if you want to parse
|
Journals from various data formats. Use this module if you want to parse
|
||||||
@ -138,7 +138,7 @@ readJournal format rulesfile assrt path s =
|
|||||||
readersFor :: (Maybe StorageFormat, Maybe FilePath, String) -> [Reader]
|
readersFor :: (Maybe StorageFormat, Maybe FilePath, String) -> [Reader]
|
||||||
readersFor (format,path,s) =
|
readersFor (format,path,s) =
|
||||||
dbg ("possible readers for "++show (format,path,elideRight 30 s)) $
|
dbg ("possible readers for "++show (format,path,elideRight 30 s)) $
|
||||||
case format of
|
case format of
|
||||||
Just f -> case readerForStorageFormat f of Just r -> [r]
|
Just f -> case readerForStorageFormat f of Just r -> [r]
|
||||||
Nothing -> []
|
Nothing -> []
|
||||||
Nothing -> case path of Nothing -> readers
|
Nothing -> case path of Nothing -> readers
|
||||||
@ -149,7 +149,7 @@ readersFor (format,path,s) =
|
|||||||
readerForStorageFormat :: StorageFormat -> Maybe Reader
|
readerForStorageFormat :: StorageFormat -> Maybe Reader
|
||||||
readerForStorageFormat s | null rs = Nothing
|
readerForStorageFormat s | null rs = Nothing
|
||||||
| otherwise = Just $ head rs
|
| otherwise = Just $ head rs
|
||||||
where
|
where
|
||||||
rs = filter ((s==).rFormat) readers :: [Reader]
|
rs = filter ((s==).rFormat) readers :: [Reader]
|
||||||
|
|
||||||
-- | Find the readers which think they can handle the given file path and data, if any.
|
-- | Find the readers which think they can handle the given file path and data, if any.
|
||||||
|
|||||||
@ -154,7 +154,7 @@ journal = do
|
|||||||
eof
|
eof
|
||||||
finalctx <- getState
|
finalctx <- getState
|
||||||
return $ (combineJournalUpdates journalupdates, finalctx)
|
return $ (combineJournalUpdates journalupdates, finalctx)
|
||||||
where
|
where
|
||||||
-- As all journal line types can be distinguished by the first
|
-- As all journal line types can be distinguished by the first
|
||||||
-- character, excepting transactions versus empty (blank or
|
-- character, excepting transactions versus empty (blank or
|
||||||
-- comment-only) lines, can use choice w/o try
|
-- comment-only) lines, can use choice w/o try
|
||||||
@ -354,7 +354,7 @@ test_transaction = do
|
|||||||
assertEqual (ttags t) (ttags t2)
|
assertEqual (ttags t) (ttags t2)
|
||||||
assertEqual (tpreceding_comment_lines t) (tpreceding_comment_lines t2)
|
assertEqual (tpreceding_comment_lines t) (tpreceding_comment_lines t2)
|
||||||
assertEqual (show $ tpostings t) (show $ tpostings t2)
|
assertEqual (show $ tpostings t) (show $ tpostings t2)
|
||||||
-- "0000/01/01\n\n" `gives` nulltransaction
|
-- "0000/01/01\n\n" `gives` nulltransaction
|
||||||
unlines [
|
unlines [
|
||||||
"2012/05/14=2012/05/15 (code) desc ; tcomment1",
|
"2012/05/14=2012/05/15 (code) desc ; tcomment1",
|
||||||
" ; tcomment2",
|
" ; tcomment2",
|
||||||
@ -412,7 +412,7 @@ test_transaction = do
|
|||||||
," b"
|
," b"
|
||||||
," "
|
," "
|
||||||
]
|
]
|
||||||
|
|
||||||
let p = parseWithCtx nullctx transaction $ unlines
|
let p = parseWithCtx nullctx transaction $ unlines
|
||||||
["2009/1/1 x ; transaction comment"
|
["2009/1/1 x ; transaction comment"
|
||||||
," a 1 ; posting 1 comment"
|
," a 1 ; posting 1 comment"
|
||||||
@ -422,7 +422,7 @@ test_transaction = do
|
|||||||
]
|
]
|
||||||
assertRight p
|
assertRight p
|
||||||
assertEqual 2 (let Right t = p in length $ tpostings t)
|
assertEqual 2 (let Right t = p in length $ tpostings t)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
-- | Parse a date in YYYY/MM/DD format. Fewer digits are allowed. The year
|
-- | Parse a date in YYYY/MM/DD format. Fewer digits are allowed. The year
|
||||||
-- may be omitted if a default year has already been set.
|
-- may be omitted if a default year has already been set.
|
||||||
@ -501,7 +501,7 @@ codep = try (do { many1 spacenonewline; char '(' <?> "codep"; code <- anyChar `m
|
|||||||
-- Parse the following whitespace-beginning lines as postings, posting tags, and/or comments.
|
-- Parse the following whitespace-beginning lines as postings, posting tags, and/or comments.
|
||||||
postings :: GenParser Char JournalContext [Posting]
|
postings :: GenParser Char JournalContext [Posting]
|
||||||
postings = many1 (try postingp) <?> "postings"
|
postings = many1 (try postingp) <?> "postings"
|
||||||
|
|
||||||
-- linebeginningwithspaces :: GenParser Char JournalContext String
|
-- linebeginningwithspaces :: GenParser Char JournalContext String
|
||||||
-- linebeginningwithspaces = do
|
-- linebeginningwithspaces = do
|
||||||
-- sp <- many1 spacenonewline
|
-- sp <- many1 spacenonewline
|
||||||
@ -532,7 +532,7 @@ postingp = do
|
|||||||
test_postingp = do
|
test_postingp = do
|
||||||
let s `gives` ep = do
|
let s `gives` ep = do
|
||||||
let parse = parseWithCtx nullctx postingp s
|
let parse = parseWithCtx nullctx postingp s
|
||||||
assertBool -- "postingp parser"
|
assertBool -- "postingp parser"
|
||||||
$ isRight parse
|
$ isRight parse
|
||||||
let Right ap = parse
|
let Right ap = parse
|
||||||
same f = assertEqual (f ep) (f ap)
|
same f = assertEqual (f ep) (f ap)
|
||||||
@ -547,21 +547,21 @@ test_postingp = do
|
|||||||
" expenses:food:dining $10.00 ; a: a a \n ; b: b b \n" `gives`
|
" expenses:food:dining $10.00 ; a: a a \n ; b: b b \n" `gives`
|
||||||
posting{paccount="expenses:food:dining", pamount=Mixed [usd 10], pcomment=" a: a a \n b: b b \n", ptags=[("a","a a"), ("b","b b")]}
|
posting{paccount="expenses:food:dining", pamount=Mixed [usd 10], pcomment=" a: a a \n b: b b \n", ptags=[("a","a a"), ("b","b b")]}
|
||||||
|
|
||||||
" a 1 ; [2012/11/28]\n" `gives`
|
" a 1 ; [2012/11/28]\n" `gives`
|
||||||
("a" `post` num 1){pcomment=" [2012/11/28]\n"
|
("a" `post` num 1){pcomment=" [2012/11/28]\n"
|
||||||
,ptags=[("date","2012/11/28")]
|
,ptags=[("date","2012/11/28")]
|
||||||
,pdate=parsedateM "2012/11/28"}
|
,pdate=parsedateM "2012/11/28"}
|
||||||
|
|
||||||
" a 1 ; a:a, [=2012/11/28]\n" `gives`
|
" a 1 ; a:a, [=2012/11/28]\n" `gives`
|
||||||
("a" `post` num 1){pcomment=" a:a, [=2012/11/28]\n"
|
("a" `post` num 1){pcomment=" a:a, [=2012/11/28]\n"
|
||||||
,ptags=[("a","a"), ("date2","2012/11/28")]
|
,ptags=[("a","a"), ("date2","2012/11/28")]
|
||||||
,pdate=Nothing}
|
,pdate=Nothing}
|
||||||
|
|
||||||
" a 1 ; a:a\n ; [2012/11/28=2012/11/29],b:b\n" `gives`
|
" a 1 ; a:a\n ; [2012/11/28=2012/11/29],b:b\n" `gives`
|
||||||
("a" `post` num 1){pcomment=" a:a\n [2012/11/28=2012/11/29],b:b\n"
|
("a" `post` num 1){pcomment=" a:a\n [2012/11/28=2012/11/29],b:b\n"
|
||||||
,ptags=[("a","a"), ("date","2012/11/28"), ("date2","2012/11/29"), ("b","b")]
|
,ptags=[("a","a"), ("date","2012/11/28"), ("date2","2012/11/29"), ("b","b")]
|
||||||
,pdate=parsedateM "2012/11/28"}
|
,pdate=parsedateM "2012/11/28"}
|
||||||
|
|
||||||
assertBool -- "postingp parses a quoted commodity with numbers"
|
assertBool -- "postingp parses a quoted commodity with numbers"
|
||||||
(isRight $ parseWithCtx nullctx postingp " a 1 \"DE123\"\n")
|
(isRight $ parseWithCtx nullctx postingp " a 1 \"DE123\"\n")
|
||||||
|
|
||||||
@ -573,7 +573,7 @@ test_postingp = do
|
|||||||
-- let Right p = parse
|
-- let Right p = parse
|
||||||
-- assertEqual "next-line comment\n" (pcomment p)
|
-- assertEqual "next-line comment\n" (pcomment p)
|
||||||
-- assertEqual (Just nullmixedamt) (pbalanceassertion p)
|
-- assertEqual (Just nullmixedamt) (pbalanceassertion p)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
-- | Parse an account name, then apply any parent account prefix and/or account aliases currently in effect.
|
-- | Parse an account name, then apply any parent account prefix and/or account aliases currently in effect.
|
||||||
modifiedaccountname :: GenParser Char JournalContext AccountName
|
modifiedaccountname :: GenParser Char JournalContext AccountName
|
||||||
@ -595,7 +595,7 @@ accountnamep = do
|
|||||||
when (accountNameFromComponents (accountNameComponents a') /= a')
|
when (accountNameFromComponents (accountNameComponents a') /= a')
|
||||||
(fail $ "account name seems ill-formed: "++a')
|
(fail $ "account name seems ill-formed: "++a')
|
||||||
return a'
|
return a'
|
||||||
where
|
where
|
||||||
singlespace = try (do {spacenonewline; do {notFollowedBy spacenonewline; return ' '}})
|
singlespace = try (do {spacenonewline; do {notFollowedBy spacenonewline; return ' '}})
|
||||||
-- couldn't avoid consuming a final space sometimes, harmless
|
-- couldn't avoid consuming a final space sometimes, harmless
|
||||||
striptrailingspace s = if last s == ' ' then init s else s
|
striptrailingspace s = if last s == ' ' then init s else s
|
||||||
@ -625,7 +625,7 @@ test_spaceandamountormissing = do
|
|||||||
assertParseEqual' (parseWithCtx nullctx spaceandamountormissing "$47.18") missingmixedamt
|
assertParseEqual' (parseWithCtx nullctx spaceandamountormissing "$47.18") missingmixedamt
|
||||||
assertParseEqual' (parseWithCtx nullctx spaceandamountormissing " ") missingmixedamt
|
assertParseEqual' (parseWithCtx nullctx spaceandamountormissing " ") missingmixedamt
|
||||||
assertParseEqual' (parseWithCtx nullctx spaceandamountormissing "") missingmixedamt
|
assertParseEqual' (parseWithCtx nullctx spaceandamountormissing "") missingmixedamt
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
-- | Parse a single-commodity amount, with optional symbol on the left or
|
-- | Parse a single-commodity amount, with optional symbol on the left or
|
||||||
-- right, optional unit or total price, and optional (ignored)
|
-- right, optional unit or total price, and optional (ignored)
|
||||||
@ -645,7 +645,7 @@ test_amountp = do
|
|||||||
assertParseEqual'
|
assertParseEqual'
|
||||||
(parseWithCtx nullctx amountp "$10 @@ €5")
|
(parseWithCtx nullctx amountp "$10 @@ €5")
|
||||||
(usd 10 `withPrecision` 0 @@ (eur 5 `withPrecision` 0))
|
(usd 10 `withPrecision` 0 @@ (eur 5 `withPrecision` 0))
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
-- | Parse an amount from a string, or get an error.
|
-- | Parse an amount from a string, or get an error.
|
||||||
amountp' :: String -> Amount
|
amountp' :: String -> Amount
|
||||||
@ -664,7 +664,7 @@ signp = do
|
|||||||
leftsymbolamount :: GenParser Char JournalContext Amount
|
leftsymbolamount :: GenParser Char JournalContext Amount
|
||||||
leftsymbolamount = do
|
leftsymbolamount = do
|
||||||
sign <- signp
|
sign <- signp
|
||||||
c <- commoditysymbol
|
c <- commoditysymbol
|
||||||
sp <- many spacenonewline
|
sp <- many spacenonewline
|
||||||
(q,prec,mdec,mgrps) <- numberp
|
(q,prec,mdec,mgrps) <- numberp
|
||||||
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}
|
||||||
@ -761,16 +761,16 @@ fixedlotprice =
|
|||||||
|
|
||||||
-- | Parse a string representation of a number for its value and display
|
-- | Parse a string representation of a number for its value and display
|
||||||
-- attributes.
|
-- attributes.
|
||||||
--
|
--
|
||||||
-- Some international number formats are accepted, eg either period or comma
|
-- Some international number formats are accepted, eg either period or comma
|
||||||
-- may be used for the decimal point, and the other of these may be used for
|
-- may be used for the decimal point, and the other of these may be used for
|
||||||
-- separating digit groups in the integer part. See
|
-- separating digit groups in the integer part. See
|
||||||
-- http://en.wikipedia.org/wiki/Decimal_separator for more examples.
|
-- http://en.wikipedia.org/wiki/Decimal_separator for more examples.
|
||||||
--
|
--
|
||||||
-- This returns: the parsed numeric value, the precision (number of digits
|
-- This returns: the parsed numeric value, the precision (number of digits
|
||||||
-- 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 :: GenParser Char JournalContext (Quantity, Int, Maybe Char, Maybe DigitGroupStyle)
|
numberp :: GenParser Char JournalContext (Quantity, Int, Maybe Char, Maybe DigitGroupStyle)
|
||||||
numberp = do
|
numberp = 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
|
||||||
@ -820,11 +820,11 @@ numberp = do
|
|||||||
<?> "numberp"
|
<?> "numberp"
|
||||||
where
|
where
|
||||||
numeric = isNumber . headDef '_'
|
numeric = isNumber . headDef '_'
|
||||||
|
|
||||||
#ifdef TESTS
|
#ifdef TESTS
|
||||||
test_numberp = do
|
test_numberp = do
|
||||||
let s `is` n = assertParseEqual' (parseWithCtx nullctx numberp s) n
|
let s `is` n = assertParseEqual' (parseWithCtx nullctx numberp s) n
|
||||||
assertFails = assertBool . isLeft . parseWithCtx nullctx numberp
|
assertFails = assertBool . isLeft . parseWithCtx nullctx numberp
|
||||||
assertFails ""
|
assertFails ""
|
||||||
"0" `is` (0, 0, '.', ',', [])
|
"0" `is` (0, 0, '.', ',', [])
|
||||||
"1" `is` (1, 0, '.', ',', [])
|
"1" `is` (1, 0, '.', ',', [])
|
||||||
@ -843,7 +843,7 @@ test_numberp = do
|
|||||||
assertFails "1..1"
|
assertFails "1..1"
|
||||||
assertFails ".1,"
|
assertFails ".1,"
|
||||||
assertFails ",1."
|
assertFails ",1."
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
-- comment parsers
|
-- comment parsers
|
||||||
|
|
||||||
@ -878,7 +878,7 @@ tagsInComment :: String -> [Tag]
|
|||||||
tagsInComment c = concatMap tagsInCommentLine $ lines c'
|
tagsInComment c = concatMap tagsInCommentLine $ lines c'
|
||||||
where
|
where
|
||||||
c' = ledgerDateSyntaxToTags c
|
c' = ledgerDateSyntaxToTags c
|
||||||
|
|
||||||
tagsInCommentLine :: String -> [Tag]
|
tagsInCommentLine :: String -> [Tag]
|
||||||
tagsInCommentLine = catMaybes . map maybetag . map strip . splitAtElement ','
|
tagsInCommentLine = catMaybes . map maybetag . map strip . splitAtElement ','
|
||||||
where
|
where
|
||||||
@ -913,7 +913,7 @@ ledgerDateSyntaxToTags = regexReplaceBy "\\[[-.\\/0-9=]+\\]" replace
|
|||||||
replace' ('=':s) | isdate s = date2tag s
|
replace' ('=':s) | isdate s = date2tag s
|
||||||
replace' s | last s =='=' && isdate (init s) = datetag (init s)
|
replace' s | last s =='=' && isdate (init s) = datetag (init s)
|
||||||
replace' s | length ds == 2 && isdate d1 && isdate d1 = datetag d1 ++ date2tag d2
|
replace' s | length ds == 2 && isdate d1 && isdate d1 = datetag d1 ++ date2tag d2
|
||||||
where
|
where
|
||||||
ds = splitAtElement '=' s
|
ds = splitAtElement '=' s
|
||||||
d1 = headDef "" ds
|
d1 = headDef "" ds
|
||||||
d2 = lastDef "" ds
|
d2 = lastDef "" ds
|
||||||
@ -922,17 +922,17 @@ ledgerDateSyntaxToTags = regexReplaceBy "\\[[-.\\/0-9=]+\\]" replace
|
|||||||
isdate = isJust . parsedateM
|
isdate = isJust . parsedateM
|
||||||
datetag s = "date:"++s++", "
|
datetag s = "date:"++s++", "
|
||||||
date2tag s = "date2:"++s++", "
|
date2tag s = "date2:"++s++", "
|
||||||
|
|
||||||
#ifdef TESTS
|
#ifdef TESTS
|
||||||
test_ledgerDateSyntaxToTags = do
|
test_ledgerDateSyntaxToTags = do
|
||||||
assertEqual "date2:2012/11/28, " $ ledgerDateSyntaxToTags "[=2012/11/28]"
|
assertEqual "date2:2012/11/28, " $ ledgerDateSyntaxToTags "[=2012/11/28]"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
dateValueFromTags, date2ValueFromTags :: [Tag] -> Maybe String
|
dateValueFromTags, date2ValueFromTags :: [Tag] -> Maybe String
|
||||||
dateValueFromTags ts = maybe Nothing (Just . snd) $ find ((=="date") . fst) ts
|
dateValueFromTags ts = maybe Nothing (Just . snd) $ find ((=="date") . fst) ts
|
||||||
date2ValueFromTags ts = maybe Nothing (Just . snd) $ find ((=="date2") . fst) ts
|
date2ValueFromTags ts = maybe Nothing (Just . snd) $ find ((=="date2") . fst) ts
|
||||||
|
|
||||||
|
|
||||||
{- old hunit tests
|
{- old hunit tests
|
||||||
|
|
||||||
test_Hledger_Read_JournalReader = TestList $ concat [
|
test_Hledger_Read_JournalReader = TestList $ concat [
|
||||||
|
|||||||
@ -86,7 +86,7 @@ timelogFile = do items <- many timelogItem
|
|||||||
eof
|
eof
|
||||||
ctx <- getState
|
ctx <- getState
|
||||||
return (liftM (foldr (.) id) $ sequence items, ctx)
|
return (liftM (foldr (.) id) $ sequence items, ctx)
|
||||||
where
|
where
|
||||||
-- As all ledger line types can be distinguished by the first
|
-- As all ledger line types can be distinguished by the first
|
||||||
-- character, excepting transactions versus empty (blank or
|
-- character, excepting transactions versus empty (blank or
|
||||||
-- comment-only) lines, can use choice w/o try
|
-- comment-only) lines, can use choice w/o try
|
||||||
|
|||||||
@ -39,9 +39,9 @@ type BalanceReportItem = (RenderableAccountName, MixedAmount)
|
|||||||
-- It has:
|
-- It has:
|
||||||
--
|
--
|
||||||
-- * The full account name
|
-- * The full account name
|
||||||
--
|
--
|
||||||
-- * The ledger-style short elided account name (the leaf name, prefixed by any boring parents immediately above)
|
-- * The ledger-style short elided account name (the leaf name, prefixed by any boring parents immediately above)
|
||||||
--
|
--
|
||||||
-- * The number of indentation steps to use when rendering a ledger-style account tree
|
-- * The number of indentation steps to use when rendering a ledger-style account tree
|
||||||
-- (normally the 0-based depth of this account excluding boring parents, or 0 with --flat).
|
-- (normally the 0-based depth of this account excluding boring parents, or 0 with --flat).
|
||||||
type RenderableAccountName = (AccountName, AccountName, Int)
|
type RenderableAccountName = (AccountName, AccountName, Int)
|
||||||
@ -67,14 +67,14 @@ balanceReport opts q j = (items, total)
|
|||||||
|
|
||||||
accts = ledgerRootAccount $ ledgerFromJournal q $ journalSelectingAmountFromOpts opts j
|
accts = ledgerRootAccount $ ledgerFromJournal q $ journalSelectingAmountFromOpts opts j
|
||||||
accts' :: [Account]
|
accts' :: [Account]
|
||||||
| flat_ opts = dbg "accts" $
|
| flat_ opts = dbg "accts" $
|
||||||
filterzeros $
|
filterzeros $
|
||||||
filterempty $
|
filterempty $
|
||||||
drop 1 $ clipAccountsAndAggregate (queryDepth q) $ flattenAccounts accts
|
drop 1 $ clipAccountsAndAggregate (queryDepth q) $ flattenAccounts accts
|
||||||
| otherwise = dbg "accts" $
|
| otherwise = dbg "accts" $
|
||||||
filter (not.aboring) $
|
filter (not.aboring) $
|
||||||
drop 1 $ flattenAccounts $
|
drop 1 $ flattenAccounts $
|
||||||
markboring $
|
markboring $
|
||||||
prunezeros $ clipAccounts (queryDepth q) accts
|
prunezeros $ clipAccounts (queryDepth q) accts
|
||||||
where
|
where
|
||||||
balance = if flat_ opts then aebalance else aibalance
|
balance = if flat_ opts then aebalance else aibalance
|
||||||
@ -247,7 +247,7 @@ tests_balanceReport =
|
|||||||
," 0"
|
," 0"
|
||||||
]
|
]
|
||||||
|
|
||||||
,"accounts report with unmatched parent of two matched subaccounts" ~:
|
,"accounts report with unmatched parent of two matched subaccounts" ~:
|
||||||
defreportopts{patterns_=["cash","saving"]} `gives`
|
defreportopts{patterns_=["cash","saving"]} `gives`
|
||||||
[" $-1 assets"
|
[" $-1 assets"
|
||||||
," $1 bank:saving"
|
," $1 bank:saving"
|
||||||
@ -256,7 +256,7 @@ tests_balanceReport =
|
|||||||
," $-1"
|
," $-1"
|
||||||
]
|
]
|
||||||
|
|
||||||
,"accounts report with multi-part account name" ~:
|
,"accounts report with multi-part account name" ~:
|
||||||
defreportopts{patterns_=["expenses:food"]} `gives`
|
defreportopts{patterns_=["expenses:food"]} `gives`
|
||||||
[" $1 expenses:food"
|
[" $1 expenses:food"
|
||||||
,"--------------------"
|
,"--------------------"
|
||||||
@ -276,13 +276,13 @@ tests_balanceReport =
|
|||||||
," $1"
|
," $1"
|
||||||
]
|
]
|
||||||
|
|
||||||
,"accounts report negative account pattern always matches full name" ~:
|
,"accounts report negative account pattern always matches full name" ~:
|
||||||
defreportopts{patterns_=["not:e"]} `gives`
|
defreportopts{patterns_=["not:e"]} `gives`
|
||||||
["--------------------"
|
["--------------------"
|
||||||
," 0"
|
," 0"
|
||||||
]
|
]
|
||||||
|
|
||||||
,"accounts report negative patterns affect totals" ~:
|
,"accounts report negative patterns affect totals" ~:
|
||||||
defreportopts{patterns_=["expenses","not:food"]} `gives`
|
defreportopts{patterns_=["expenses","not:food"]} `gives`
|
||||||
[" $1 expenses:supplies"
|
[" $1 expenses:supplies"
|
||||||
,"--------------------"
|
,"--------------------"
|
||||||
@ -317,7 +317,7 @@ tests_balanceReport =
|
|||||||
-}
|
-}
|
||||||
]
|
]
|
||||||
|
|
||||||
Right samplejournal2 = journalBalanceTransactions $
|
Right samplejournal2 = journalBalanceTransactions $
|
||||||
nulljournal
|
nulljournal
|
||||||
{jtxns = [
|
{jtxns = [
|
||||||
txnTieKnot $ Transaction {
|
txnTieKnot $ Transaction {
|
||||||
@ -337,12 +337,12 @@ Right samplejournal2 = journalBalanceTransactions $
|
|||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
-- tests_isInterestingIndented = [
|
-- tests_isInterestingIndented = [
|
||||||
-- "isInterestingIndented" ~: do
|
-- "isInterestingIndented" ~: do
|
||||||
-- let (opts, journal, acctname) `gives` r = isInterestingIndented opts l acctname `is` r
|
-- let (opts, journal, acctname) `gives` r = isInterestingIndented opts l acctname `is` r
|
||||||
-- where l = ledgerFromJournal (queryFromOpts nulldate opts) journal
|
-- where l = ledgerFromJournal (queryFromOpts nulldate opts) journal
|
||||||
|
|
||||||
-- (defreportopts, samplejournal, "expenses") `gives` True
|
-- (defreportopts, samplejournal, "expenses") `gives` True
|
||||||
-- ]
|
-- ]
|
||||||
|
|
||||||
|
|||||||
@ -107,7 +107,7 @@ multiBalanceReport opts q j = MultiBalanceReport (displayspans, items, totals)
|
|||||||
postingAcctBals :: [Posting] -> [(ClippedAccountName, MixedAmount)]
|
postingAcctBals :: [Posting] -> [(ClippedAccountName, MixedAmount)]
|
||||||
postingAcctBals ps = [(aname a, (if tree_ opts then aibalance else aebalance) a) | a <- as]
|
postingAcctBals ps = [(aname a, (if tree_ opts then aibalance else aebalance) a) | a <- as]
|
||||||
where
|
where
|
||||||
as = depthLimit $
|
as = depthLimit $
|
||||||
(if tree_ opts then id else filter ((>0).anumpostings)) $
|
(if tree_ opts then id else filter ((>0).anumpostings)) $
|
||||||
drop 1 $ accountsFromPostings ps
|
drop 1 $ accountsFromPostings ps
|
||||||
depthLimit
|
depthLimit
|
||||||
|
|||||||
@ -70,7 +70,7 @@ postingsReport opts q j = (totallabel, items)
|
|||||||
beforeendq = dbg "beforeendq" $ dateqcons $ DateSpan Nothing reportend
|
beforeendq = dbg "beforeendq" $ dateqcons $ DateSpan Nothing reportend
|
||||||
reportq = dbg "reportq" $ depthless $ And [datelessq, beforeendq] -- user's query with no start date, end date on an interval boundary and no depth limit
|
reportq = dbg "reportq" $ depthless $ And [datelessq, beforeendq] -- user's query with no start date, end date on an interval boundary and no depth limit
|
||||||
|
|
||||||
pstoend =
|
pstoend =
|
||||||
dbg "ps4" $ sortBy (comparing pdate) $ -- sort postings by date (or date2)
|
dbg "ps4" $ sortBy (comparing pdate) $ -- sort postings by date (or date2)
|
||||||
dbg "ps3" $ map (filterPostingAmount symq) $ -- remove amount parts which the query's cur: terms would exclude
|
dbg "ps3" $ map (filterPostingAmount symq) $ -- remove amount parts which the query's cur: terms would exclude
|
||||||
dbg "ps2" $ (if related_ opts then concatMap relatedPostings else id) $ -- with -r, replace each with its sibling postings
|
dbg "ps2" $ (if related_ opts then concatMap relatedPostings else id) $ -- with -r, replace each with its sibling postings
|
||||||
@ -172,7 +172,7 @@ summarisePostingsInDateSpan (DateSpan b e) wd depth showempty ps
|
|||||||
anames = sort $ nub $ map paccount ps
|
anames = sort $ nub $ map paccount ps
|
||||||
-- aggregate balances by account, like ledgerFromJournal, then do depth-clipping
|
-- aggregate balances by account, like ledgerFromJournal, then do depth-clipping
|
||||||
accts = accountsFromPostings ps
|
accts = accountsFromPostings ps
|
||||||
balance a = maybe nullmixedamt bal $ lookupAccount a accts
|
balance a = maybe nullmixedamt bal $ lookupAccount a accts
|
||||||
where
|
where
|
||||||
bal = if isclipped a then aibalance else aebalance
|
bal = if isclipped a then aibalance else aebalance
|
||||||
isclipped a = accountNameLevel a >= depth
|
isclipped a = accountNameLevel a >= depth
|
||||||
@ -262,7 +262,7 @@ tests_postingsReport = [
|
|||||||
]
|
]
|
||||||
|
|
||||||
,"postings report with cleared option" ~:
|
,"postings report with cleared option" ~:
|
||||||
do
|
do
|
||||||
let opts = defreportopts{cleared_=True}
|
let opts = defreportopts{cleared_=True}
|
||||||
j <- readJournal' sample_journal_str
|
j <- readJournal' sample_journal_str
|
||||||
(postingsReportAsText opts $ postingsReport opts (queryFromOpts date1 opts) j) `is` unlines
|
(postingsReportAsText opts $ postingsReport opts (queryFromOpts date1 opts) j) `is` unlines
|
||||||
@ -274,7 +274,7 @@ tests_postingsReport = [
|
|||||||
]
|
]
|
||||||
|
|
||||||
,"postings report with uncleared option" ~:
|
,"postings report with uncleared option" ~:
|
||||||
do
|
do
|
||||||
let opts = defreportopts{uncleared_=True}
|
let opts = defreportopts{uncleared_=True}
|
||||||
j <- readJournal' sample_journal_str
|
j <- readJournal' sample_journal_str
|
||||||
(postingsReportAsText opts $ postingsReport opts (queryFromOpts date1 opts) j) `is` unlines
|
(postingsReportAsText opts $ postingsReport opts (queryFromOpts date1 opts) j) `is` unlines
|
||||||
@ -287,7 +287,7 @@ tests_postingsReport = [
|
|||||||
]
|
]
|
||||||
|
|
||||||
,"postings report sorts by date" ~:
|
,"postings report sorts by date" ~:
|
||||||
do
|
do
|
||||||
j <- readJournal' $ unlines
|
j <- readJournal' $ unlines
|
||||||
["2008/02/02 a"
|
["2008/02/02 a"
|
||||||
," b 1"
|
," b 1"
|
||||||
@ -309,7 +309,7 @@ tests_postingsReport = [
|
|||||||
]
|
]
|
||||||
|
|
||||||
,"postings report with account pattern, case insensitive" ~:
|
,"postings report with account pattern, case insensitive" ~:
|
||||||
do
|
do
|
||||||
j <- samplejournal
|
j <- samplejournal
|
||||||
let opts = defreportopts{patterns_=["cAsH"]}
|
let opts = defreportopts{patterns_=["cAsH"]}
|
||||||
(postingsReportAsText opts $ postingsReport opts (queryFromOpts date1 opts) j) `is` unlines
|
(postingsReportAsText opts $ postingsReport opts (queryFromOpts date1 opts) j) `is` unlines
|
||||||
@ -317,9 +317,9 @@ tests_postingsReport = [
|
|||||||
]
|
]
|
||||||
|
|
||||||
,"postings report with display expression" ~:
|
,"postings report with display expression" ~:
|
||||||
do
|
do
|
||||||
j <- samplejournal
|
j <- samplejournal
|
||||||
let gives displayexpr =
|
let gives displayexpr =
|
||||||
(registerdates (postingsReportAsText opts $ postingsReport opts (queryFromOpts date1 opts) j) `is`)
|
(registerdates (postingsReportAsText opts $ postingsReport opts (queryFromOpts date1 opts) j) `is`)
|
||||||
where opts = defreportopts{display_=Just displayexpr}
|
where opts = defreportopts{display_=Just displayexpr}
|
||||||
"d<[2008/6/2]" `gives` ["2008/01/01","2008/06/01"]
|
"d<[2008/6/2]" `gives` ["2008/01/01","2008/06/01"]
|
||||||
@ -329,7 +329,7 @@ tests_postingsReport = [
|
|||||||
"d>[2008/6/2]" `gives` ["2008/06/03","2008/12/31"]
|
"d>[2008/6/2]" `gives` ["2008/06/03","2008/12/31"]
|
||||||
|
|
||||||
,"postings report with period expression" ~:
|
,"postings report with period expression" ~:
|
||||||
do
|
do
|
||||||
j <- samplejournal
|
j <- samplejournal
|
||||||
let periodexpr `gives` dates = do
|
let periodexpr `gives` dates = do
|
||||||
j' <- samplejournal
|
j' <- samplejournal
|
||||||
@ -359,7 +359,7 @@ tests_postingsReport = [
|
|||||||
]
|
]
|
||||||
|
|
||||||
, "postings report with depth arg" ~:
|
, "postings report with depth arg" ~:
|
||||||
do
|
do
|
||||||
j <- samplejournal
|
j <- samplejournal
|
||||||
let opts = defreportopts{depth_=Just 2}
|
let opts = defreportopts{depth_=Just 2}
|
||||||
(postingsReportAsText opts $ postingsReport opts (queryFromOpts date1 opts) j) `is` unlines
|
(postingsReportAsText opts $ postingsReport opts (queryFromOpts date1 opts) j) `is` unlines
|
||||||
|
|||||||
@ -120,7 +120,7 @@ accountTransactionsReport opts j q thisacctquery = (label, items)
|
|||||||
ts3 = map (setTransactionDateToPostingDate q thisacctquery) ts2
|
ts3 = map (setTransactionDateToPostingDate q thisacctquery) ts2
|
||||||
-- and sorted
|
-- and sorted
|
||||||
ts = sortBy (comparing tdate) ts3
|
ts = sortBy (comparing tdate) ts3
|
||||||
|
|
||||||
-- starting balance: if we are filtering by a start date and nothing else,
|
-- starting balance: if we are filtering by a start date and nothing else,
|
||||||
-- the sum of postings to this account before that date; otherwise zero.
|
-- the sum of postings to this account before that date; otherwise zero.
|
||||||
(startbal,label) | queryIsNull q = (nullmixedamt, balancelabel)
|
(startbal,label) | queryIsNull q = (nullmixedamt, balancelabel)
|
||||||
|
|||||||
@ -251,7 +251,7 @@ difforzero a b = maximum [(a - b), 0]
|
|||||||
-- lists
|
-- lists
|
||||||
|
|
||||||
splitAtElement :: Eq a => a -> [a] -> [[a]]
|
splitAtElement :: Eq a => a -> [a] -> [[a]]
|
||||||
splitAtElement e l =
|
splitAtElement e l =
|
||||||
case dropWhile (e==) l of
|
case dropWhile (e==) l of
|
||||||
[] -> []
|
[] -> []
|
||||||
l' -> first : splitAtElement e rest
|
l' -> first : splitAtElement e rest
|
||||||
@ -285,7 +285,7 @@ subtreeinforest _ [] = Nothing
|
|||||||
subtreeinforest v (t:ts) = case (subtreeat v t) of
|
subtreeinforest v (t:ts) = case (subtreeat v t) of
|
||||||
Just t' -> Just t'
|
Just t' -> Just t'
|
||||||
Nothing -> subtreeinforest v ts
|
Nothing -> subtreeinforest v ts
|
||||||
|
|
||||||
-- | remove all nodes past a certain depth
|
-- | remove all nodes past a certain depth
|
||||||
treeprune :: Int -> Tree a -> Tree a
|
treeprune :: Int -> Tree a -> Tree a
|
||||||
treeprune 0 t = Node (root t) []
|
treeprune 0 t = Node (root t) []
|
||||||
@ -297,15 +297,15 @@ treemap f t = Node (f $ root t) (map (treemap f) $ branches t)
|
|||||||
|
|
||||||
-- | remove all subtrees whose nodes do not fulfill predicate
|
-- | remove all subtrees whose nodes do not fulfill predicate
|
||||||
treefilter :: (a -> Bool) -> Tree a -> Tree a
|
treefilter :: (a -> Bool) -> Tree a -> Tree a
|
||||||
treefilter f t = Node
|
treefilter f t = Node
|
||||||
(root t)
|
(root t)
|
||||||
(map (treefilter f) $ filter (treeany f) $ branches t)
|
(map (treefilter f) $ filter (treeany f) $ branches t)
|
||||||
|
|
||||||
-- | is predicate true in any node of tree ?
|
-- | is predicate true in any node of tree ?
|
||||||
treeany :: (a -> Bool) -> Tree a -> Bool
|
treeany :: (a -> Bool) -> Tree a -> Bool
|
||||||
treeany f t = f (root t) || any (treeany f) (branches t)
|
treeany f t = f (root t) || any (treeany f) (branches t)
|
||||||
|
|
||||||
-- treedrop -- remove the leaves which do fulfill predicate.
|
-- treedrop -- remove the leaves which do fulfill predicate.
|
||||||
-- treedropall -- do this repeatedly.
|
-- treedropall -- do this repeatedly.
|
||||||
|
|
||||||
-- | show a compact ascii representation of a tree
|
-- | show a compact ascii representation of a tree
|
||||||
@ -605,7 +605,7 @@ applyN :: Int -> (a -> a) -> a -> a
|
|||||||
applyN n f = (!! n) . iterate f
|
applyN n f = (!! n) . iterate f
|
||||||
|
|
||||||
-- | Convert a possibly relative, possibly tilde-containing file path to an absolute one,
|
-- | Convert a possibly relative, possibly tilde-containing file path to an absolute one,
|
||||||
-- given the current directory. ~username is not supported. Leave "-" unchanged.
|
-- given the current directory. ~username is not supported. Leave "-" unchanged.
|
||||||
expandPath :: MonadIO m => FilePath -> FilePath -> m FilePath -- general type sig for use in reader parsers
|
expandPath :: MonadIO m => FilePath -> FilePath -> m FilePath -- general type sig for use in reader parsers
|
||||||
expandPath _ "-" = return "-"
|
expandPath _ "-" = return "-"
|
||||||
expandPath curdir p = (if isRelative p then (curdir </>) else id) `liftM` expandPath' p
|
expandPath curdir p = (if isRelative p then (curdir </>) else id) `liftM` expandPath' p
|
||||||
|
|||||||
@ -116,7 +116,7 @@ replaceAll re f s = start end
|
|||||||
where
|
where
|
||||||
(_, end, start) = foldl' go (0, s, id) $ getAllMatches $ match re s
|
(_, end, start) = foldl' go (0, s, id) $ getAllMatches $ match re s
|
||||||
go (ind,read,write) (off,len) =
|
go (ind,read,write) (off,len) =
|
||||||
let (skip, start) = splitAt (off - ind) read
|
let (skip, start) = splitAt (off - ind) read
|
||||||
(matched, remaining) = splitAt len start
|
(matched, remaining) = splitAt len start
|
||||||
in (off + len, remaining, write . (skip++) . (f matched ++))
|
in (off + len, remaining, write . (skip++) . (f matched ++))
|
||||||
|
|
||||||
|
|||||||
@ -111,7 +111,7 @@ registerChartHtml percommoditytxnreports =
|
|||||||
\$('#register-chart-label').text('#{charttitle}');
|
\$('#register-chart-label').text('#{charttitle}');
|
||||||
var seriesData = [
|
var seriesData = [
|
||||||
$forall (c,(_,items)) <- percommoditytxnreports
|
$forall (c,(_,items)) <- percommoditytxnreports
|
||||||
/* we render each commodity using two series:
|
/* we render each commodity using two series:
|
||||||
* one with extra data points added to show a stepped balance line */
|
* one with extra data points added to show a stepped balance line */
|
||||||
{
|
{
|
||||||
data: [
|
data: [
|
||||||
@ -128,7 +128,7 @@ registerChartHtml percommoditytxnreports =
|
|||||||
show: true,
|
show: true,
|
||||||
steps: true,
|
steps: true,
|
||||||
},
|
},
|
||||||
points: {
|
points: {
|
||||||
show: false,
|
show: false,
|
||||||
},
|
},
|
||||||
clickable: false,
|
clickable: false,
|
||||||
@ -152,7 +152,7 @@ registerChartHtml percommoditytxnreports =
|
|||||||
lines: {
|
lines: {
|
||||||
show: false,
|
show: false,
|
||||||
},
|
},
|
||||||
points: {
|
points: {
|
||||||
show: true,
|
show: true,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|||||||
@ -29,7 +29,7 @@ webflags = [
|
|||||||
,flagReq ["base-url"] (\s opts -> Right $ setopt "base-url" s opts) "BASEURL" ("set the base url (default: "++defbaseurlexample++")")
|
,flagReq ["base-url"] (\s opts -> Right $ setopt "base-url" s opts) "BASEURL" ("set the base url (default: "++defbaseurlexample++")")
|
||||||
,flagReq ["file-url"] (\s opts -> Right $ setopt "file-url" s opts) "FILEURL" ("set the static files url (default: BASEURL/static)")
|
,flagReq ["file-url"] (\s opts -> Right $ setopt "file-url" s opts) "FILEURL" ("set the static files url (default: BASEURL/static)")
|
||||||
]
|
]
|
||||||
|
|
||||||
webmode :: Mode [([Char], [Char])]
|
webmode :: Mode [([Char], [Char])]
|
||||||
webmode = (mode "hledger-web" [("command","web")]
|
webmode = (mode "hledger-web" [("command","web")]
|
||||||
"start serving the hledger web interface"
|
"start serving the hledger web interface"
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
{-|
|
{-|
|
||||||
|
|
||||||
Hledger.Cli re-exports the options, utilities and commands provided by
|
Hledger.Cli re-exports the options, utilities and commands provided by
|
||||||
the hledger command-line program. This module also aggregates the
|
the hledger command-line program. This module also aggregates the
|
||||||
@ -69,19 +69,19 @@ tests_Hledger_Cli = TestList
|
|||||||
j1 `is` j2{filereadtime=filereadtime j1, files=files j1, jContext=jContext j1}
|
j1 `is` j2{filereadtime=filereadtime j1, files=files j1, jContext=jContext j1}
|
||||||
in TestList
|
in TestList
|
||||||
[
|
[
|
||||||
"account directive 1" ~: sameParse
|
"account directive 1" ~: sameParse
|
||||||
"2008/12/07 One\n test:from $-1\n test:to $1\n"
|
"2008/12/07 One\n test:from $-1\n test:to $1\n"
|
||||||
"!account test\n2008/12/07 One\n from $-1\n to $1\n"
|
"!account test\n2008/12/07 One\n from $-1\n to $1\n"
|
||||||
|
|
||||||
,"account directive 2" ~: sameParse
|
,"account directive 2" ~: sameParse
|
||||||
"2008/12/07 One\n test:foo:from $-1\n test:foo:to $1\n"
|
"2008/12/07 One\n test:foo:from $-1\n test:foo:to $1\n"
|
||||||
"!account test\n!account foo\n2008/12/07 One\n from $-1\n to $1\n"
|
"!account test\n!account foo\n2008/12/07 One\n from $-1\n to $1\n"
|
||||||
|
|
||||||
,"account directive 3" ~: sameParse
|
,"account directive 3" ~: sameParse
|
||||||
"2008/12/07 One\n test:from $-1\n test:to $1\n"
|
"2008/12/07 One\n test:from $-1\n test:to $1\n"
|
||||||
"!account test\n!account foo\n!end\n2008/12/07 One\n from $-1\n to $1\n"
|
"!account test\n!account foo\n!end\n2008/12/07 One\n from $-1\n to $1\n"
|
||||||
|
|
||||||
,"account directive 4" ~: sameParse
|
,"account directive 4" ~: sameParse
|
||||||
("2008/12/07 One\n alpha $-1\n beta $1\n" ++
|
("2008/12/07 One\n alpha $-1\n beta $1\n" ++
|
||||||
"!account outer\n2008/12/07 Two\n aigh $-2\n bee $2\n" ++
|
"!account outer\n2008/12/07 Two\n aigh $-2\n bee $2\n" ++
|
||||||
"!account inner\n2008/12/07 Three\n gamma $-3\n delta $3\n" ++
|
"!account inner\n2008/12/07 Three\n gamma $-3\n delta $3\n" ++
|
||||||
@ -136,7 +136,7 @@ tests_Hledger_Cli = TestList
|
|||||||
|
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
-- fixtures/test data
|
-- fixtures/test data
|
||||||
|
|
||||||
-- date1 = parsedate "2008/11/26"
|
-- date1 = parsedate "2008/11/26"
|
||||||
@ -340,7 +340,7 @@ defaultyear_journal_str = unlines
|
|||||||
-- ]
|
-- ]
|
||||||
|
|
||||||
journal7 :: Journal
|
journal7 :: Journal
|
||||||
journal7 = nulljournal {jtxns =
|
journal7 = nulljournal {jtxns =
|
||||||
[
|
[
|
||||||
txnTieKnot Transaction {
|
txnTieKnot Transaction {
|
||||||
tsourcepos=nullsourcepos,
|
tsourcepos=nullsourcepos,
|
||||||
|
|||||||
@ -20,7 +20,7 @@ import Safe (headDef, headMay)
|
|||||||
import System.Console.CmdArgs.Explicit
|
import System.Console.CmdArgs.Explicit
|
||||||
import System.Console.Haskeline (runInputT, defaultSettings, setComplete)
|
import System.Console.Haskeline (runInputT, defaultSettings, setComplete)
|
||||||
import System.Console.Haskeline.Completion
|
import System.Console.Haskeline.Completion
|
||||||
import System.Console.Wizard
|
import System.Console.Wizard
|
||||||
import System.Console.Wizard.Haskeline
|
import System.Console.Wizard.Haskeline
|
||||||
import System.IO ( stderr, hPutStr, hPutStrLn )
|
import System.IO ( stderr, hPutStr, hPutStrLn )
|
||||||
import Text.ParserCombinators.Parsec hiding (Line)
|
import Text.ParserCombinators.Parsec hiding (Line)
|
||||||
@ -128,9 +128,9 @@ confirmedTransactionWizard es@EntryState{..} = do
|
|||||||
-- liftIO $ hPrintf stderr {- "Transaction entered:\n%s" -} (show t)
|
-- liftIO $ hPrintf stderr {- "Transaction entered:\n%s" -} (show t)
|
||||||
output $ show t
|
output $ show t
|
||||||
y <- let def = "y" in
|
y <- let def = "y" in
|
||||||
retryMsg "Please enter y or n." $
|
retryMsg "Please enter y or n." $
|
||||||
parser ((fmap ('y' ==)) . headMay . map toLower . strip) $
|
parser ((fmap ('y' ==)) . headMay . map toLower . strip) $
|
||||||
defaultTo' def $ nonEmpty $
|
defaultTo' def $ nonEmpty $
|
||||||
maybeRestartTransaction $
|
maybeRestartTransaction $
|
||||||
line $ green $ printf "Save this transaction to the journal ?%s: " (showDefault def)
|
line $ green $ printf "Save this transaction to the journal ?%s: " (showDefault def)
|
||||||
if y then return t else throw RestartTransactionException
|
if y then return t else throw RestartTransactionException
|
||||||
@ -167,10 +167,10 @@ similarTransaction EntryState{..} desc =
|
|||||||
|
|
||||||
dateAndCodeWizard EntryState{..} = do
|
dateAndCodeWizard EntryState{..} = do
|
||||||
let def = headDef (showDate esDefDate) esArgs
|
let def = headDef (showDate esDefDate) esArgs
|
||||||
retryMsg "A valid hledger smart date is required. Eg: 2014/2/14, 14, yesterday." $
|
retryMsg "A valid hledger smart date is required. Eg: 2014/2/14, 14, yesterday." $
|
||||||
parser (parseSmartDateAndCode esToday) $
|
parser (parseSmartDateAndCode esToday) $
|
||||||
withCompletion (dateCompleter def) $
|
withCompletion (dateCompleter def) $
|
||||||
defaultTo' def $ nonEmpty $
|
defaultTo' def $ nonEmpty $
|
||||||
maybeExit $
|
maybeExit $
|
||||||
maybeRestartTransaction $
|
maybeRestartTransaction $
|
||||||
-- maybeShowHelp $
|
-- maybeShowHelp $
|
||||||
@ -191,7 +191,7 @@ dateAndCodeWizard EntryState{..} = do
|
|||||||
descriptionAndCommentWizard EntryState{..} = do
|
descriptionAndCommentWizard EntryState{..} = do
|
||||||
let def = headDef "" esArgs
|
let def = headDef "" esArgs
|
||||||
s <- withCompletion (descriptionCompleter esJournal def) $
|
s <- withCompletion (descriptionCompleter esJournal def) $
|
||||||
defaultTo' def $ nonEmpty $
|
defaultTo' def $ nonEmpty $
|
||||||
maybeRestartTransaction $
|
maybeRestartTransaction $
|
||||||
line $ green $ printf "Description%s: " (showDefault def)
|
line $ green $ printf "Description%s: " (showDefault def)
|
||||||
let (desc,comment) = (strip a, strip $ dropWhile (==';') b) where (a,b) = break (==';') s
|
let (desc,comment) = (strip a, strip $ dropWhile (==';') b) where (a,b) = break (==';') s
|
||||||
@ -233,7 +233,7 @@ accountWizard EntryState{..} = do
|
|||||||
retryMsg "A valid hledger account name is required. Eg: assets:cash, expenses:food:eating out." $
|
retryMsg "A valid hledger account name is required. Eg: assets:cash, expenses:food:eating out." $
|
||||||
parser (parseAccountOrDotOrNull def canfinish) $
|
parser (parseAccountOrDotOrNull def canfinish) $
|
||||||
withCompletion (accountCompleter esJournal def) $
|
withCompletion (accountCompleter esJournal def) $
|
||||||
defaultTo' def $ -- nonEmpty $
|
defaultTo' def $ -- nonEmpty $
|
||||||
maybeRestartTransaction $
|
maybeRestartTransaction $
|
||||||
line $ green $ printf "Account %d%s%s: " pnum (endmsg::String) (showDefault def)
|
line $ green $ printf "Account %d%s%s: " pnum (endmsg::String) (showDefault def)
|
||||||
where
|
where
|
||||||
@ -259,12 +259,12 @@ amountAndCommentWizard EntryState{..} = do
|
|||||||
_ | pnum > 1 && not (isZeroMixedAmount balancingamt) -> showamt balancingamt
|
_ | pnum > 1 && not (isZeroMixedAmount balancingamt) -> showamt balancingamt
|
||||||
_ -> ""
|
_ -> ""
|
||||||
retryMsg "A valid hledger amount is required. Eg: 1, $2, 3 EUR, \"4 red apples\"." $
|
retryMsg "A valid hledger amount is required. Eg: 1, $2, 3 EUR, \"4 red apples\"." $
|
||||||
parser parseAmountAndComment $
|
parser parseAmountAndComment $
|
||||||
withCompletion (amountCompleter def) $
|
withCompletion (amountCompleter def) $
|
||||||
defaultTo' def $ nonEmpty $
|
defaultTo' def $ nonEmpty $
|
||||||
maybeRestartTransaction $
|
maybeRestartTransaction $
|
||||||
line $ green $ printf "Amount %d%s: " pnum (showDefault def)
|
line $ green $ printf "Amount %d%s: " pnum (showDefault def)
|
||||||
where
|
where
|
||||||
parseAmountAndComment = either (const Nothing) Just . parseWithCtx nodefcommodityctx amountandcommentp
|
parseAmountAndComment = either (const Nothing) Just . parseWithCtx nodefcommodityctx amountandcommentp
|
||||||
nodefcommodityctx = (jContext esJournal){ctxDefaultCommodityAndStyle=Nothing}
|
nodefcommodityctx = (jContext esJournal){ctxDefaultCommodityAndStyle=Nothing}
|
||||||
amountandcommentp = do
|
amountandcommentp = do
|
||||||
@ -298,7 +298,7 @@ maybeExit = parser (\s -> if s=="." then throw UnexpectedEOF else Just s)
|
|||||||
maybeRestartTransaction = parser (\s -> if s=="<" then throw RestartTransactionException else Just s)
|
maybeRestartTransaction = parser (\s -> if s=="<" then throw RestartTransactionException else Just s)
|
||||||
|
|
||||||
-- maybeShowHelp :: Wizard Haskeline String -> Wizard Haskeline String
|
-- maybeShowHelp :: Wizard Haskeline String -> Wizard Haskeline String
|
||||||
-- maybeShowHelp wizard = maybe (liftIO showHelp >> wizard) return $
|
-- maybeShowHelp wizard = maybe (liftIO showHelp >> wizard) return $
|
||||||
-- parser (\s -> if s=="?" then Nothing else Just s) wizard
|
-- parser (\s -> if s=="?" then Nothing else Just s) wizard
|
||||||
|
|
||||||
-- Completion helpers
|
-- Completion helpers
|
||||||
|
|||||||
@ -129,7 +129,7 @@ There are three kinds of multi-column balance report, indicated by the heading:
|
|||||||
period. Here, checking's balance increased by 10 in Feb:
|
period. Here, checking's balance increased by 10 in Feb:
|
||||||
|
|
||||||
> Change of balance (flow):
|
> Change of balance (flow):
|
||||||
>
|
>
|
||||||
> Jan Feb Mar
|
> Jan Feb Mar
|
||||||
> assets:checking 20 10 -5
|
> assets:checking 20 10 -5
|
||||||
|
|
||||||
@ -138,7 +138,7 @@ There are three kinds of multi-column balance report, indicated by the heading:
|
|||||||
Here, 30 is the sum of checking postings during Jan and Feb:
|
Here, 30 is the sum of checking postings during Jan and Feb:
|
||||||
|
|
||||||
> Ending balance (cumulative):
|
> Ending balance (cumulative):
|
||||||
>
|
>
|
||||||
> Jan Feb Mar
|
> Jan Feb Mar
|
||||||
> assets:checking 20 30 25
|
> assets:checking 20 30 25
|
||||||
|
|
||||||
@ -148,7 +148,7 @@ There are three kinds of multi-column balance report, indicated by the heading:
|
|||||||
pre-Jan postings which created a starting balance of 100:
|
pre-Jan postings which created a starting balance of 100:
|
||||||
|
|
||||||
> Ending balance (historical):
|
> Ending balance (historical):
|
||||||
>
|
>
|
||||||
> Jan Feb Mar
|
> Jan Feb Mar
|
||||||
> assets:checking 120 130 125
|
> assets:checking 120 130 125
|
||||||
|
|
||||||
@ -161,7 +161,7 @@ Here's a (imperfect?) specification for the eliding/omitting behaviour:
|
|||||||
* An account less deep than the report's max depth, with just one
|
* An account less deep than the report's max depth, with just one
|
||||||
interesting subaccount, and the same balance as the subaccount, is
|
interesting subaccount, and the same balance as the subaccount, is
|
||||||
non-interesting, and prefixed to the subaccount's line, unless
|
non-interesting, and prefixed to the subaccount's line, unless
|
||||||
@--no-elide@ is in effect.
|
@--no-elide@ is in effect.
|
||||||
|
|
||||||
* An account with a zero inclusive balance and less than two interesting
|
* An account with a zero inclusive balance and less than two interesting
|
||||||
subaccounts is not displayed at all, unless @--empty@ is in effect.
|
subaccounts is not displayed at all, unless @--empty@ is in effect.
|
||||||
@ -405,7 +405,7 @@ cumulativeBalanceReportAsText opts r@(MultiBalanceReport (colspans, items, colto
|
|||||||
([printf "Ending balances (cumulative) in %s:" (showDateSpan $ multiBalanceReportSpan r)] ++) $
|
([printf "Ending balances (cumulative) in %s:" (showDateSpan $ multiBalanceReportSpan r)] ++) $
|
||||||
trimborder $ lines $
|
trimborder $ lines $
|
||||||
render id ((" "++) . maybe "" (showDate . prevday) . spanEnd) showMixedAmountOneLineWithoutPrice $
|
render id ((" "++) . maybe "" (showDate . prevday) . spanEnd) showMixedAmountOneLineWithoutPrice $
|
||||||
addtotalrow $
|
addtotalrow $
|
||||||
Table
|
Table
|
||||||
(T.Group NoLine $ map (Header . padright acctswidth) accts)
|
(T.Group NoLine $ map (Header . padright acctswidth) accts)
|
||||||
(T.Group NoLine $ map Header colspans)
|
(T.Group NoLine $ map Header colspans)
|
||||||
@ -426,7 +426,7 @@ historicalBalanceReportAsText opts r@(MultiBalanceReport (colspans, items, colto
|
|||||||
([printf "Ending balances (historical) in %s:" (showDateSpan $ multiBalanceReportSpan r)] ++) $
|
([printf "Ending balances (historical) in %s:" (showDateSpan $ multiBalanceReportSpan r)] ++) $
|
||||||
trimborder $ lines $
|
trimborder $ lines $
|
||||||
render id ((" "++) . maybe "" (showDate . prevday) . spanEnd) showMixedAmountOneLineWithoutPrice $
|
render id ((" "++) . maybe "" (showDate . prevday) . spanEnd) showMixedAmountOneLineWithoutPrice $
|
||||||
addtotalrow $
|
addtotalrow $
|
||||||
Table
|
Table
|
||||||
(T.Group NoLine $ map (Header . padright acctswidth) accts)
|
(T.Group NoLine $ map (Header . padright acctswidth) accts)
|
||||||
(T.Group NoLine $ map Header colspans)
|
(T.Group NoLine $ map Header colspans)
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
{-|
|
{-|
|
||||||
|
|
||||||
Print a histogram report. (The "activity" command).
|
Print a histogram report. (The "activity" command).
|
||||||
|
|
||||||
|
|||||||
@ -21,7 +21,7 @@ module Hledger.Cli.Options (
|
|||||||
argsFlag,
|
argsFlag,
|
||||||
showModeHelp,
|
showModeHelp,
|
||||||
withAliases,
|
withAliases,
|
||||||
|
|
||||||
-- * CLI options
|
-- * CLI options
|
||||||
CliOpts(..),
|
CliOpts(..),
|
||||||
defcliopts,
|
defcliopts,
|
||||||
@ -51,9 +51,9 @@ module Hledger.Cli.Options (
|
|||||||
-- * Tests
|
-- * Tests
|
||||||
tests_Hledger_Cli_Options
|
tests_Hledger_Cli_Options
|
||||||
|
|
||||||
)
|
)
|
||||||
where
|
where
|
||||||
|
|
||||||
import qualified Control.Exception as C
|
import qualified Control.Exception as C
|
||||||
import Control.Monad (when)
|
import Control.Monad (when)
|
||||||
import Data.List
|
import Data.List
|
||||||
@ -199,7 +199,7 @@ standardAddonsHelp = [
|
|||||||
|
|
||||||
-- | Get a mode's help message as a nicely wrapped string.
|
-- | Get a mode's help message as a nicely wrapped string.
|
||||||
showModeHelp :: Mode a -> String
|
showModeHelp :: Mode a -> String
|
||||||
showModeHelp = (showText defaultWrap :: [Text] -> String) .
|
showModeHelp = (showText defaultWrap :: [Text] -> String) .
|
||||||
(helpText [] HelpFormatDefault :: Mode a -> [Text])
|
(helpText [] HelpFormatDefault :: Mode a -> [Text])
|
||||||
|
|
||||||
-- | Add command aliases to the command's help string.
|
-- | Add command aliases to the command's help string.
|
||||||
@ -275,7 +275,7 @@ rawOptsToCliOpts rawopts = do
|
|||||||
,width_ = maybestringopt "width" rawopts -- register
|
,width_ = maybestringopt "width" rawopts -- register
|
||||||
,reportopts_ = ropts
|
,reportopts_ = ropts
|
||||||
}
|
}
|
||||||
|
|
||||||
-- | Do final validation of processed opts, raising an error if there is trouble.
|
-- | Do final validation of processed opts, raising an error if there is trouble.
|
||||||
checkCliOpts :: CliOpts -> IO CliOpts -- or pure..
|
checkCliOpts :: CliOpts -> IO CliOpts -- or pure..
|
||||||
checkCliOpts opts@CliOpts{reportopts_=ropts} = do
|
checkCliOpts opts@CliOpts{reportopts_=ropts} = do
|
||||||
@ -362,7 +362,7 @@ defaultBalanceFormat = [
|
|||||||
|
|
||||||
-- | Output width configuration (for register).
|
-- | Output width configuration (for register).
|
||||||
data OutputWidth =
|
data OutputWidth =
|
||||||
TotalWidth Width -- ^ specify the overall width
|
TotalWidth Width -- ^ specify the overall width
|
||||||
| FieldWidths [Width] -- ^ specify each field's width
|
| FieldWidths [Width] -- ^ specify each field's width
|
||||||
deriving Show
|
deriving Show
|
||||||
|
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
{-|
|
{-|
|
||||||
|
|
||||||
A ledger-compatible @print@ command.
|
A ledger-compatible @print@ command.
|
||||||
|
|
||||||
@ -46,7 +46,7 @@ entriesReportAsText _ _ items = concatMap showTransactionUnelided items
|
|||||||
-- "showTransactions" ~: do
|
-- "showTransactions" ~: do
|
||||||
|
|
||||||
-- -- "print expenses" ~:
|
-- -- "print expenses" ~:
|
||||||
-- do
|
-- do
|
||||||
-- let opts = defreportopts{query_="expenses"}
|
-- let opts = defreportopts{query_="expenses"}
|
||||||
-- d <- getCurrentDay
|
-- d <- getCurrentDay
|
||||||
-- showTransactions opts (queryFromOpts d opts) samplejournal `is` unlines
|
-- showTransactions opts (queryFromOpts d opts) samplejournal `is` unlines
|
||||||
@ -58,7 +58,7 @@ entriesReportAsText _ _ items = concatMap showTransactionUnelided items
|
|||||||
-- ]
|
-- ]
|
||||||
|
|
||||||
-- -- , "print report with depth arg" ~:
|
-- -- , "print report with depth arg" ~:
|
||||||
-- do
|
-- do
|
||||||
-- let opts = defreportopts{depth_=Just 2}
|
-- let opts = defreportopts{depth_=Just 2}
|
||||||
-- d <- getCurrentDay
|
-- d <- getCurrentDay
|
||||||
-- showTransactions opts (queryFromOpts d opts) samplejournal `is` unlines
|
-- showTransactions opts (queryFromOpts d opts) samplejournal `is` unlines
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
{-|
|
{-|
|
||||||
|
|
||||||
A ledger-compatible @register@ command.
|
A ledger-compatible @register@ command.
|
||||||
|
|
||||||
@ -75,7 +75,7 @@ postingsReportItemAsText opts (mdate, menddate, mdesc, p, b) =
|
|||||||
date desc acct amtfirstline balfirstline]
|
date desc acct amtfirstline balfirstline]
|
||||||
++
|
++
|
||||||
[printf (spacer ++ "%"++amtw++"s %"++balw++"s") a b | (a,b) <- zip amtrest balrest ]
|
[printf (spacer ++ "%"++amtw++"s %"++balw++"s") a b | (a,b) <- zip amtrest balrest ]
|
||||||
|
|
||||||
where
|
where
|
||||||
totalwidth = case widthFromOpts opts of
|
totalwidth = case widthFromOpts opts of
|
||||||
Left _ -> defaultWidth -- shouldn't happen
|
Left _ -> defaultWidth -- shouldn't happen
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
#!/usr/bin/env runhaskell
|
#!/usr/bin/env runhaskell
|
||||||
{-
|
{-
|
||||||
generateledger.hs NUMTXNS NUMACCTS ACCTDEPTH
|
generateledger.hs NUMTXNS NUMACCTS ACCTDEPTH
|
||||||
|
|
||||||
Outputs a dummy ledger file with the specified number of transactions,
|
Outputs a dummy ledger file with the specified number of transactions,
|
||||||
|
|||||||
@ -43,7 +43,7 @@ allDeps base mod = allDeps' [mod] [mod] where
|
|||||||
allDeps' [] _ = return []
|
allDeps' [] _ = return []
|
||||||
|
|
||||||
{-
|
{-
|
||||||
Usage: OrderByComplexity
|
Usage: OrderByComplexity
|
||||||
|
|
||||||
= directory where source code is found. This MUST
|
= directory where source code is found. This MUST
|
||||||
end in '/'
|
end in '/'
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
#!/usr/bin/env runhaskell
|
#!/usr/bin/env runhaskell
|
||||||
{-
|
{-
|
||||||
bench.hs - simple benchmarking of command-line programs.
|
bench.hs - simple benchmarking of command-line programs.
|
||||||
Requires html and tabular.
|
Requires html and tabular.
|
||||||
Simon Michael 2008-2013
|
Simon Michael 2008-2013
|
||||||
@ -63,14 +63,14 @@ usagehdr = "bench [-f testsfile] [-n iterations] [-p precision] executable1 [exe
|
|||||||
"Run some functional tests with each of the specified executables,\n" ++
|
"Run some functional tests with each of the specified executables,\n" ++
|
||||||
"where a test is \"zero or more arguments supported by all executables\",\n" ++
|
"where a test is \"zero or more arguments supported by all executables\",\n" ++
|
||||||
"and report the best execution times.\n"
|
"and report the best execution times.\n"
|
||||||
|
|
||||||
options = [
|
options = [
|
||||||
Option "f" ["testsfile"] (ReqArg File "testsfile") "file containing tests, one per line, default: bench.tests"
|
Option "f" ["testsfile"] (ReqArg File "testsfile") "file containing tests, one per line, default: bench.tests"
|
||||||
,Option "n" ["iterations"] (ReqArg Num "iterations") "number of test iterations to run, default: 2"
|
,Option "n" ["iterations"] (ReqArg Num "iterations") "number of test iterations to run, default: 2"
|
||||||
,Option "p" ["precision"] (ReqArg Prec "precision") "show times with this precision, default: 2"
|
,Option "p" ["precision"] (ReqArg Prec "precision") "show times with this precision, default: 2"
|
||||||
,Option "v" ["verbose"] (NoArg Verbose) "show intermediate results"
|
,Option "v" ["verbose"] (NoArg Verbose) "show intermediate results"
|
||||||
,Option "h" ["help"] (NoArg Help) "show this help"
|
,Option "h" ["help"] (NoArg Help) "show this help"
|
||||||
]
|
]
|
||||||
|
|
||||||
usageftr = "\n" ++
|
usageftr = "\n" ++
|
||||||
"Tips:\n" ++
|
"Tips:\n" ++
|
||||||
@ -81,10 +81,10 @@ usageftr = "\n" ++
|
|||||||
usage = usageInfo usagehdr options ++ usageftr
|
usage = usageInfo usagehdr options ++ usageftr
|
||||||
|
|
||||||
-- an option value
|
-- an option value
|
||||||
data Opt = File {value::String}
|
data Opt = File {value::String}
|
||||||
| Num {value::String}
|
| Num {value::String}
|
||||||
| Prec {value::String}
|
| Prec {value::String}
|
||||||
-- I don't know how optValuesForConstructor etc. can have that
|
-- I don't know how optValuesForConstructor etc. can have that
|
||||||
-- type signature with these, but it works..
|
-- type signature with these, but it works..
|
||||||
-- | Some Int
|
-- | Some Int
|
||||||
| Verbose
|
| Verbose
|
||||||
@ -112,7 +112,7 @@ parseargs as =
|
|||||||
(_,_,errs) -> error (concat errs ++ usage)
|
(_,_,errs) -> error (concat errs ++ usage)
|
||||||
|
|
||||||
optValueWithDefault :: (String -> Opt) -> String -> [Opt] -> String
|
optValueWithDefault :: (String -> Opt) -> String -> [Opt] -> String
|
||||||
optValueWithDefault optcons def opts =
|
optValueWithDefault optcons def opts =
|
||||||
last $ def : optValuesForConstructor optcons opts
|
last $ def : optValuesForConstructor optcons opts
|
||||||
|
|
||||||
optValuesForConstructor :: (String -> Opt) -> [Opt] -> [String]
|
optValuesForConstructor :: (String -> Opt) -> [Opt] -> [String]
|
||||||
@ -127,13 +127,13 @@ main = do
|
|||||||
tests <- liftM (filter istest . lines) (readFile file)
|
tests <- liftM (filter istest . lines) (readFile file)
|
||||||
now <- getCurrentTime
|
now <- getCurrentTime
|
||||||
putStrLn $ printf "Using %s" file
|
putStrLn $ printf "Using %s" file
|
||||||
putStrLn $ printf "Running %d tests %d times with %d executables at %s:"
|
putStrLn $ printf "Running %d tests %d times with %d executables at %s:"
|
||||||
(length tests) num (length exes) (show now)
|
(length tests) num (length exes) (show now)
|
||||||
let doexe t e = mapM (doiteration opts t e) [1..num]
|
let doexe t e = mapM (doiteration opts t e) [1..num]
|
||||||
let dotest t = mapM (doexe t) exes
|
let dotest t = mapM (doexe t) exes
|
||||||
hSetBuffering stdout NoBuffering
|
hSetBuffering stdout NoBuffering
|
||||||
results <- mapM dotest tests
|
results <- mapM dotest tests
|
||||||
summarise opts tests exes results
|
summarise opts tests exes results
|
||||||
|
|
||||||
istest s = not (null s' || ("#" `isPrefixOf` s')) where s' = clean s
|
istest s = not (null s' || ("#" `isPrefixOf` s')) where s' = clean s
|
||||||
clean = unwords . words
|
clean = unwords . words
|
||||||
|
|||||||
@ -9,7 +9,7 @@ import System.Environment
|
|||||||
import Text.Printf
|
import Text.Printf
|
||||||
|
|
||||||
main = do
|
main = do
|
||||||
args <- getArgs
|
args <- getArgs
|
||||||
let f = head args
|
let f = head args
|
||||||
s <- readFile f
|
s <- readFile f
|
||||||
let ls = lines s
|
let ls = lines s
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user