add: more code cleanup

This commit is contained in:
Simon Michael 2013-02-24 20:05:31 +00:00
parent 33153851e9
commit 7025c6f66a

View File

@ -34,15 +34,6 @@ import Hledger.Cli.Options
import Hledger.Cli.Register (postingsReportAsText) import Hledger.Cli.Register (postingsReportAsText)
{- | Information used as the basis for suggested account names, amounts,
etc in add prompt
-}
data PostingState = PostingState {
psJournal :: Journal,
psAccept :: AccountName -> Bool,
psSuggestHistoricalAmount :: Bool,
psHistory :: Maybe [Posting]}
-- | Read multiple transactions from the console, prompting for each -- | Read multiple transactions from the console, prompting for each
-- field, and append them to the journal file. If the journal came -- field, and append them to the journal file. If the journal came
-- from stdin, this command has no effect. -- from stdin, this command has no effect.
@ -61,7 +52,7 @@ add opts j
today <- showDate `fmap` getCurrentDay today <- showDate `fmap` getCurrentDay
let args = words' $ query_ $ reportopts_ opts let args = words' $ query_ $ reportopts_ opts
(defdate, moredefs) = headTailDef today args (defdate, moredefs) = headTailDef today args
getAndAddTransactions j opts defdate moredefs getAndAddTransactionsLoop j opts defdate moredefs
`C.catch` (\e -> unless (isEOFError e) $ ioError e) `C.catch` (\e -> unless (isEOFError e) $ ioError e)
where f = journalFilePath j where f = journalFilePath j
@ -70,14 +61,14 @@ add opts j
-- until end of input or ctrl-c (then raise an EOF exception). -- until end of input or ctrl-c (then raise an EOF exception).
-- If provided, command-line arguments are used as defaults for the -- If provided, command-line arguments are used as defaults for the
-- first transaction; otherwise defaults come from the most similar -- first transaction; otherwise defaults come from the most similar
-- recent transaction. -- recent transaction in the journal.
getAndAddTransactions :: Journal -> CliOpts -> String -> [String] -> IO () getAndAddTransactionsLoop :: Journal -> CliOpts -> String -> [String] -> IO ()
getAndAddTransactions j opts defdate moredefs = do getAndAddTransactionsLoop j opts defdate moredefs = do
t <- getTransaction j opts defdate moredefs t <- getTransaction j opts defdate moredefs
j <- journalAddTransaction j opts t j <- journalAddTransaction j opts t
hPrintf stderr "\nRecorded transaction:\n%s" (show t) hPrintf stderr "\nRecorded transaction:\n%s" (show t)
let defdate' = showDate $ tdate t let defdate' = showDate $ tdate t
getAndAddTransactions j opts defdate' [] getAndAddTransactionsLoop j opts defdate' []
-- | Read a single transaction from the console, with history-aware prompting. -- | Read a single transaction from the console, with history-aware prompting.
-- A default date, and zero or more defaults for subsequent fields, are provided. -- A default date, and zero or more defaults for subsequent fields, are provided.
@ -96,15 +87,27 @@ getTransaction j opts defdate moredefs = do
if description == "<" if description == "<"
then restart then restart
else do else do
mt <- getPostingsAndValidateTransaction j opts datestr description moredefs' mt <- getPostingsForTransactionWithHistory j opts datestr description moredefs'
case mt of case mt of
Nothing -> restart Nothing -> restart
Just t -> return t Just t -> return t
-- | Loop reading postings from the console, until two or more valid balanced data RestartEntryException = RestartEntryException deriving (Typeable,Show)
-- postings have been entered, then return the final transaction. instance Exception RestartEntryException
getPostingsAndValidateTransaction :: Journal -> CliOpts -> String -> String -> [String] -> IO (Maybe Transaction)
getPostingsAndValidateTransaction j opts datestr description defargs = do -- | Information used as the basis for suggested account names, amounts etc. in add prompt.
data PostingsState = PostingsState {
psJournal :: Journal
,psAccept :: AccountName -> Bool
,psSuggestHistoricalAmount :: Bool
,psHistory :: Maybe [Posting]
}
-- | Loop reading postings from the console, until a valid balanced
-- set of postings has been entered, then return the final transaction,
-- or nothing indicating that the user wants to restart entering this transaction.
getPostingsForTransactionWithHistory :: Journal -> CliOpts -> String -> String -> [String] -> IO (Maybe Transaction)
getPostingsForTransactionWithHistory j opts datestr description defargs = do
today <- getCurrentDay today <- getCurrentDay
let historymatches = transactionsSimilarTo j (queryFromOpts today $ reportopts_ opts) description let historymatches = transactionsSimilarTo j (queryFromOpts today $ reportopts_ opts) description
bestmatch | not (null defargs) || null historymatches = Nothing bestmatch | not (null defargs) || null historymatches = Nothing
@ -116,28 +119,24 @@ getPostingsAndValidateTransaction j opts datestr description defargs = do
then x `elem` existingaccts then x `elem` existingaccts
else True else True
existingaccts = journalAccountNames j existingaccts = journalAccountNames j
getpostingsandvalidate = do getvalidpostings = do
ps <- getPostingsWithState (PostingState j accept True bestmatchpostings) [] defargs ps <- getPostingsLoop (PostingsState j accept True bestmatchpostings) [] defargs
let t = nulltransaction{tdate=date let t = nulltransaction{tdate=date
,tstatus=False ,tstatus=False
,tdescription=description ,tdescription=description
,tpostings=ps ,tpostings=ps
} }
retry msg = do
let msg' = capitalize msg
liftIO $ hPutStrLn stderr $ "\n" ++ msg' ++ "please re-enter."
getpostingsandvalidate
either retry (return . Just) $ balanceTransaction Nothing t -- imprecise balancing either retry (return . Just) $ balanceTransaction Nothing t -- imprecise balancing
where
retry msg = liftIO (hPutStrLn stderr $ "\n" ++ (capitalize msg) ++ "please re-enter.") >> getvalidpostings
when (isJust bestmatch) $ liftIO $ hPrintf stderr "\nUsing this similar transaction for defaults:\n%s" (show $ fromJust bestmatch) when (isJust bestmatch) $ liftIO $ hPrintf stderr "\nUsing this similar transaction for defaults:\n%s" (show $ fromJust bestmatch)
getpostingsandvalidate `catch` \(_::RestartEntryException) -> return Nothing getvalidpostings `catch` \(_::RestartEntryException) -> return Nothing
data RestartEntryException = RestartEntryException deriving (Typeable,Show) -- | Read postings from the command line until . is entered, generating
instance Exception RestartEntryException -- useful defaults based on historical context and postings entered so far.
getPostingsLoop :: PostingsState -> [Posting] -> [String] -> IO [Posting]
-- | Read postings from the command line until . is entered, using any getPostingsLoop st enteredps defargs = do
-- provided historical postings and the journal context to guess defaults.
getPostingsWithState :: PostingState -> [Posting] -> [String] -> IO [Posting]
getPostingsWithState st enteredps defargs = do
let bestmatch | isNothing historicalps = Nothing let bestmatch | isNothing historicalps = Nothing
| n <= length ps = Just $ ps !! (n-1) | n <= length ps = Just $ ps !! (n-1)
| otherwise = Nothing | otherwise = Nothing
@ -153,7 +152,7 @@ getPostingsWithState st enteredps defargs = do
then then
if null enteredps if null enteredps
then do hPutStrLn stderr $ "\nPlease enter some postings first." then do hPutStrLn stderr $ "\nPlease enter some postings first."
getPostingsWithState st enteredps defargs getPostingsLoop st enteredps defargs
else return enteredps else return enteredps
else do else do
let defacctused = Just account == defacct let defacctused = Just account == defacct
@ -195,7 +194,7 @@ getPostingsWithState st enteredps defargs = do
else st{psHistory=historicalps', psSuggestHistoricalAmount=False} else st{psHistory=historicalps', psSuggestHistoricalAmount=False}
when (isJust defcommodityadded) $ when (isJust defcommodityadded) $
liftIO $ hPutStrLn stderr $ printf "using default commodity (%s)" (fromJust defcommodityadded) liftIO $ hPutStrLn stderr $ printf "using default commodity (%s)" (fromJust defcommodityadded)
getPostingsWithState st' (enteredps ++ [p]) defargs'' getPostingsLoop st' (enteredps ++ [p]) defargs''
where where
j = psJournal st j = psJournal st
historicalps = psHistory st historicalps = psHistory st
@ -215,7 +214,7 @@ getPostingsWithState st enteredps defargs = do
-- | Prompt for and read a string value, optionally with a default value -- | Prompt for and read a string value, optionally with a default value
-- and a validator. A validator causes the prompt to repeat until the -- and a validator. A validator causes the prompt to repeat until the
-- input is valid. May also raise an EOF exception if control-d is pressed. -- input is valid. May also raise an EOF exception if control-d or control-c is pressed.
askFor :: String -> Maybe String -> Maybe (String -> Bool) -> InputT IO String askFor :: String -> Maybe String -> Maybe (String -> Bool) -> InputT IO String
askFor prompt def validator = do askFor prompt def validator = do
l <- fmap (maybe eofErr id) l <- fmap (maybe eofErr id)