more convenient timelog querying when invoked as "hours"

This commit is contained in:
Simon Michael 2009-01-23 02:04:31 +00:00
parent f733a3de80
commit a26a56eafe
2 changed files with 72 additions and 20 deletions

View File

@ -3,7 +3,9 @@ where
import System
import System.Console.GetOpt
import System.Directory
import System.Environment
import Text.Printf
import Data.Char (toLower)
import Ledger.Parse
import Ledger.Utils
import Ledger.Types
@ -12,9 +14,13 @@ import Ledger.Dates
versionno = "0.3"
version = printf "hledger version %s \n" versionno :: String
defaultfile = "~/.ledger"
fileenvvar = "LEDGER"
usagehdr = "Usage: hledger [OPTS] COMMAND [ACCTPATTERNS] [-- DESCPATTERNS]\n" ++
ledgerdefault = "~/.ledger"
ledgerenvvar = "LEDGER"
timelogdefault = "~/.timelog"
timelogenvvar = "TIMELOG"
timeprogname = "hours"
usagehdr = "Usage: hledger [OPTION] COMMAND [ACCTPATTERNS] [-- DESCPATTERNS]\n" ++
"or: hours [OPTIONS] [PERIOD [COMMAND]]\n" ++
"\n" ++
"Options (before command, unless using --options-anywhere):"
usageftr = "\n" ++
@ -27,7 +33,7 @@ usageftr = "\n" ++
"Account and description patterns are regular expressions which filter by\n" ++
"account name and entry description. Prefix a pattern with - to negate it,\n" ++
"and separate account and description patterns with --.\n" ++
"(With --options-anywhere, use ^ and ^^.)\n" ++
"(With --options-anywhere, use ^ and ^^. \"hours\" implies --options-anywhere.)\n" ++
"\n" ++
"Also: hledger [-v] test [TESTPATTERNS] to run self-tests.\n" ++
"\n"
@ -61,7 +67,7 @@ options = [
]
where
filehelp = printf "ledger file; - means use standard input. Defaults\nto the %s environment variable or %s"
fileenvvar defaultfile
ledgerenvvar ledgerdefault
-- | An option value from a command-line flag.
data Opt =
@ -97,18 +103,33 @@ optValuesForConstructor f opts = concatMap get opts
optValuesForConstructors fs opts = concatMap get opts
where get o = if any (\f -> f v == o) fs then [v] else [] where v = value o
-- | Parse the command-line arguments into ledger options, ledger command
-- name, and ledger command arguments. Also any dates in the options are
-- converted to full YYYY/MM/DD format, while we are in the IO monad
-- and can get the current time.
-- | Parse the command-line arguments into options, command name, and
-- command arguments. Any dates in the options are converted to full
-- YYYY/MM/DD format, while we are in the IO monad and can get the current
-- time. Arguments are parsed differently if the program was invoked as
-- "hours".
parseArguments :: IO ([Opt], String, [String])
parseArguments = do
args <- getArgs
let order = if "--options-anywhere" `elem` args then Permute else RequireOrder
case (getOpt order options args) of
(opts,cmd:args,[]) -> do {opts' <- fixOptDates opts; return (opts',cmd,args)}
(opts,[],[]) -> do {opts' <- fixOptDates opts; return (opts',[],[])}
(opts,_,errs) -> ioError (userError (concat errs ++ usage))
istimequery <- usingTimeProgramName
let order = if "--options-anywhere" `elem` args || istimequery
then Permute
else RequireOrder
let (os,as,es) = getOpt order options args
os' <- fixOptDates os
case istimequery of
False ->
case (os,as,es) of
(opts,cmd:args,[]) -> return (os',cmd,args)
(opts,[],[]) -> return (os',"",[])
(opts,_,errs) -> ioError (userError (concat errs ++ usage))
True ->
case (os,as,es) of
(opts,p:cmd:args,[]) -> return (os' ++ [Period p],cmd,args)
(opts,p:args,[]) -> return ([Period p,SubTotal] ++ os',"balance",args)
(opts,[],[]) -> return ([Period "today",SubTotal] ++ os',"balance",[])
(opts,_,errs) -> ioError (userError (concat errs ++ usage))
-- | Convert any fuzzy dates within these option values to explicit ones,
-- based on today's date.
@ -170,10 +191,20 @@ displayFromOpts opts = listtomaybe $ optValuesForConstructor Display opts
listtomaybe [] = Nothing
listtomaybe vs = Just $ last vs
-- | Was the program invoked via the \"hours\" alias ?
usingTimeProgramName :: IO Bool
usingTimeProgramName = do
progname <- getProgName
return $ map toLower progname == timeprogname
-- | Get the ledger file path from options, an environment variable, or a default
ledgerFilePathFromOpts :: [Opt] -> IO String
ledgerFilePathFromOpts opts = do
envordefault <- getEnv fileenvvar `catch` \_ -> return defaultfile
istimequery <- usingTimeProgramName
let (e,d) = if istimequery
then (timelogenvvar,timelogdefault)
else (ledgerenvvar,ledgerdefault)
envordefault <- getEnv e `catch` \_ -> return d
paths <- mapM tildeExpand $ [envordefault] ++ optValuesForConstructor File opts
return $ last paths

31
README
View File

@ -37,9 +37,12 @@ To get the latest development code do::
darcs get http://joyful.com/repos/hledger
Examples
--------
Here are some commands to try::
Usage
-----
hledger looks for your ledger file at ~/.ledger by default. To use a
different file, specify it with the LEDGER environment variable or -f
option (which may be - for standard input). Here are some commands to
try::
hledger --help
hledger -f sample.ledger balance
@ -50,9 +53,27 @@ Here are some commands to try::
hledger reg -- shop
hledger ui
hledger looks for your ledger file at ~/.ledger by default. To use a different file,
specify it with -f or the LEDGER environment variable.
Time reporting
--------------
hledger can parse a timelog file in timeclock.el's format, treating time
categories as accounts. If hledger is invoked by the "hours" alias it
looks for your timelog, and parses arguments slightly differently for
convenient querying:
hours [OPTIONS] [PERIOD [COMMAND]]
PERIOD and COMMAND default to "today" and "balance --subtotal"
respectively, and --options-anywhere is assumed. The timelog is found in
the same way as your ledger: ~/.timelog or the file specified by $TIMELOG
or an -f option. Examples:
hours # today's balances
hours today # the same
hours 'this week' # so far this week
hours week # the same
hours lastmonth # last month, the space is optional
hours 'monthly in 2008' reg --depth 1 # monthly register, top-level only
Features
--------