add: use command line arguments as defaults for first txn

With one or more command line arguments, they will used as defaults
for the first transaction, and history will be ignored. Subsequent
transactions will use history for defaults (and now only the best match
from history is shown).
This commit is contained in:
Simon Michael 2013-02-24 02:07:58 +00:00
parent c8e2751aa5
commit bf91efda7c

View File

@ -21,7 +21,7 @@ import Data.Time.Calendar
import Data.Typeable (Typeable) import Data.Typeable (Typeable)
import System.Console.Haskeline (InputT, runInputT, defaultSettings, setComplete, getInputLine) import System.Console.Haskeline (InputT, runInputT, defaultSettings, setComplete, getInputLine)
import System.Console.Haskeline.Completion import System.Console.Haskeline.Completion
import System.IO ( stderr, hPutStrLn, hPutStr ) import System.IO ( stderr, hPutStrLn )
import System.IO.Error import System.IO.Error
import Text.ParserCombinators.Parsec import Text.ParserCombinators.Parsec
import Text.Printf import Text.Printf
@ -98,7 +98,7 @@ getPostingsAndValidateTransaction :: Journal -> CliOpts -> String -> String -> I
getPostingsAndValidateTransaction j opts datestr description = do getPostingsAndValidateTransaction j opts datestr description = do
today <- getCurrentDay today <- getCurrentDay
let historymatches = transactionsSimilarTo j (queryFromOpts today $ reportopts_ opts) description let historymatches = transactionsSimilarTo j (queryFromOpts today $ reportopts_ opts) description
bestmatch | null historymatches = Nothing bestmatch | not (null defargs) || null historymatches = Nothing
| otherwise = Just $ snd $ head historymatches | otherwise = Just $ snd $ head historymatches
bestmatchpostings = maybe Nothing (Just . tpostings) bestmatch bestmatchpostings = maybe Nothing (Just . tpostings) bestmatch
date = fixSmartDate today $ fromparse $ (parse smartdate "" . lowercase) datestr date = fixSmartDate today $ fromparse $ (parse smartdate "" . lowercase) datestr
@ -130,34 +130,38 @@ instance Exception RestartEntryException
-- fragile -- fragile
-- | Read postings from the command line until . is entered, using any -- | Read postings from the command line until . is entered, using any
-- provided historical postings and the journal context to guess defaults. -- provided historical postings and the journal context to guess defaults.
getPostingsWithState :: PostingState -> [Posting] -> IO [Posting] getPostingsWithState :: PostingState -> [Posting] -> [String] -> IO [Posting]
getPostingsWithState st enteredps = do 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
where Just ps = historicalps where Just ps = historicalps
defaultaccount = maybe Nothing (Just . showacctname) bestmatch bestmatchacct = maybe Nothing (Just . showacctname) bestmatch
defacct = maybe bestmatchacct Just $ headMay defargs
defargs' = tailDef [] defargs
ordot | null enteredps || length enteredrealps == 1 = "" :: String ordot | null enteredps || length enteredrealps == 1 = "" :: String
| otherwise = " (or . to record)" | otherwise = " (or . to record)"
account <- runInteraction j $ askFor (printf "account %d%s" n ordot) defaultaccount (Just accept) account <- runInteraction j $ askFor (printf "account %d%s" n ordot) defacct (Just accept)
when (account=="<") $ throwIO RestartEntryException when (account=="<") $ throwIO RestartEntryException
if account=="." if account=="."
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 getPostingsWithState st enteredps defargs
else return enteredps else return enteredps
else do else do
let defaultacctused = Just account == defaultaccount let defacctused = Just account == defacct
historicalps' = if defaultacctused then historicalps else Nothing historicalps' = if defacctused then historicalps else Nothing
bestmatch' | isNothing historicalps' = Nothing bestmatch' | isNothing historicalps' = Nothing
| n <= length ps = Just $ ps !! (n-1) | n <= length ps = Just $ ps !! (n-1)
| otherwise = Nothing | otherwise = Nothing
where Just ps = historicalps' where Just ps = historicalps'
defaultamountstr | isJust bestmatch' && suggesthistorical = Just historicalamountstr defamountstr | isJust commandlineamt = commandlineamt
| n > 1 = Just balancingamountstr | isJust bestmatch' && suggesthistorical = Just historicalamountstr
| otherwise = Nothing | n > 1 = Just balancingamountstr
| otherwise = Nothing
where where
commandlineamt = headMay defargs'
historicalamountstr = showMixedAmountWithPrecision p $ pamount $ fromJust bestmatch' historicalamountstr = showMixedAmountWithPrecision p $ pamount $ fromJust bestmatch'
balancingamountstr = showMixedAmountWithPrecision p $ negate $ sum $ map pamount enteredrealps balancingamountstr = showMixedAmountWithPrecision p $ negate $ sum $ map pamount enteredrealps
-- what should this be ? -- what should this be ?
@ -168,23 +172,24 @@ getPostingsWithState st enteredps = do
-- 5 3 or 4, whichever would show the most decimal places ? -- 5 3 or 4, whichever would show the most decimal places ?
-- I think 1 or 4, whichever would show the most decimal places -- I think 1 or 4, whichever would show the most decimal places
p = maxprecisionwithpoint p = maxprecisionwithpoint
amountstr <- runInteractionDefault $ askFor (printf "amount %d" n) defaultamountstr validateamount defargs'' = tailDef [] defargs'
amountstr <- runInteractionDefault $ askFor (printf "amount %d" n) defamountstr validateamount
when (amountstr=="<") $ throwIO RestartEntryException when (amountstr=="<") $ throwIO RestartEntryException
let a = fromparse $ runParser (amountp <|> return missingamt) ctx "" amountstr let a = fromparse $ runParser (amountp <|> return missingamt) ctx "" amountstr
a' = fromparse $ runParser (amountp <|> return missingamt) nullctx "" amountstr a' = fromparse $ runParser (amountp <|> return missingamt) nullctx "" amountstr
wasdefaultamtused = Just (showAmount a) == defaultamountstr wasdefamtused = Just (showAmount a) == defamountstr
defaultcommodityadded | acommodity a == acommodity a' = Nothing defcommodityadded | acommodity a == acommodity a' = Nothing
| otherwise = Just $ acommodity a | otherwise = Just $ acommodity a
p = nullposting{paccount=stripbrackets account p = nullposting{paccount=stripbrackets account
,pamount=mixed a ,pamount=mixed a
,ptype=postingtype account ,ptype=postingtype account
} }
st' = if wasdefaultamtused st' = if wasdefamtused
then st then st
else st{psHistory=historicalps', psSuggestHistoricalAmount=False} else st{psHistory=historicalps', psSuggestHistoricalAmount=False}
when (isJust defaultcommodityadded) $ when (isJust defcommodityadded) $
liftIO $ hPutStrLn stderr $ printf "using default commodity (%s)" (fromJust defaultcommodityadded) liftIO $ hPutStrLn stderr $ printf "using default commodity (%s)" (fromJust defcommodityadded)
getPostingsWithState st' (enteredps ++ [p]) getPostingsWithState st' (enteredps ++ [p]) defargs''
where where
j = psJournal st j = psJournal st
historicalps = psHistory st historicalps = psHistory st