fix warnings all over - hledger is now -W-clean
This commit is contained in:
parent
92d67926f5
commit
cb8ea69dfc
@ -21,7 +21,7 @@ import Utils (ledgerFromStringWithOpts)
|
|||||||
-- and append them to the ledger file. If the ledger came from stdin, this
|
-- and append them to the ledger file. If the ledger came from stdin, this
|
||||||
-- command has no effect.
|
-- command has no effect.
|
||||||
add :: [Opt] -> [String] -> Ledger -> IO ()
|
add :: [Opt] -> [String] -> Ledger -> IO ()
|
||||||
add opts args l
|
add _ args l
|
||||||
| filepath (rawledger l) == "-" = return ()
|
| filepath (rawledger l) == "-" = return ()
|
||||||
| otherwise = do
|
| otherwise = do
|
||||||
hPutStrLn stderr
|
hPutStrLn stderr
|
||||||
@ -90,7 +90,6 @@ getPostings historicalps enteredps = do
|
|||||||
getPostings historicalps $ enteredps ++ [p]
|
getPostings historicalps $ enteredps ++ [p]
|
||||||
where
|
where
|
||||||
n = length enteredps + 1
|
n = length enteredps + 1
|
||||||
realn = length enteredrealps + 1
|
|
||||||
enteredrealps = filter isReal enteredps
|
enteredrealps = filter isReal enteredps
|
||||||
bestmatch | isNothing historicalps = Nothing
|
bestmatch | isNothing historicalps = Nothing
|
||||||
| n <= length ps = Just $ ps !! (n-1)
|
| n <= length ps = Just $ ps !! (n-1)
|
||||||
@ -164,8 +163,8 @@ registerFromString s = do
|
|||||||
-- with a modification for short strings.
|
-- with a modification for short strings.
|
||||||
compareStrings :: String -> String -> Float
|
compareStrings :: String -> String -> Float
|
||||||
compareStrings "" "" = 1
|
compareStrings "" "" = 1
|
||||||
compareStrings (a:[]) "" = 0
|
compareStrings (_:[]) "" = 0
|
||||||
compareStrings "" (b:[]) = 0
|
compareStrings "" (_:[]) = 0
|
||||||
compareStrings (a:[]) (b:[]) = if toUpper a == toUpper b then 1 else 0
|
compareStrings (a:[]) (b:[]) = if toUpper a == toUpper b then 1 else 0
|
||||||
compareStrings s1 s2 = 2.0 * (fromIntegral i) / (fromIntegral u)
|
compareStrings s1 s2 = 2.0 * (fromIntegral i) / (fromIntegral u)
|
||||||
where
|
where
|
||||||
|
|||||||
@ -103,9 +103,7 @@ import Ledger.Amount
|
|||||||
import Ledger.AccountName
|
import Ledger.AccountName
|
||||||
import Ledger.Transaction
|
import Ledger.Transaction
|
||||||
import Ledger.Ledger
|
import Ledger.Ledger
|
||||||
import Ledger.Parse
|
|
||||||
import Options
|
import Options
|
||||||
import Utils
|
|
||||||
import System.IO.UTF8
|
import System.IO.UTF8
|
||||||
|
|
||||||
|
|
||||||
@ -115,7 +113,7 @@ balance opts args l = putStr $ showBalanceReport opts args l
|
|||||||
|
|
||||||
-- | Generate a balance report with the specified options for this ledger.
|
-- | Generate a balance report with the specified options for this ledger.
|
||||||
showBalanceReport :: [Opt] -> [String] -> Ledger -> String
|
showBalanceReport :: [Opt] -> [String] -> Ledger -> String
|
||||||
showBalanceReport opts args l = acctsstr ++ totalstr
|
showBalanceReport opts _ l = acctsstr ++ totalstr
|
||||||
where
|
where
|
||||||
acctsstr = unlines $ map showacct interestingaccts
|
acctsstr = unlines $ map showacct interestingaccts
|
||||||
where
|
where
|
||||||
|
|||||||
@ -37,14 +37,12 @@ optional rule saving.
|
|||||||
-}
|
-}
|
||||||
|
|
||||||
module Commands.Convert where
|
module Commands.Convert where
|
||||||
import Data.Maybe (isJust)
|
|
||||||
import Data.List.Split (splitOn)
|
import Data.List.Split (splitOn)
|
||||||
import Options -- (Opt,Debug)
|
import Options -- (Opt,Debug)
|
||||||
import Ledger.Types (Ledger,AccountName)
|
import Ledger.Types (Ledger,AccountName)
|
||||||
import Ledger.Utils (strip)
|
import Ledger.Utils (strip)
|
||||||
import System (getArgs)
|
|
||||||
import System.IO (stderr, hPutStrLn)
|
import System.IO (stderr, hPutStrLn)
|
||||||
import Text.CSV (parseCSVFromFile, Record)
|
import Text.CSV (parseCSVFromFile)
|
||||||
import Text.Printf (printf)
|
import Text.Printf (printf)
|
||||||
import Text.RegexPR (matchRegexPR)
|
import Text.RegexPR (matchRegexPR)
|
||||||
import Data.Maybe
|
import Data.Maybe
|
||||||
@ -55,7 +53,7 @@ import Control.Monad (when)
|
|||||||
|
|
||||||
|
|
||||||
convert :: [Opt] -> [String] -> Ledger -> IO ()
|
convert :: [Opt] -> [String] -> Ledger -> IO ()
|
||||||
convert opts args l = do
|
convert opts args _ = do
|
||||||
when (length args /= 3) (error "please specify a csv file, base account, and import rules file.")
|
when (length args /= 3) (error "please specify a csv file, base account, and import rules file.")
|
||||||
let [csvfile,baseacct,rulesfile] = args
|
let [csvfile,baseacct,rulesfile] = args
|
||||||
rulesstr <- readFile rulesfile
|
rulesstr <- readFile rulesfile
|
||||||
@ -83,10 +81,11 @@ parseRules s = do
|
|||||||
parsePatRepl :: String -> (String, Maybe String)
|
parsePatRepl :: String -> (String, Maybe String)
|
||||||
parsePatRepl l = case splitOn "=" l of
|
parsePatRepl l = case splitOn "=" l of
|
||||||
(p:r:_) -> (p, Just r)
|
(p:r:_) -> (p, Just r)
|
||||||
(p:_) -> (p, Nothing)
|
_ -> (l, Nothing)
|
||||||
|
|
||||||
print_ledger_txn debug (baseacct,fieldpositions,rules) record@(a:b:c:d:e) = do
|
print_ledger_txn :: Bool -> (String,[Int],[Rule]) -> [String] -> IO ()
|
||||||
let [date,cleared,number,description,amount] = map (record !!) fieldpositions
|
print_ledger_txn debug (baseacct,fieldpositions,rules) record@(_:_:_:_:_:[]) = do
|
||||||
|
let [date,_,number,description,amount] = map (record !!) fieldpositions
|
||||||
amount' = strnegate amount where strnegate ('-':s) = s
|
amount' = strnegate amount where strnegate ('-':s) = s
|
||||||
strnegate s = '-':s
|
strnegate s = '-':s
|
||||||
unknownacct | (read amount' :: Double) < 0 = "income:unknown"
|
unknownacct | (read amount' :: Double) < 0 = "income:unknown"
|
||||||
|
|||||||
@ -7,8 +7,6 @@ Print a histogram report.
|
|||||||
module Commands.Histogram
|
module Commands.Histogram
|
||||||
where
|
where
|
||||||
import Prelude hiding (putStr)
|
import Prelude hiding (putStr)
|
||||||
import qualified Data.Map as Map
|
|
||||||
import Data.Map ((!))
|
|
||||||
import Ledger
|
import Ledger
|
||||||
import Options
|
import Options
|
||||||
import System.IO.UTF8
|
import System.IO.UTF8
|
||||||
|
|||||||
@ -7,8 +7,6 @@ A ledger-compatible @register@ command.
|
|||||||
module Commands.Register
|
module Commands.Register
|
||||||
where
|
where
|
||||||
import Prelude hiding (putStr)
|
import Prelude hiding (putStr)
|
||||||
import qualified Data.Map as Map
|
|
||||||
import Data.Map ((!))
|
|
||||||
import Ledger
|
import Ledger
|
||||||
import Options
|
import Options
|
||||||
import System.IO.UTF8
|
import System.IO.UTF8
|
||||||
@ -46,7 +44,7 @@ showRegisterReport opts args l
|
|||||||
startbal = sumTransactions precedingts
|
startbal = sumTransactions precedingts
|
||||||
matchapats t = matchpats apats $ taccount t
|
matchapats t = matchpats apats $ taccount t
|
||||||
(apats,_) = parsePatternArgs args
|
(apats,_) = parsePatternArgs args
|
||||||
matchdisplayopt Nothing t = True
|
matchdisplayopt Nothing _ = True
|
||||||
matchdisplayopt (Just e) t = (fromparse $ parsewith datedisplayexpr e) t
|
matchdisplayopt (Just e) t = (fromparse $ parsewith datedisplayexpr e) t
|
||||||
dopt = displayFromOpts opts
|
dopt = displayFromOpts opts
|
||||||
empty = Empty `elem` opts
|
empty = Empty `elem` opts
|
||||||
@ -99,7 +97,7 @@ clipAccountNames d as = nub $ map (clip d) as
|
|||||||
-- | Show transactions one per line, with each date/description appearing
|
-- | Show transactions one per line, with each date/description appearing
|
||||||
-- only once, and a running balance.
|
-- only once, and a running balance.
|
||||||
showtxns [] _ _ = ""
|
showtxns [] _ _ = ""
|
||||||
showtxns (t@Transaction{tamount=a}:ts) tprev bal = this ++ showtxns ts t bal'
|
showtxns (t:ts) tprev bal = this ++ showtxns ts t bal'
|
||||||
where
|
where
|
||||||
this = showtxn (t `issame` tprev) t bal'
|
this = showtxn (t `issame` tprev) t bal'
|
||||||
issame t1 t2 = tnum t1 == tnum t2
|
issame t1 t2 = tnum t1 == tnum t2
|
||||||
|
|||||||
@ -7,12 +7,9 @@ Print some statistics for the ledger.
|
|||||||
module Commands.Stats
|
module Commands.Stats
|
||||||
where
|
where
|
||||||
import Prelude hiding (putStr)
|
import Prelude hiding (putStr)
|
||||||
import qualified Data.Map as Map
|
|
||||||
import Data.Map ((!))
|
|
||||||
import Ledger
|
import Ledger
|
||||||
import Options
|
import Options
|
||||||
import System.IO.UTF8
|
import System.IO.UTF8
|
||||||
import Utils (filterAndCacheLedgerWithOpts)
|
|
||||||
|
|
||||||
|
|
||||||
-- | Print various statistics for the ledger.
|
-- | Print various statistics for the ledger.
|
||||||
@ -22,7 +19,7 @@ stats opts args l = do
|
|||||||
putStr $ showStats opts args l today
|
putStr $ showStats opts args l today
|
||||||
|
|
||||||
showStats :: [Opt] -> [String] -> Ledger -> Day -> String
|
showStats :: [Opt] -> [String] -> Ledger -> Day -> String
|
||||||
showStats opts args l today =
|
showStats _ _ l today =
|
||||||
heading ++ (unlines $ map (\(a,b) -> printf fmt a b) stats)
|
heading ++ (unlines $ map (\(a,b) -> printf fmt a b) stats)
|
||||||
where
|
where
|
||||||
heading = underline $ printf "Ledger statistics as of %s" (show today)
|
heading = underline $ printf "Ledger statistics as of %s" (show today)
|
||||||
|
|||||||
@ -6,8 +6,6 @@ A simple text UI for hledger, based on the vty library.
|
|||||||
|
|
||||||
module Commands.UI
|
module Commands.UI
|
||||||
where
|
where
|
||||||
import qualified Data.Map as Map
|
|
||||||
import Data.Map ((!))
|
|
||||||
import Graphics.Vty
|
import Graphics.Vty
|
||||||
import qualified Data.ByteString.Char8 as B
|
import qualified Data.ByteString.Char8 as B
|
||||||
import Ledger
|
import Ledger
|
||||||
@ -19,7 +17,7 @@ import Commands.Print
|
|||||||
|
|
||||||
helpmsg = "(b)alance, (r)egister, (p)rint, (right) to drill down, (left) to back up, (q)uit"
|
helpmsg = "(b)alance, (r)egister, (p)rint, (right) to drill down, (left) to back up, (q)uit"
|
||||||
|
|
||||||
instance Show Vty where show v = "a Vty"
|
instance Show Vty where show = const "a Vty"
|
||||||
|
|
||||||
-- | The application state when running the ui command.
|
-- | The application state when running the ui command.
|
||||||
data AppState = AppState {
|
data AppState = AppState {
|
||||||
@ -46,7 +44,7 @@ data Loc = Loc {
|
|||||||
data Screen = BalanceScreen -- ^ like hledger balance, shows accounts
|
data Screen = BalanceScreen -- ^ like hledger balance, shows accounts
|
||||||
| RegisterScreen -- ^ like hledger register, shows transaction-postings
|
| RegisterScreen -- ^ like hledger register, shows transaction-postings
|
||||||
| PrintScreen -- ^ like hledger print, shows ledger transactions
|
| PrintScreen -- ^ like hledger print, shows ledger transactions
|
||||||
| LedgerScreen -- ^ shows the raw ledger
|
-- | LedgerScreen -- ^ shows the raw ledger
|
||||||
deriving (Eq,Show)
|
deriving (Eq,Show)
|
||||||
|
|
||||||
-- | Run the interactive text ui.
|
-- | Run the interactive text ui.
|
||||||
@ -71,7 +69,7 @@ ui opts args l = do
|
|||||||
|
|
||||||
-- | Update the screen, wait for the next event, repeat.
|
-- | Update the screen, wait for the next event, repeat.
|
||||||
go :: AppState -> IO ()
|
go :: AppState -> IO ()
|
||||||
go a@AppState{av=av,aw=aw,ah=ah,abuf=buf,amsg=amsg,aopts=opts,aargs=args,aledger=l} = do
|
go a@AppState{av=av,aw=_,ah=_,abuf=_,amsg=_,aopts=opts,aargs=_,aledger=_} = do
|
||||||
when (not $ DebugNoUI `elem` opts) $ update av (renderScreen a)
|
when (not $ DebugNoUI `elem` opts) $ update av (renderScreen a)
|
||||||
k <- getEvent av
|
k <- getEvent av
|
||||||
case k of
|
case k of
|
||||||
@ -100,9 +98,6 @@ go a@AppState{av=av,aw=aw,ah=ah,abuf=buf,amsg=amsg,aopts=opts,aargs=args,aledger
|
|||||||
EvKey (KASCII 'q') [] -> shutdown av >> return ()
|
EvKey (KASCII 'q') [] -> shutdown av >> return ()
|
||||||
-- EvKey KEsc [] -> shutdown av >> return ()
|
-- EvKey KEsc [] -> shutdown av >> return ()
|
||||||
_ -> go a
|
_ -> go a
|
||||||
where
|
|
||||||
bh = length buf
|
|
||||||
y = posY a
|
|
||||||
|
|
||||||
-- app state modifiers
|
-- app state modifiers
|
||||||
|
|
||||||
@ -120,8 +115,13 @@ scrollY = sy . loc
|
|||||||
posY a = scrollY a + cursorY a
|
posY a = scrollY a + cursorY a
|
||||||
|
|
||||||
setCursorY, setScrollY, setPosY :: Int -> AppState -> AppState
|
setCursorY, setScrollY, setPosY :: Int -> AppState -> AppState
|
||||||
|
setCursorY _ AppState{alocs=[]} = error "shouldn't happen" -- silence warnings
|
||||||
setCursorY y a@AppState{alocs=(l:locs)} = a{alocs=(l':locs)} where l' = setLocCursorY y l
|
setCursorY y a@AppState{alocs=(l:locs)} = a{alocs=(l':locs)} where l' = setLocCursorY y l
|
||||||
|
|
||||||
|
setScrollY _ AppState{alocs=[]} = error "shouldn't happen" -- silence warnings
|
||||||
setScrollY y a@AppState{alocs=(l:locs)} = a{alocs=(l':locs)} where l' = setLocScrollY y l
|
setScrollY y a@AppState{alocs=(l:locs)} = a{alocs=(l':locs)} where l' = setLocScrollY y l
|
||||||
|
|
||||||
|
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
|
||||||
@ -129,6 +129,7 @@ setPosY y a@AppState{alocs=(l:locs)} = a{alocs=(l':locs)}
|
|||||||
cy = y `mod` ph
|
cy = y `mod` ph
|
||||||
sy = y - cy
|
sy = y - cy
|
||||||
|
|
||||||
|
|
||||||
updateCursorY, updateScrollY, updatePosY :: (Int -> Int) -> AppState -> AppState
|
updateCursorY, updateScrollY, updatePosY :: (Int -> Int) -> AppState -> AppState
|
||||||
updateCursorY f a = setCursorY (f $ cursorY a) a
|
updateCursorY f a = setCursorY (f $ cursorY a) a
|
||||||
updateScrollY f a = setScrollY (f $ scrollY a) a
|
updateScrollY f a = setScrollY (f $ scrollY a) a
|
||||||
@ -147,17 +148,19 @@ moveToBottom :: AppState -> AppState
|
|||||||
moveToBottom a = setPosY (length $ abuf a) a
|
moveToBottom a = setPosY (length $ abuf a) a
|
||||||
|
|
||||||
moveUpAndPushEdge :: AppState -> AppState
|
moveUpAndPushEdge :: AppState -> AppState
|
||||||
moveUpAndPushEdge a@AppState{alocs=(Loc{sy=sy,cy=cy}:_)}
|
moveUpAndPushEdge a
|
||||||
| cy > 0 = updateCursorY (subtract 1) a
|
| cy > 0 = updateCursorY (subtract 1) a
|
||||||
| sy > 0 = updateScrollY (subtract 1) a
|
| sy > 0 = updateScrollY (subtract 1) a
|
||||||
| otherwise = a
|
| otherwise = a
|
||||||
|
where Loc{sy=sy,cy=cy} = head $ alocs a
|
||||||
|
|
||||||
moveDownAndPushEdge :: AppState -> AppState
|
moveDownAndPushEdge :: AppState -> AppState
|
||||||
moveDownAndPushEdge a@AppState{alocs=(Loc{sy=sy,cy=cy}:_)}
|
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
|
||||||
ph = pageHeight a
|
ph = pageHeight a
|
||||||
bh = length $ abuf a
|
bh = length $ abuf a
|
||||||
|
|
||||||
@ -178,7 +181,7 @@ nextpage (a@AppState{abuf=b})
|
|||||||
-- without moving the cursor, or if we are scrolled as far as possible
|
-- without moving the cursor, or if we are scrolled as far as possible
|
||||||
-- then move the cursor to the first line.
|
-- then move the cursor to the first line.
|
||||||
prevpage :: AppState -> AppState
|
prevpage :: AppState -> AppState
|
||||||
prevpage (a@AppState{abuf=b})
|
prevpage a
|
||||||
| sy > 0 = setScrollY sy' a
|
| sy > 0 = setScrollY sy' a
|
||||||
| otherwise = setCursorY 0 a
|
| otherwise = setCursorY 0 a
|
||||||
where
|
where
|
||||||
@ -212,31 +215,30 @@ enter :: Screen -> AppState -> AppState
|
|||||||
enter scr@BalanceScreen a = updateData $ pushLoc Loc{scr=scr,sy=0,cy=0} a
|
enter scr@BalanceScreen a = updateData $ pushLoc Loc{scr=scr,sy=0,cy=0} a
|
||||||
enter scr@RegisterScreen a = updateData $ pushLoc Loc{scr=scr,sy=0,cy=0} a
|
enter scr@RegisterScreen a = updateData $ pushLoc Loc{scr=scr,sy=0,cy=0} a
|
||||||
enter scr@PrintScreen a = updateData $ pushLoc Loc{scr=scr,sy=0,cy=0} a
|
enter scr@PrintScreen a = updateData $ pushLoc Loc{scr=scr,sy=0,cy=0} a
|
||||||
enter scr@LedgerScreen a = updateData $ pushLoc Loc{scr=scr,sy=0,cy=0} a
|
-- enter scr@LedgerScreen a = updateData $ pushLoc Loc{scr=scr,sy=0,cy=0} a
|
||||||
|
|
||||||
resetTrailAndEnter scr a = enter scr $ clearLocs a
|
resetTrailAndEnter scr a = enter scr $ clearLocs a
|
||||||
|
|
||||||
-- | Regenerate the display data appropriate for the current screen.
|
-- | Regenerate the display data appropriate for the current screen.
|
||||||
updateData :: AppState -> AppState
|
updateData :: AppState -> AppState
|
||||||
updateData a@AppState{aopts=opts,aargs=args,aledger=l}
|
updateData a@AppState{aopts=opts,aargs=args,aledger=l} =
|
||||||
| scr == BalanceScreen = a{abuf=lines $ showBalanceReport opts [] l, aargs=[]}
|
case screen a of
|
||||||
| scr == RegisterScreen = a{abuf=lines $ showRegisterReport opts args l}
|
BalanceScreen -> a{abuf=lines $ showBalanceReport opts [] l, aargs=[]}
|
||||||
| scr == PrintScreen = a{abuf=lines $ showLedgerTransactions opts args l}
|
RegisterScreen -> a{abuf=lines $ showRegisterReport opts args l}
|
||||||
| scr == LedgerScreen = a{abuf=lines $ rawledgertext l}
|
PrintScreen -> a{abuf=lines $ showLedgerTransactions opts args l}
|
||||||
where scr = screen a
|
-- LedgerScreen -> a{abuf=lines $ rawledgertext l}
|
||||||
|
|
||||||
backout :: AppState -> AppState
|
backout :: AppState -> AppState
|
||||||
backout a
|
backout a | screen a == BalanceScreen = a
|
||||||
| screen a == BalanceScreen = a
|
| otherwise = updateData $ popLoc a
|
||||||
| otherwise = updateData $ popLoc a
|
|
||||||
|
|
||||||
drilldown :: AppState -> AppState
|
drilldown :: AppState -> AppState
|
||||||
drilldown a
|
drilldown a =
|
||||||
| screen a == BalanceScreen = enter RegisterScreen a{aargs=[currentAccountName a]}
|
case screen a of
|
||||||
| screen a == RegisterScreen = scrollToLedgerTransaction e $ enter PrintScreen a
|
BalanceScreen -> enter RegisterScreen a{aargs=[currentAccountName a]}
|
||||||
| screen a == PrintScreen = a
|
RegisterScreen -> scrollToLedgerTransaction e $ enter PrintScreen a
|
||||||
-- screen a == PrintScreen = enter LedgerScreen a
|
PrintScreen -> a
|
||||||
-- screen a == LedgerScreen = a
|
-- LedgerScreen -> a{abuf=lines $ rawledgertext l}
|
||||||
where e = currentLedgerTransaction a
|
where e = currentLedgerTransaction a
|
||||||
|
|
||||||
-- | Get the account name currently highlighted by the cursor on the
|
-- | Get the account name currently highlighted by the cursor on the
|
||||||
@ -350,28 +352,26 @@ renderStatus w s = renderBS statusattr (B.pack $ take w (s ++ repeat ' '))
|
|||||||
|
|
||||||
-- the all-important theming engine
|
-- the all-important theming engine
|
||||||
|
|
||||||
theme = 1
|
theme = Restrained
|
||||||
|
|
||||||
|
data UITheme = Restrained | Colorful | Blood
|
||||||
|
|
||||||
(defaultattr,
|
(defaultattr,
|
||||||
currentlineattr,
|
currentlineattr,
|
||||||
statusattr
|
statusattr
|
||||||
) =
|
) = case theme of
|
||||||
case theme of
|
Restrained -> (attr
|
||||||
1 -> ( -- restrained
|
,setBold attr
|
||||||
attr
|
,setRV attr
|
||||||
,setBold attr
|
)
|
||||||
,setRV attr
|
Colorful -> (setRV attr
|
||||||
)
|
,setFG white $ setBG red $ attr
|
||||||
2 -> ( -- colorful
|
,setFG black $ setBG green $ attr
|
||||||
setRV attr
|
)
|
||||||
,setFG white $ setBG red $ attr
|
Blood -> (setRV attr
|
||||||
,setFG black $ setBG green $ attr
|
,setFG white $ setBG red $ attr
|
||||||
)
|
,setRV attr
|
||||||
3 -> ( --
|
)
|
||||||
setRV attr
|
|
||||||
,setFG white $ setBG red $ attr
|
|
||||||
,setRV attr
|
|
||||||
)
|
|
||||||
|
|
||||||
halfbrightattr = setHalfBright attr
|
halfbrightattr = setHalfBright attr
|
||||||
reverseattr = setRV attr
|
reverseattr = setRV attr
|
||||||
|
|||||||
@ -4,23 +4,13 @@ A happs-based web UI for hledger.
|
|||||||
|
|
||||||
module Commands.Web
|
module Commands.Web
|
||||||
where
|
where
|
||||||
import Control.Monad.Trans (liftIO)
|
|
||||||
import Data.ByteString.Lazy.UTF8 (toString)
|
|
||||||
import qualified Data.Map as M
|
|
||||||
-- import Data.Map ((!))
|
|
||||||
import Data.Time.Clock
|
|
||||||
import Data.Time.Format
|
|
||||||
import Locale
|
|
||||||
import Control.Concurrent
|
import Control.Concurrent
|
||||||
import qualified Data.ByteString.Lazy.Char8 as B
|
|
||||||
import Happstack.Data (defaultValue)
|
|
||||||
import Happstack.Server
|
import Happstack.Server
|
||||||
import Happstack.Server.HTTP.FileServe (fileServe)
|
|
||||||
import Happstack.State.Control (waitForTermination)
|
import Happstack.State.Control (waitForTermination)
|
||||||
import System.Cmd (system)
|
import System.Cmd (system)
|
||||||
import System.Info (os)
|
import System.Info (os)
|
||||||
import System.Exit
|
import System.Exit
|
||||||
import Network.HTTP (urlEncode, urlDecode, urlEncodeVars)
|
import Network.HTTP (urlEncode, urlDecode)
|
||||||
import Text.XHtml hiding (dir)
|
import Text.XHtml hiding (dir)
|
||||||
|
|
||||||
import Ledger
|
import Ledger
|
||||||
@ -122,7 +112,7 @@ searchform r a p' =
|
|||||||
| otherwise = spaceHtml +++ anchor ! [href u] << stringToHtml "reset"
|
| otherwise = spaceHtml +++ anchor ! [href u] << stringToHtml "reset"
|
||||||
|
|
||||||
navlinks :: Request -> String -> String -> Html
|
navlinks :: Request -> String -> String -> Html
|
||||||
navlinks r a p' =
|
navlinks _ a p' =
|
||||||
concatHtml $ intersperse sep $ map linkto ["balance", "register", "print", "histogram"]
|
concatHtml $ intersperse sep $ map linkto ["balance", "register", "print", "histogram"]
|
||||||
where
|
where
|
||||||
sep = stringToHtml " | "
|
sep = stringToHtml " | "
|
||||||
|
|||||||
@ -10,7 +10,7 @@ module Ledger.AccountName
|
|||||||
where
|
where
|
||||||
import Ledger.Utils
|
import Ledger.Utils
|
||||||
import Ledger.Types
|
import Ledger.Types
|
||||||
import Data.Map ((!), fromList, Map)
|
import Data.Map (Map)
|
||||||
import qualified Data.Map as M
|
import qualified Data.Map as M
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -39,7 +39,6 @@ examples:
|
|||||||
|
|
||||||
module Ledger.Amount
|
module Ledger.Amount
|
||||||
where
|
where
|
||||||
import qualified Data.Map as Map
|
|
||||||
import Ledger.Utils
|
import Ledger.Utils
|
||||||
import Ledger.Types
|
import Ledger.Types
|
||||||
import Ledger.Commodity
|
import Ledger.Commodity
|
||||||
@ -77,13 +76,13 @@ negateAmountPreservingPrice a = (-a){price=price a}
|
|||||||
-- any price information. (Using the second commodity is best since sum
|
-- any price information. (Using the second commodity is best since sum
|
||||||
-- and other folds start with a no-commodity amount.)
|
-- and other folds start with a no-commodity amount.)
|
||||||
amountop :: (Double -> Double -> Double) -> Amount -> Amount -> Amount
|
amountop :: (Double -> Double -> Double) -> Amount -> Amount -> Amount
|
||||||
amountop op a@(Amount ac aq ap) b@(Amount bc bq bp) =
|
amountop op a@(Amount _ _ _) (Amount bc bq _) =
|
||||||
Amount bc ((quantity $ convertAmountTo bc a) `op` bq) Nothing
|
Amount bc ((quantity $ convertAmountTo bc a) `op` bq) Nothing
|
||||||
|
|
||||||
-- | Convert an amount to the commodity of its saved price, if any.
|
-- | Convert an amount to the commodity of its saved price, if any.
|
||||||
costOfAmount :: Amount -> Amount
|
costOfAmount :: Amount -> Amount
|
||||||
costOfAmount a@(Amount _ _ Nothing) = a
|
costOfAmount a@(Amount _ _ Nothing) = a
|
||||||
costOfAmount a@(Amount _ q (Just price))
|
costOfAmount (Amount _ q (Just price))
|
||||||
| isZeroMixedAmount price = nullamt
|
| isZeroMixedAmount price = nullamt
|
||||||
| otherwise = Amount pc (pq*q) Nothing
|
| otherwise = Amount pc (pq*q) Nothing
|
||||||
where (Amount pc pq _) = head $ amounts price
|
where (Amount pc pq _) = head $ amounts price
|
||||||
@ -91,15 +90,16 @@ costOfAmount a@(Amount _ q (Just price))
|
|||||||
-- | Convert an amount to the specified commodity using the appropriate
|
-- | Convert an amount to the specified commodity using the appropriate
|
||||||
-- exchange rate (which is currently always 1).
|
-- exchange rate (which is currently always 1).
|
||||||
convertAmountTo :: Commodity -> Amount -> Amount
|
convertAmountTo :: Commodity -> Amount -> Amount
|
||||||
convertAmountTo c2 (Amount c1 q p) = Amount c2 (q * conversionRate c1 c2) Nothing
|
convertAmountTo c2 (Amount c1 q _) = Amount c2 (q * conversionRate c1 c2) Nothing
|
||||||
|
|
||||||
-- | Get the string representation of an amount, based on its commodity's
|
-- | Get the string representation of an amount, based on its commodity's
|
||||||
-- display settings.
|
-- display settings.
|
||||||
showAmount :: Amount -> String
|
showAmount :: Amount -> String
|
||||||
showAmount a@(Amount (Commodity {symbol=sym,side=side,spaced=spaced}) q pri)
|
showAmount (Amount (Commodity {symbol="AUTO"}) _ _) = "" -- can appear in an error message
|
||||||
| sym=="AUTO" = "" -- can display one of these in an error message
|
showAmount a@(Amount (Commodity {symbol=sym,side=side,spaced=spaced}) _ pri) =
|
||||||
| side==L = printf "%s%s%s%s" sym space quantity price
|
case side of
|
||||||
| side==R = printf "%s%s%s%s" quantity space sym price
|
L -> printf "%s%s%s%s" sym space quantity price
|
||||||
|
R -> printf "%s%s%s%s" quantity space sym price
|
||||||
where
|
where
|
||||||
space = if spaced then " " else ""
|
space = if spaced then " " else ""
|
||||||
quantity = showAmount' a
|
quantity = showAmount' a
|
||||||
|
|||||||
@ -8,7 +8,6 @@ are thousands separated by comma, significant decimal places and so on.
|
|||||||
-}
|
-}
|
||||||
module Ledger.Commodity
|
module Ledger.Commodity
|
||||||
where
|
where
|
||||||
import qualified Data.Map as Map
|
|
||||||
import Ledger.Utils
|
import Ledger.Utils
|
||||||
import Ledger.Types
|
import Ledger.Types
|
||||||
|
|
||||||
@ -36,5 +35,5 @@ comm sym = fromMaybe
|
|||||||
|
|
||||||
-- | Find the conversion rate between two commodities. Currently returns 1.
|
-- | Find the conversion rate between two commodities. Currently returns 1.
|
||||||
conversionRate :: Commodity -> Commodity -> Double
|
conversionRate :: Commodity -> Commodity -> Double
|
||||||
conversionRate oldc newc = 1
|
conversionRate _ _ = 1
|
||||||
|
|
||||||
|
|||||||
@ -19,16 +19,9 @@ quarterly, etc.
|
|||||||
module Ledger.Dates
|
module Ledger.Dates
|
||||||
where
|
where
|
||||||
|
|
||||||
import Data.Time.Clock
|
|
||||||
import Data.Time.Format
|
import Data.Time.Format
|
||||||
import Data.Time.Calendar
|
|
||||||
import Data.Time.Calendar.MonthDay
|
|
||||||
import Data.Time.Calendar.OrdinalDate
|
import Data.Time.Calendar.OrdinalDate
|
||||||
import Data.Time.Calendar.WeekDate
|
|
||||||
import Data.Time.LocalTime
|
|
||||||
import Locale (defaultTimeLocale)
|
import Locale (defaultTimeLocale)
|
||||||
import Text.Printf
|
|
||||||
import Data.Maybe
|
|
||||||
import Text.ParserCombinators.Parsec
|
import Text.ParserCombinators.Parsec
|
||||||
import Text.ParserCombinators.Parsec.Char
|
import Text.ParserCombinators.Parsec.Char
|
||||||
import Text.ParserCombinators.Parsec.Combinator
|
import Text.ParserCombinators.Parsec.Combinator
|
||||||
@ -49,24 +42,29 @@ elapsedSeconds t1 t2 = realToFrac $ diffUTCTime t1 t2
|
|||||||
|
|
||||||
-- | Split a DateSpan into one or more consecutive spans at the specified interval.
|
-- | Split a DateSpan into one or more consecutive spans at the specified interval.
|
||||||
splitSpan :: Interval -> DateSpan -> [DateSpan]
|
splitSpan :: Interval -> DateSpan -> [DateSpan]
|
||||||
splitSpan i (DateSpan Nothing Nothing) = [DateSpan Nothing Nothing]
|
splitSpan _ (DateSpan Nothing Nothing) = [DateSpan Nothing Nothing]
|
||||||
splitSpan NoInterval s = [s]
|
splitSpan NoInterval s = [s]
|
||||||
splitSpan Daily s = splitspan start next s where (start,next) = (startofday,nextday)
|
splitSpan Daily s = splitspan startofday nextday s
|
||||||
splitSpan Weekly s = splitspan start next s where (start,next) = (startofweek,nextweek)
|
splitSpan Weekly s = splitspan startofweek nextweek s
|
||||||
splitSpan Monthly s = splitspan start next s where (start,next) = (startofmonth,nextmonth)
|
splitSpan Monthly s = splitspan startofmonth nextmonth s
|
||||||
splitSpan Quarterly s = splitspan start next s where (start,next) = (startofquarter,nextquarter)
|
splitSpan Quarterly s = splitspan startofquarter nextquarter s
|
||||||
splitSpan Yearly s = splitspan start next s where (start,next) = (startofyear,nextyear)
|
splitSpan Yearly s = splitspan startofyear nextyear s
|
||||||
|
|
||||||
|
splitspan :: (Day -> Day) -> (Day -> Day) -> DateSpan -> [DateSpan]
|
||||||
splitspan _ _ (DateSpan Nothing Nothing) = []
|
splitspan _ _ (DateSpan Nothing Nothing) = []
|
||||||
splitspan startof next (DateSpan Nothing (Just e)) = [DateSpan (Just $ startof e) (Just $ next $ startof e)]
|
splitspan start next (DateSpan Nothing (Just e)) = [DateSpan (Just $ start e) (Just $ next $ start e)]
|
||||||
splitspan startof next (DateSpan (Just b) Nothing) = [DateSpan (Just $ startof b) (Just $ next $ startof b)]
|
splitspan start next (DateSpan (Just b) Nothing) = [DateSpan (Just $ start b) (Just $ next $ start b)]
|
||||||
splitspan startof next s@(DateSpan (Just b) (Just e))
|
splitspan start next span@(DateSpan (Just b) (Just e))
|
||||||
| b == e = [s]
|
| b == e = [span]
|
||||||
| otherwise = splitspan' startof next s
|
| otherwise = splitspan' start next span
|
||||||
where splitspan' startof next (DateSpan (Just b) (Just e))
|
where
|
||||||
| b >= e = []
|
splitspan' start next (DateSpan (Just b) (Just e))
|
||||||
| otherwise = [DateSpan (Just $ startof b) (Just $ next $ startof b)]
|
| b >= e = []
|
||||||
++ splitspan' startof next (DateSpan (Just $ next $ startof b) (Just e))
|
| otherwise = [DateSpan (Just s) (Just n)]
|
||||||
|
++ splitspan' start next (DateSpan (Just n) (Just e))
|
||||||
|
where s = start b
|
||||||
|
n = next s
|
||||||
|
splitspan' _ _ _ = error "won't happen, avoids warnings"
|
||||||
|
|
||||||
-- | Count the days in a DateSpan, or if it is open-ended return Nothing.
|
-- | Count the days in a DateSpan, or if it is open-ended return Nothing.
|
||||||
daysInSpan :: DateSpan -> Maybe Integer
|
daysInSpan :: DateSpan -> Maybe Integer
|
||||||
@ -89,7 +87,7 @@ spanFromSmartDateString refdate s = spanFromSmartDate refdate sdate
|
|||||||
spanFromSmartDate :: Day -> SmartDate -> DateSpan
|
spanFromSmartDate :: Day -> SmartDate -> DateSpan
|
||||||
spanFromSmartDate refdate sdate = DateSpan (Just b) (Just e)
|
spanFromSmartDate refdate sdate = DateSpan (Just b) (Just e)
|
||||||
where
|
where
|
||||||
(ry,rm,rd) = toGregorian refdate
|
(ry,rm,_) = toGregorian refdate
|
||||||
(b,e) = span sdate
|
(b,e) = span sdate
|
||||||
span :: SmartDate -> (Day,Day)
|
span :: SmartDate -> (Day,Day)
|
||||||
span ("","","today") = (refdate, nextday refdate)
|
span ("","","today") = (refdate, nextday refdate)
|
||||||
|
|||||||
@ -5,8 +5,6 @@ Utilities for doing I/O with ledger files.
|
|||||||
module Ledger.IO
|
module Ledger.IO
|
||||||
where
|
where
|
||||||
import Control.Monad.Error
|
import Control.Monad.Error
|
||||||
import Data.Time.Clock
|
|
||||||
import Data.Time.LocalTime (LocalTime)
|
|
||||||
import Ledger.Ledger (cacheLedger)
|
import Ledger.Ledger (cacheLedger)
|
||||||
import Ledger.Parse (parseLedger)
|
import Ledger.Parse (parseLedger)
|
||||||
import Ledger.RawLedger (canonicaliseAmounts,filterRawLedger)
|
import Ledger.RawLedger (canonicaliseAmounts,filterRawLedger)
|
||||||
@ -15,8 +13,6 @@ import Ledger.Utils (getCurrentLocalTime)
|
|||||||
import System.Directory (getHomeDirectory)
|
import System.Directory (getHomeDirectory)
|
||||||
import System.Environment (getEnv)
|
import System.Environment (getEnv)
|
||||||
import System.IO
|
import System.IO
|
||||||
import Text.ParserCombinators.Parsec
|
|
||||||
import qualified Data.Map as Map (lookup)
|
|
||||||
import System.FilePath ((</>))
|
import System.FilePath ((</>))
|
||||||
|
|
||||||
|
|
||||||
@ -81,7 +77,6 @@ readLedger = readLedgerWithIOArgs noioargs
|
|||||||
-- | or give an error.
|
-- | or give an error.
|
||||||
readLedgerWithIOArgs :: IOArgs -> FilePath -> IO Ledger
|
readLedgerWithIOArgs :: IOArgs -> FilePath -> IO Ledger
|
||||||
readLedgerWithIOArgs ioargs f = do
|
readLedgerWithIOArgs ioargs f = do
|
||||||
t <- getCurrentLocalTime
|
|
||||||
s <- readFile f
|
s <- readFile f
|
||||||
rl <- rawLedgerFromString s
|
rl <- rawLedgerFromString s
|
||||||
return $ filterAndCacheLedger ioargs s rl
|
return $ filterAndCacheLedger ioargs s rl
|
||||||
|
|||||||
@ -57,12 +57,10 @@ import qualified Data.Map as Map
|
|||||||
import Data.Map ((!))
|
import Data.Map ((!))
|
||||||
import Ledger.Utils
|
import Ledger.Utils
|
||||||
import Ledger.Types
|
import Ledger.Types
|
||||||
import Ledger.Amount
|
import Ledger.Account ()
|
||||||
import Ledger.AccountName
|
import Ledger.AccountName
|
||||||
import Ledger.Account
|
|
||||||
import Ledger.Transaction
|
import Ledger.Transaction
|
||||||
import Ledger.RawLedger
|
import Ledger.RawLedger
|
||||||
import Ledger.LedgerTransaction
|
|
||||||
|
|
||||||
|
|
||||||
instance Show Ledger where
|
instance Show Ledger where
|
||||||
|
|||||||
@ -57,15 +57,13 @@ showLedgerTransactionUnelided = showLedgerTransaction' False
|
|||||||
|
|
||||||
showLedgerTransaction' :: Bool -> LedgerTransaction -> String
|
showLedgerTransaction' :: Bool -> LedgerTransaction -> String
|
||||||
showLedgerTransaction' elide t =
|
showLedgerTransaction' elide t =
|
||||||
unlines $ [{-precedingcomment ++ -}description] ++ (showpostings $ ltpostings t) ++ [""]
|
unlines $ [description] ++ (showpostings $ ltpostings t) ++ [""]
|
||||||
where
|
where
|
||||||
precedingcomment = ltpreceding_comment_lines t
|
|
||||||
description = concat [date, status, code, desc] -- , comment]
|
description = concat [date, status, code, desc] -- , comment]
|
||||||
date = showdate $ ltdate t
|
date = showdate $ ltdate t
|
||||||
status = if ltstatus t then " *" else ""
|
status = if ltstatus t then " *" else ""
|
||||||
code = if (length $ ltcode t) > 0 then (printf " (%s)" $ ltcode t) else ""
|
code = if (length $ ltcode t) > 0 then (printf " (%s)" $ ltcode t) else ""
|
||||||
desc = " " ++ ltdescription t
|
desc = " " ++ ltdescription t
|
||||||
comment = if (length $ ltcomment t) > 0 then " ; "++(ltcomment t) else ""
|
|
||||||
showdate d = printf "%-10s" (showDate d)
|
showdate d = printf "%-10s" (showDate d)
|
||||||
showpostings ps
|
showpostings ps
|
||||||
| elide && length ps > 1 && isLedgerTransactionBalanced t
|
| elide && length ps > 1 && isLedgerTransactionBalanced t
|
||||||
|
|||||||
@ -7,28 +7,19 @@ Parsers for standard ledger and timelog files.
|
|||||||
module Ledger.Parse
|
module Ledger.Parse
|
||||||
where
|
where
|
||||||
import Prelude hiding (readFile, putStr, print)
|
import Prelude hiding (readFile, putStr, print)
|
||||||
import Control.Monad
|
|
||||||
import Control.Monad.Error
|
import Control.Monad.Error
|
||||||
import Text.ParserCombinators.Parsec
|
import Text.ParserCombinators.Parsec
|
||||||
import Text.ParserCombinators.Parsec.Char
|
import Text.ParserCombinators.Parsec.Char
|
||||||
import Text.ParserCombinators.Parsec.Language
|
|
||||||
import Text.ParserCombinators.Parsec.Combinator
|
import Text.ParserCombinators.Parsec.Combinator
|
||||||
import qualified Text.ParserCombinators.Parsec.Token as P
|
|
||||||
import System.Directory
|
import System.Directory
|
||||||
import System.IO.UTF8
|
import System.IO.UTF8
|
||||||
import System.IO (stdin)
|
import System.IO (stdin)
|
||||||
import qualified Data.Map as Map
|
|
||||||
import Data.Time.LocalTime
|
|
||||||
import Data.Time.Calendar
|
|
||||||
import Ledger.Utils
|
import Ledger.Utils
|
||||||
import Ledger.Types
|
import Ledger.Types
|
||||||
import Ledger.Dates
|
import Ledger.Dates
|
||||||
import Ledger.AccountName
|
|
||||||
import Ledger.Amount
|
import Ledger.Amount
|
||||||
import Ledger.LedgerTransaction
|
import Ledger.LedgerTransaction
|
||||||
import Ledger.Posting
|
import Ledger.Posting
|
||||||
import Ledger.Commodity
|
|
||||||
import Ledger.TimeLog
|
|
||||||
import Ledger.RawLedger
|
import Ledger.RawLedger
|
||||||
import System.FilePath(takeDirectory,combine)
|
import System.FilePath(takeDirectory,combine)
|
||||||
|
|
||||||
@ -111,6 +102,7 @@ ledgerDirective = do char '!' <?> "directive"
|
|||||||
"include" -> ledgerInclude
|
"include" -> ledgerInclude
|
||||||
"account" -> ledgerAccountBegin
|
"account" -> ledgerAccountBegin
|
||||||
"end" -> ledgerAccountEnd
|
"end" -> ledgerAccountEnd
|
||||||
|
_ -> mzero
|
||||||
|
|
||||||
ledgerInclude :: GenParser Char LedgerFileCtx (ErrorT String IO (RawLedger -> RawLedger))
|
ledgerInclude :: GenParser Char LedgerFileCtx (ErrorT String IO (RawLedger -> RawLedger))
|
||||||
ledgerInclude = do many1 spacenonewline
|
ledgerInclude = do many1 spacenonewline
|
||||||
@ -291,9 +283,9 @@ ledgerHistoricalPrice = do
|
|||||||
many spacenonewline
|
many spacenonewline
|
||||||
symbol1 <- commoditysymbol
|
symbol1 <- commoditysymbol
|
||||||
many spacenonewline
|
many spacenonewline
|
||||||
(Mixed [Amount c price pri]) <- someamount
|
(Mixed [Amount c q _]) <- someamount
|
||||||
restofline
|
restofline
|
||||||
return $ HistoricalPrice date symbol1 (symbol c) price
|
return $ HistoricalPrice date symbol1 (symbol c) q
|
||||||
|
|
||||||
-- like ledgerAccountBegin, updates the LedgerFileCtx
|
-- like ledgerAccountBegin, updates the LedgerFileCtx
|
||||||
ledgerDefaultYear :: GenParser Char LedgerFileCtx (ErrorT String IO (RawLedger -> RawLedger))
|
ledgerDefaultYear :: GenParser Char LedgerFileCtx (ErrorT String IO (RawLedger -> RawLedger))
|
||||||
@ -373,7 +365,6 @@ ledgerposting = do
|
|||||||
many spacenonewline
|
many spacenonewline
|
||||||
comment <- ledgercomment
|
comment <- ledgercomment
|
||||||
restofline
|
restofline
|
||||||
parent <- getParentAccount
|
|
||||||
return (Posting status account' amount comment ptype)
|
return (Posting status account' amount comment ptype)
|
||||||
|
|
||||||
-- Qualify with the parent account from parsing context
|
-- Qualify with the parent account from parsing context
|
||||||
@ -542,16 +533,16 @@ datedisplayexpr = do
|
|||||||
char '['
|
char '['
|
||||||
(y,m,d) <- smartdate
|
(y,m,d) <- smartdate
|
||||||
char ']'
|
char ']'
|
||||||
let ltdate = parsedate $ printf "%04s/%02s/%02s" y m d
|
let date = parsedate $ printf "%04s/%02s/%02s" y m d
|
||||||
let matcher = \(Transaction{tdate=d}) ->
|
test op = return $ (`op` date) . tdate
|
||||||
case op of
|
case op of
|
||||||
"<" -> d < ltdate
|
"<" -> test (<)
|
||||||
"<=" -> d <= ltdate
|
"<=" -> test (<=)
|
||||||
"=" -> d == ltdate
|
"=" -> test (==)
|
||||||
"==" -> d == ltdate -- just in case
|
"==" -> test (==)
|
||||||
">=" -> d >= ltdate
|
">=" -> test (>=)
|
||||||
">" -> d > ltdate
|
">" -> test (>)
|
||||||
return matcher
|
_ -> mzero
|
||||||
|
|
||||||
compareop = choice $ map (try . string) ["<=",">=","==","<","=",">"]
|
compareop = choice $ map (try . string) ["<=",">=","==","<","=",">"]
|
||||||
|
|
||||||
|
|||||||
@ -22,14 +22,14 @@ instance Show Posting where show = showPosting
|
|||||||
nullrawposting = Posting False "" nullmixedamt "" RegularPosting
|
nullrawposting = Posting False "" nullmixedamt "" RegularPosting
|
||||||
|
|
||||||
showPosting :: Posting -> String
|
showPosting :: Posting -> String
|
||||||
showPosting (Posting s a amt _ ttype) =
|
showPosting (Posting _ a amt _ ttype) =
|
||||||
concatTopPadded [showaccountname a ++ " ", showamount amt]
|
concatTopPadded [showaccountname a ++ " ", showamount amt]
|
||||||
where
|
where
|
||||||
showaccountname = printf "%-22s" . bracket . elideAccountName width
|
showaccountname = printf "%-22s" . bracket . elideAccountName width
|
||||||
(bracket,width) = case ttype of
|
(bracket,width) = case ttype of
|
||||||
BalancedVirtualPosting -> (\s -> "["++s++"]", 20)
|
BalancedVirtualPosting -> (\s -> "["++s++"]", 20)
|
||||||
VirtualPosting -> (\s -> "("++s++")", 20)
|
VirtualPosting -> (\s -> "("++s++")", 20)
|
||||||
otherwise -> (id,22)
|
_ -> (id,22)
|
||||||
showamount = padleft 12 . showMixedAmountOrZero
|
showamount = padleft 12 . showMixedAmountOrZero
|
||||||
|
|
||||||
isReal :: Posting -> Bool
|
isReal :: Posting -> Bool
|
||||||
|
|||||||
@ -13,7 +13,6 @@ import Ledger.Utils
|
|||||||
import Ledger.Types
|
import Ledger.Types
|
||||||
import Ledger.AccountName
|
import Ledger.AccountName
|
||||||
import Ledger.Amount
|
import Ledger.Amount
|
||||||
import Ledger.LedgerTransaction
|
|
||||||
import Ledger.Transaction
|
import Ledger.Transaction
|
||||||
import Ledger.Posting
|
import Ledger.Posting
|
||||||
import Ledger.TimeLog
|
import Ledger.TimeLog
|
||||||
|
|||||||
@ -12,7 +12,6 @@ import Ledger.Utils
|
|||||||
import Ledger.Types
|
import Ledger.Types
|
||||||
import Ledger.Dates
|
import Ledger.Dates
|
||||||
import Ledger.Commodity
|
import Ledger.Commodity
|
||||||
import Ledger.Amount
|
|
||||||
import Ledger.LedgerTransaction
|
import Ledger.LedgerTransaction
|
||||||
|
|
||||||
instance Show TimeLogEntry where
|
instance Show TimeLogEntry where
|
||||||
@ -82,7 +81,6 @@ entryFromTimeLogInOut i o
|
|||||||
itod = localTimeOfDay itime
|
itod = localTimeOfDay itime
|
||||||
otod = localTimeOfDay otime
|
otod = localTimeOfDay otime
|
||||||
idate = localDay itime
|
idate = localDay itime
|
||||||
odate = localDay otime
|
|
||||||
hrs = elapsedSeconds (toutc otime) (toutc itime) / 3600 where toutc = localTimeToUTC utc
|
hrs = elapsedSeconds (toutc otime) (toutc itime) / 3600 where toutc = localTimeToUTC utc
|
||||||
amount = Mixed [hours hrs]
|
amount = Mixed [hours hrs]
|
||||||
ps = [Posting False acctname amount "" RegularPosting
|
ps = [Posting False acctname amount "" RegularPosting
|
||||||
|
|||||||
@ -15,14 +15,13 @@ import Ledger.Utils
|
|||||||
import Ledger.Types
|
import Ledger.Types
|
||||||
import Ledger.Dates
|
import Ledger.Dates
|
||||||
import Ledger.LedgerTransaction (showAccountName)
|
import Ledger.LedgerTransaction (showAccountName)
|
||||||
import Ledger.Posting
|
|
||||||
import Ledger.Amount
|
import Ledger.Amount
|
||||||
|
|
||||||
|
|
||||||
instance Show Transaction where show=showTransaction
|
instance Show Transaction where show=showTransaction
|
||||||
|
|
||||||
showTransaction :: Transaction -> String
|
showTransaction :: Transaction -> String
|
||||||
showTransaction (Transaction eno stat d desc a amt ttype) =
|
showTransaction (Transaction _ stat d desc a amt ttype) =
|
||||||
s ++ unwords [showDate d,desc,a',show amt,show ttype]
|
s ++ unwords [showDate d,desc,a',show amt,show ttype]
|
||||||
where s = if stat then " *" else ""
|
where s = if stat then " *" else ""
|
||||||
a' = showAccountName Nothing ttype a
|
a' = showAccountName Nothing ttype a
|
||||||
|
|||||||
@ -150,7 +150,7 @@ difforzero a b = maximum [(a - b), 0]
|
|||||||
containsRegex :: String -> String -> Bool
|
containsRegex :: String -> String -> Bool
|
||||||
containsRegex r s = case matchRegexPR ("(?i)"++r) s of
|
containsRegex r s = case matchRegexPR ("(?i)"++r) s of
|
||||||
Just _ -> True
|
Just _ -> True
|
||||||
otherwise -> False
|
_ -> False
|
||||||
|
|
||||||
|
|
||||||
-- lists
|
-- lists
|
||||||
@ -184,7 +184,7 @@ subtreeat v t
|
|||||||
-- | get the sub-tree for the specified node value in the first tree in
|
-- | get the sub-tree for the specified node value in the first tree in
|
||||||
-- forest in which it occurs.
|
-- forest in which it occurs.
|
||||||
subtreeinforest :: Eq a => a -> [Tree a] -> Maybe (Tree a)
|
subtreeinforest :: Eq a => a -> [Tree a] -> Maybe (Tree a)
|
||||||
subtreeinforest v [] = Nothing
|
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
|
||||||
|
|||||||
30
Options.hs
30
Options.hs
@ -5,15 +5,9 @@ Command-line options for the application.
|
|||||||
|
|
||||||
module Options
|
module Options
|
||||||
where
|
where
|
||||||
import System
|
|
||||||
import System.Console.GetOpt
|
import System.Console.GetOpt
|
||||||
import System.Environment
|
import System.Environment
|
||||||
import Text.Printf
|
import Ledger.IO (IOArgs,myLedgerPath,myTimelogPath)
|
||||||
import Data.Char (toLower)
|
|
||||||
import Ledger.IO (IOArgs,
|
|
||||||
ledgerenvvar,myLedgerPath,
|
|
||||||
timelogenvvar,myTimelogPath)
|
|
||||||
import Ledger.Parse
|
|
||||||
import Ledger.Utils
|
import Ledger.Utils
|
||||||
import Ledger.Types
|
import Ledger.Types
|
||||||
import Ledger.Dates
|
import Ledger.Dates
|
||||||
@ -176,19 +170,17 @@ dateSpanFromOpts refdate opts
|
|||||||
-- | Figure out the reporting interval, if any, specified by the options.
|
-- | Figure out the reporting interval, if any, specified by the options.
|
||||||
-- If there is a period option, the others are ignored.
|
-- If there is a period option, the others are ignored.
|
||||||
intervalFromOpts :: [Opt] -> Interval
|
intervalFromOpts :: [Opt] -> Interval
|
||||||
intervalFromOpts opts
|
intervalFromOpts opts =
|
||||||
| not $ null popts = fst $ parsePeriodExpr refdate $ last popts
|
case (periodopts, intervalopts) of
|
||||||
| null otheropts = NoInterval
|
((p:_), _) -> fst $ parsePeriodExpr d p where d = parsedate "0001/01/01" -- unused
|
||||||
| otherwise = case last otheropts of
|
(_, (WeeklyOpt:_)) -> Weekly
|
||||||
WeeklyOpt -> Weekly
|
(_, (MonthlyOpt:_)) -> Monthly
|
||||||
MonthlyOpt -> Monthly
|
(_, (QuarterlyOpt:_)) -> Quarterly
|
||||||
QuarterlyOpt -> Quarterly
|
(_, (YearlyOpt:_)) -> Yearly
|
||||||
YearlyOpt -> Yearly
|
(_, _) -> NoInterval
|
||||||
where
|
where
|
||||||
popts = optValuesForConstructor Period opts
|
periodopts = reverse $ optValuesForConstructor Period opts
|
||||||
otheropts = filter (`elem` [WeeklyOpt,MonthlyOpt,QuarterlyOpt,YearlyOpt]) opts
|
intervalopts = reverse $ filter (`elem` [WeeklyOpt,MonthlyOpt,QuarterlyOpt,YearlyOpt]) opts
|
||||||
-- doesn't affect the interval, but parsePeriodExpr needs something
|
|
||||||
refdate = parsedate "0001/01/01"
|
|
||||||
|
|
||||||
-- | Get the value of the (last) depth option, if any, otherwise a large number.
|
-- | Get the value of the (last) depth option, if any, otherwise a large number.
|
||||||
depthFromOpts :: [Opt] -> Int
|
depthFromOpts :: [Opt] -> Int
|
||||||
|
|||||||
11
Tests.hs
11
Tests.hs
@ -171,8 +171,7 @@ import qualified Data.Map as Map
|
|||||||
import Data.Time.Format
|
import Data.Time.Format
|
||||||
import Locale (defaultTimeLocale)
|
import Locale (defaultTimeLocale)
|
||||||
import Text.ParserCombinators.Parsec
|
import Text.ParserCombinators.Parsec
|
||||||
import Test.HUnit
|
import Test.HUnit.Tools (runVerboseTests)
|
||||||
import Test.HUnit.Tools (assertRaises, runVerboseTests)
|
|
||||||
|
|
||||||
import Commands.All
|
import Commands.All
|
||||||
import Ledger
|
import Ledger
|
||||||
@ -180,12 +179,12 @@ import Options
|
|||||||
import Utils
|
import Utils
|
||||||
|
|
||||||
|
|
||||||
runtests opts args = runner flattests
|
runtests opts args = runner ts
|
||||||
where
|
where
|
||||||
runner | (Verbose `elem` opts) = runVerboseTests
|
runner | (Verbose `elem` opts) = runVerboseTests
|
||||||
| otherwise = \t -> runTestTT t >>= return . (flip (,) 0)
|
| otherwise = \t -> runTestTT t >>= return . (flip (,) 0)
|
||||||
flattests = TestList $ filter matchname $ concatMap tflatten tests
|
ts = TestList $ filter matchname $ concatMap tflatten tests
|
||||||
deeptests = tfilter matchname $ TestList tests
|
--ts = tfilter matchname $ TestList tests -- unflattened
|
||||||
matchname = matchpats args . tname
|
matchname = matchpats args . tname
|
||||||
|
|
||||||
-- | Get a Test's label, or the empty string.
|
-- | Get a Test's label, or the empty string.
|
||||||
@ -482,7 +481,6 @@ tests = [
|
|||||||
nowstr = showtime now
|
nowstr = showtime now
|
||||||
yesterday = prevday today
|
yesterday = prevday today
|
||||||
clockin t a = TimeLogEntry In t a
|
clockin t a = TimeLogEntry In t a
|
||||||
clockout t = TimeLogEntry Out t ""
|
|
||||||
mktime d s = LocalTime d $ fromMaybe midnight $ parseTime defaultTimeLocale "%H:%M:%S" s
|
mktime d s = LocalTime d $ fromMaybe midnight $ parseTime defaultTimeLocale "%H:%M:%S" s
|
||||||
showtime t = formatTime defaultTimeLocale "%H:%M" t
|
showtime t = formatTime defaultTimeLocale "%H:%M" t
|
||||||
assertEntriesGiveStrings name es ss = assertEqual name ss (map ltdescription $ entriesFromTimeLogEntries now es)
|
assertEntriesGiveStrings name es ss = assertEqual name ss (map ltdescription $ entriesFromTimeLogEntries now es)
|
||||||
@ -582,7 +580,6 @@ tests = [
|
|||||||
return ()
|
return ()
|
||||||
|
|
||||||
,"ledgerFile" ~: do
|
,"ledgerFile" ~: do
|
||||||
let now = getCurrentLocalTime
|
|
||||||
assertBool "ledgerFile should parse an empty file" $ (isRight $ parseWithCtx ledgerFile "")
|
assertBool "ledgerFile should parse an empty file" $ (isRight $ parseWithCtx ledgerFile "")
|
||||||
r <- rawLedgerFromString "" -- don't know how to get it from ledgerFile
|
r <- rawLedgerFromString "" -- don't know how to get it from ledgerFile
|
||||||
assertBool "ledgerFile parsing an empty file should give an empty ledger" $ null $ ledger_txns r
|
assertBool "ledgerFile parsing an empty file should give an empty ledger" $ null $ ledger_txns r
|
||||||
|
|||||||
3
Utils.hs
3
Utils.hs
@ -8,13 +8,10 @@ Utilities for top-level modules and ghci. See also "Ledger.IO" and
|
|||||||
module Utils
|
module Utils
|
||||||
where
|
where
|
||||||
import Control.Monad.Error
|
import Control.Monad.Error
|
||||||
import Data.Time.Clock
|
|
||||||
import Ledger
|
import Ledger
|
||||||
import Options (Opt,ledgerFilePathFromOpts,optsToIOArgs)
|
import Options (Opt,ledgerFilePathFromOpts,optsToIOArgs)
|
||||||
import System.Directory (doesFileExist)
|
import System.Directory (doesFileExist)
|
||||||
import System.IO
|
import System.IO
|
||||||
import Text.ParserCombinators.Parsec
|
|
||||||
import qualified Data.Map as Map (lookup)
|
|
||||||
|
|
||||||
|
|
||||||
-- | Parse the user's specified ledger file and run a hledger command on
|
-- | Parse the user's specified ledger file and run a hledger command on
|
||||||
|
|||||||
@ -42,6 +42,8 @@ binaryfilename = prettify $ splitAtElement '.' buildversion :: String
|
|||||||
prettify (major:minor:bugfix:[]) = prettify (major:minor:bugfix:"0":[])
|
prettify (major:minor:bugfix:[]) = prettify (major:minor:bugfix:"0":[])
|
||||||
prettify (major:minor:[]) = prettify (major:minor:"0":"0":[])
|
prettify (major:minor:[]) = prettify (major:minor:"0":"0":[])
|
||||||
prettify (major:[]) = prettify (major:"0":"0":"0":[])
|
prettify (major:[]) = prettify (major:"0":"0":"0":[])
|
||||||
|
prettify [] = error "VERSION is empty, please fix"
|
||||||
|
prettify _ = error "VERSION has too many components, please fix"
|
||||||
|
|
||||||
versionstr = prettify $ splitAtElement '.' buildversion :: String
|
versionstr = prettify $ splitAtElement '.' buildversion :: String
|
||||||
where
|
where
|
||||||
|
|||||||
@ -36,11 +36,8 @@ See "Ledger.Ledger" for more examples.
|
|||||||
-}
|
-}
|
||||||
|
|
||||||
module Main where
|
module Main where
|
||||||
import Control.Monad.Error
|
|
||||||
import Prelude hiding (putStr, putStrLn)
|
import Prelude hiding (putStr, putStrLn)
|
||||||
import System.IO (stderr)
|
|
||||||
import System.IO.UTF8
|
import System.IO.UTF8
|
||||||
import qualified Data.Map as Map (lookup)
|
|
||||||
|
|
||||||
import Commands.All
|
import Commands.All
|
||||||
import Ledger
|
import Ledger
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user