imp: cli: config files can now provide the command name
If the first thing in a config file's general section is a non-flag argument, that will be used as the command name argument, taking precedence over any command line arguments.
This commit is contained in:
parent
a928ed994b
commit
46897cd30b
@ -96,7 +96,7 @@ import Data.Function ((&))
|
|||||||
import Data.Functor ((<&>))
|
import Data.Functor ((<&>))
|
||||||
import Data.List
|
import Data.List
|
||||||
import qualified Data.List.NonEmpty as NE
|
import qualified Data.List.NonEmpty as NE
|
||||||
import Data.Maybe (isJust)
|
import Data.Maybe (isJust, fromMaybe)
|
||||||
import Data.Text (pack, Text)
|
import Data.Text (pack, Text)
|
||||||
import Data.Time.Clock.POSIX (getPOSIXTime)
|
import Data.Time.Clock.POSIX (getPOSIXTime)
|
||||||
import Safe
|
import Safe
|
||||||
@ -191,6 +191,7 @@ main :: IO ()
|
|||||||
main = withGhcDebug' $ do
|
main = withGhcDebug' $ do
|
||||||
|
|
||||||
-- 0. let's go!
|
-- 0. let's go!
|
||||||
|
|
||||||
let
|
let
|
||||||
-- Trace helpers. These always trace to stderr, even when running `hledger ui`;
|
-- Trace helpers. These always trace to stderr, even when running `hledger ui`;
|
||||||
-- that's ok as conf is a hledger cli feature for now.
|
-- that's ok as conf is a hledger cli feature for now.
|
||||||
@ -198,24 +199,24 @@ main = withGhcDebug' $ do
|
|||||||
dbgIO = ptraceAtIO verboseDebugLevel
|
dbgIO = ptraceAtIO verboseDebugLevel
|
||||||
dbgIO1 = ptraceAtIO 1
|
dbgIO1 = ptraceAtIO 1
|
||||||
dbgIO2 = ptraceAtIO 2
|
dbgIO2 = ptraceAtIO 2
|
||||||
|
|
||||||
dbgIO "running" prognameandversion
|
dbgIO "running" prognameandversion
|
||||||
|
|
||||||
starttime <- getPOSIXTime
|
starttime <- getPOSIXTime
|
||||||
|
|
||||||
-- give ghc-debug a chance to take control
|
-- give ghc-debug a chance to take control
|
||||||
when (ghcDebugMode == GDPauseAtStart) $ ghcDebugPause'
|
when (ghcDebugMode == GDPauseAtStart) $ ghcDebugPause'
|
||||||
|
|
||||||
-- try to encourage user's $PAGER to display ANSI when supported
|
-- try to encourage user's $PAGER to display ANSI when supported
|
||||||
when useColorOnStdout setupPager
|
when useColorOnStdout setupPager
|
||||||
|
|
||||||
-- Search PATH for addon commands. Exclude any that match builtin command names.
|
-- Search PATH for addon commands. Exclude any that match builtin command names.
|
||||||
addons <- hledgerAddons <&> filter (not . (`elem` builtinCommandNames) . dropExtension)
|
addons <- hledgerAddons <&> filter (not . (`elem` builtinCommandNames) . dropExtension)
|
||||||
|
|
||||||
---------------------------------------------------------------
|
---------------------------------------------------------------
|
||||||
-- 1. Preliminary command line parsing.
|
|
||||||
|
|
||||||
dbgIO "\n1. Preliminary command line parsing" ()
|
dbgIO "\n1. Preliminary command line parsing" ()
|
||||||
|
|
||||||
|
-- Naming notes:
|
||||||
|
-- "arg" often has the most general meaning, including things like: -f, --flag, flagvalue, arg, >file, &, etc.
|
||||||
|
-- confcmdarg, clicmdarg = the first non-flag argument, from config file or cli = the subcommand name
|
||||||
|
-- cmdname = the full unabbreviated command name, or ""
|
||||||
|
-- confcmdargs = arguments for the subcommand, from config file
|
||||||
|
|
||||||
-- Do some argument preprocessing to help cmdargs
|
-- Do some argument preprocessing to help cmdargs
|
||||||
cliargs <- getArgs
|
cliargs <- getArgs
|
||||||
>>= expandArgsAt -- interpolate @ARGFILEs
|
>>= expandArgsAt -- interpolate @ARGFILEs
|
||||||
@ -226,144 +227,167 @@ main = withGhcDebug' $ do
|
|||||||
(cliargsbeforecmd, cliargsaftercmd) = second (drop 1) $ break (==clicmdarg) cliargs
|
(cliargsbeforecmd, cliargsaftercmd) = second (drop 1) $ break (==clicmdarg) cliargs
|
||||||
dbgIO "cli args" cliargs
|
dbgIO "cli args" cliargs
|
||||||
dbg1IO "cli args with command first, if any" cliargswithcmdfirst
|
dbg1IO "cli args with command first, if any" cliargswithcmdfirst
|
||||||
dbgIO "command argument found" clicmdarg
|
dbgIO "cli command argument found" clicmdarg
|
||||||
dbgIO "cli args before command" cliargsbeforecmd
|
dbgIO "cli args before command" cliargsbeforecmd
|
||||||
dbgIO "cli args after command" cliargsaftercmd
|
dbgIO "cli args after command" cliargsaftercmd
|
||||||
|
dbgIO "cli args without command" cliargswithoutcmd
|
||||||
|
|
||||||
-- Now try to identify the full subcommand name, so we can look for
|
---------------------------------------------------------------
|
||||||
-- command-specific options in config files (clicmdarg may be only an abbreviation).
|
dbgIO "\n2. Read the config file if any" ()
|
||||||
-- For this do a preliminary cmdargs parse of the arguments with cli-specific options removed.
|
|
||||||
-- If no command was provided, or if the command line contains a bad flag
|
-- Identify any --conf/--no-conf options.
|
||||||
-- or a wrongly present/missing flag argument, cmd will be "".
|
-- Run cmdargs on just the args that look conf-related.
|
||||||
let
|
let
|
||||||
rawopts1 = cmdargsParse
|
cliconfargs = dropUnsupportedOpts confflagsmode cliargswithoutcmd
|
||||||
"for command name"
|
cliconfrawopts = cmdargsParse "for conf options" confflagsmode cliconfargs
|
||||||
(mainmode addons)
|
|
||||||
cliargswithcmdfirstwithoutclispecific
|
-- Read extra general and command-specific args/opts from the config file, if any.
|
||||||
cmd = stringopt "command" rawopts1
|
(conf, mconffile) <-
|
||||||
-- XXX better error message when cmdargs fails (eg spaced/quoted/malformed flag values) ?
|
seq cliconfrawopts $ -- order debug output
|
||||||
nocmdprovided = null clicmdarg
|
getConf cliconfrawopts
|
||||||
badcmdprovided = null cmd && not nocmdprovided
|
|
||||||
isaddoncmd = not (null cmd) && cmd `elem` addons
|
---------------------------------------------------------------
|
||||||
-- isbuiltincmd = cmd `elem` builtinCommandNames
|
dbgIO "\n3. Identify a command name from config file or command line" ()
|
||||||
mcmdmodeaction = findBuiltinCommand cmd
|
|
||||||
effectivemode = maybe (mainmode []) fst mcmdmodeaction
|
-- Try to identify the subcommand name,
|
||||||
|
-- from the first non-flag general argument in the config file,
|
||||||
|
-- or if there is none, from the first non-flag argument on the command line.
|
||||||
|
|
||||||
|
let
|
||||||
|
confallgenargs = confLookup "general" conf
|
||||||
|
-- we don't try to move flags/values preceding a command argument here;
|
||||||
|
-- if a command name is written in the config file, it must be first
|
||||||
|
(confcmdarg, confothergenargs) = case confallgenargs of
|
||||||
|
a:as | not $ isFlagArg a -> (a,as)
|
||||||
|
as -> ("",as)
|
||||||
|
cmdarg = if not $ null confcmdarg then confcmdarg else clicmdarg
|
||||||
|
nocmdprovided = null cmdarg
|
||||||
|
|
||||||
|
-- The argument may be an abbreviated command name.
|
||||||
|
-- Run cmdargs on conf + cli args to get the full command name.
|
||||||
|
-- If no command argument was provided, or if cmdargs fails because
|
||||||
|
-- the command line contains a bad flag or wrongly present/missing flag value,
|
||||||
|
-- cmdname will be "".
|
||||||
|
args = confallgenargs <> cliargswithcmdfirstwithoutclispecific
|
||||||
|
cmdname = stringopt "command" $ cmdargsParse "for command name" (mainmode addons) args
|
||||||
|
badcmdprovided = null cmdname && not nocmdprovided
|
||||||
|
isaddoncmd = not (null cmdname) && cmdname `elem` addons
|
||||||
|
|
||||||
|
-- And get the builtin command's action, if any.
|
||||||
|
mbuiltincmdaction = findBuiltinCommand cmdname
|
||||||
|
effectivemode = maybe (mainmode []) fst mbuiltincmdaction
|
||||||
|
|
||||||
|
when (isJust mconffile) $ do
|
||||||
|
unless (null confcmdarg) $
|
||||||
|
dbgIO1 "using command name argument from config file" confcmdarg
|
||||||
dbgIO "cli args with command first and no cli-specific opts" cliargswithcmdfirstwithoutclispecific
|
dbgIO "cli args with command first and no cli-specific opts" cliargswithcmdfirstwithoutclispecific
|
||||||
dbgIO1 "command found" cmd
|
dbgIO1 "command found" cmdname
|
||||||
dbgIO "no command provided" nocmdprovided
|
dbgIO "no command provided" nocmdprovided
|
||||||
dbgIO "bad command provided" badcmdprovided
|
dbgIO "bad command provided" badcmdprovided
|
||||||
dbgIO "is addon command" isaddoncmd
|
dbgIO "is addon command" isaddoncmd
|
||||||
|
|
||||||
---------------------------------------------------------------
|
---------------------------------------------------------------
|
||||||
-- 2. Read extra options from a config file.
|
dbgIO "\n4. Get applicable options/arguments from config file" ()
|
||||||
|
|
||||||
dbgIO "\n2. Read options from a config file" ()
|
|
||||||
-- Identify any --conf/--no-conf options.
|
|
||||||
-- For this parse with cmdargs a second time, this time with just the args that look conf-related.
|
|
||||||
let cliconfargs = dropUnsupportedOpts confflagsmode cliargswithoutcmd
|
|
||||||
dbgIO "cli args without command" cliargswithoutcmd
|
|
||||||
-- dbgIO "cli conf args" cliconfargs
|
|
||||||
let rawopts2 = cmdargsParse "for conf options" confflagsmode cliconfargs
|
|
||||||
|
|
||||||
-- Read extra general and command-specific args/opts from the config file if found.
|
|
||||||
-- Ignore any general opts or cli-specific opts not known to be supported by the command.
|
-- Ignore any general opts or cli-specific opts not known to be supported by the command.
|
||||||
(conf, mconffile) <- getConf rawopts2
|
|
||||||
let
|
let
|
||||||
genargsfromconf = confLookup "general" conf
|
|
||||||
addoncmdssupportinggenopts = ["ui", "web"] -- addons known to support hledger general options
|
addoncmdssupportinggenopts = ["ui", "web"] -- addons known to support hledger general options
|
||||||
supportedgenargsfromconf
|
supportedgenargsfromconf
|
||||||
| cmd `elem` addoncmdssupportinggenopts =
|
| cmdname `elem` addoncmdssupportinggenopts =
|
||||||
[a | a <- genargsfromconf, not $ any (`isPrefixOf` a) addoncmdssupportinggenopts]
|
[a | a <- confothergenargs, not $ any (`isPrefixOf` a) addoncmdssupportinggenopts]
|
||||||
| isaddoncmd = []
|
| isaddoncmd = []
|
||||||
| otherwise = dropUnsupportedOpts effectivemode genargsfromconf
|
| otherwise = dropUnsupportedOpts effectivemode confothergenargs
|
||||||
excludedgenargsfromconf = genargsfromconf \\ supportedgenargsfromconf
|
excludedgenargsfromconf = confothergenargs \\ supportedgenargsfromconf
|
||||||
cmdargsfromconf
|
confcmdargs
|
||||||
| null cmd = []
|
| null cmdname = []
|
||||||
| otherwise = confLookup cmd conf & if isaddoncmd then ("--":) else id
|
| otherwise = confLookup cmdname conf & if isaddoncmd then ("--":) else id
|
||||||
|
|
||||||
when (isJust mconffile) $ do
|
when (isJust mconffile) $ do
|
||||||
dbgIO1 "using extra general args from config file" genargsfromconf
|
dbgIO1 "using general args from config file" confothergenargs
|
||||||
unless (null excludedgenargsfromconf) $
|
unless (null excludedgenargsfromconf) $
|
||||||
dbgIO1 "excluded general args from config file, not supported by this command" excludedgenargsfromconf
|
dbgIO1 "excluded general args from config file, not supported by this command" excludedgenargsfromconf
|
||||||
dbgIO1 "using extra command args from config file" cmdargsfromconf
|
dbgIO1 "using subcommand args from config file" confcmdargs
|
||||||
|
|
||||||
---------------------------------------------------------------
|
---------------------------------------------------------------
|
||||||
-- 3. Combine cli and config file args and parse with cmdargs a third time.
|
dbgIO "\n5. Combine config file and command line args" ()
|
||||||
-- A bad flag or flag argument will cause the program to exit with an error here.
|
|
||||||
|
|
||||||
dbgIO "\n3. Combine command line and config file args" ()
|
|
||||||
let
|
let
|
||||||
finalargs =
|
finalargs =
|
||||||
(if null clicmdarg then [] else [clicmdarg]) <> supportedgenargsfromconf <> cmdargsfromconf <> cliargswithoutcmd
|
[cmdarg | not $ null cmdarg] <> supportedgenargsfromconf <> confcmdargs <> cliargswithoutcmd
|
||||||
& replaceNumericFlags -- convert any -NUM opts from the config file
|
& replaceNumericFlags -- convert any -NUM opts from the config file
|
||||||
-- finalargs' <- expandArgsAt finalargs -- expand @ARGFILEs in the config file ? don't bother
|
-- finalargs' <- expandArgsAt finalargs -- expand @ARGFILEs in the config file ? don't bother
|
||||||
let rawopts3 = cmdargsParse "for all options" (mainmode addons) finalargs
|
dbgIO1 "final args" finalargs
|
||||||
|
|
||||||
|
-- Run cmdargs on command name + supported conf general args + conf subcommand args + cli args to get the final options.
|
||||||
|
-- A bad flag or flag argument will cause the program to exit with an error here.
|
||||||
|
let rawopts = cmdargsParse "final command line" (mainmode addons) finalargs
|
||||||
|
|
||||||
---------------------------------------------------------------
|
---------------------------------------------------------------
|
||||||
-- 4. Finally, select an action and run it.
|
seq rawopts $ -- order debug output
|
||||||
|
dbgIO "\n6. Select an action and run it" ()
|
||||||
|
|
||||||
dbgIO "\n4. Select an action" ()
|
|
||||||
-- We check for the help/doc/version flags first, since they are a high priority.
|
-- We check for the help/doc/version flags first, since they are a high priority.
|
||||||
-- (A perfectionist might think they should be so high priority that adding -h
|
-- (A perfectionist might think they should be so high priority that adding -h
|
||||||
-- to an invalid command line would show help. But cmdargs tends to fail first,
|
-- to an invalid command line would show help. But cmdargs tends to fail first,
|
||||||
-- preventing this, and trying to detect them without cmdargs, and always do the
|
-- preventing this, and trying to detect them without cmdargs, and always do the
|
||||||
-- right thing with builtin commands and addon commands, gets much too complicated.)
|
-- right thing with builtin commands and addon commands, gets much too complicated.)
|
||||||
let
|
let
|
||||||
helpFlag = boolopt "help" rawopts3
|
helpFlag = boolopt "help" rawopts
|
||||||
tldrFlag = boolopt "tldr" rawopts3
|
tldrFlag = boolopt "tldr" rawopts
|
||||||
infoFlag = boolopt "info" rawopts3
|
infoFlag = boolopt "info" rawopts
|
||||||
manFlag = boolopt "man" rawopts3
|
manFlag = boolopt "man" rawopts
|
||||||
versionFlag = boolopt "version" rawopts3
|
versionFlag = boolopt "version" rawopts
|
||||||
|
|
||||||
if
|
if
|
||||||
-- 4.1. no command and a help/doc flag found - show general help/docs
|
-- 6.1. no command and a help/doc flag found - show general help/docs
|
||||||
| nocmdprovided && helpFlag -> pager $ showModeUsage (mainmode []) ++ "\n"
|
| nocmdprovided && helpFlag -> pager $ showModeUsage (mainmode []) ++ "\n"
|
||||||
| nocmdprovided && tldrFlag -> runTldrForPage "hledger"
|
| nocmdprovided && tldrFlag -> runTldrForPage "hledger"
|
||||||
| nocmdprovided && infoFlag -> runInfoForTopic "hledger" Nothing
|
| nocmdprovided && infoFlag -> runInfoForTopic "hledger" Nothing
|
||||||
| nocmdprovided && manFlag -> runManForTopic "hledger" Nothing
|
| nocmdprovided && manFlag -> runManForTopic "hledger" Nothing
|
||||||
|
|
||||||
-- 4.2. --version flag found and none of these other conditions - show version
|
-- 6.2. --version flag found and none of these other conditions - show version
|
||||||
| versionFlag && not (isaddoncmd || helpFlag || tldrFlag || infoFlag || manFlag) -> putStrLn prognameandversion
|
| versionFlag && not (isaddoncmd || helpFlag || tldrFlag || infoFlag || manFlag) -> putStrLn prognameandversion
|
||||||
|
|
||||||
-- 4.3. there's a command argument, but it's bad - show error
|
-- 6.3. there's a command argument, but it's bad - show error
|
||||||
| badcmdprovided -> error' $ "command "++clicmdarg++" is not recognized, run with no command to see a list"
|
| badcmdprovided -> error' $ "command "++clicmdarg++" is not recognized, run with no command to see a list"
|
||||||
|
|
||||||
-- 4.4. no command found, nothing else to do - show the commands list
|
-- 6.4. no command found, nothing else to do - show the commands list
|
||||||
| nocmdprovided -> dbgIO "" "no command, showing commands list" >> printCommandsList prognameandversion addons
|
| nocmdprovided -> dbgIO1 "no command, showing commands list" () >> printCommandsList prognameandversion addons
|
||||||
|
|
||||||
-- 4.5. builtin command found
|
-- 6.5. builtin command found
|
||||||
| Just (cmdmode, cmdaction) <- mcmdmodeaction -> do
|
| Just (cmdmode, cmdaction) <- mbuiltincmdaction -> do
|
||||||
|
let mmodecmdname = headMay $ modeNames cmdmode
|
||||||
|
dbgIO1 "running builtin command mode" $ fromMaybe "" mmodecmdname
|
||||||
|
|
||||||
-- validate opts/args more and convert to CliOpts
|
-- validate opts/args more and convert to CliOpts
|
||||||
opts <- rawOptsToCliOpts rawopts3 >>= \opts0 -> return opts0{progstarttime_=starttime}
|
opts <- rawOptsToCliOpts rawopts >>= \opts0 -> return opts0{progstarttime_=starttime}
|
||||||
dbgIO2 "processed opts" opts
|
dbgIO2 "processed opts" opts
|
||||||
dbgIO "period from opts" (period_ . _rsReportOpts $ reportspec_ opts)
|
dbgIO "period from opts" (period_ . _rsReportOpts $ reportspec_ opts)
|
||||||
dbgIO "interval from opts" (interval_ . _rsReportOpts $ reportspec_ opts)
|
dbgIO "interval from opts" (interval_ . _rsReportOpts $ reportspec_ opts)
|
||||||
dbgIO "query from opts & args" (_rsQuery $ reportspec_ opts)
|
dbgIO "query from opts & args" (_rsQuery $ reportspec_ opts)
|
||||||
let
|
let tldrpagename = maybe "hledger" (("hledger-"<>)) mmodecmdname
|
||||||
mcmdname = headMay $ modeNames cmdmode
|
|
||||||
tldrpagename = maybe "hledger" (("hledger-"<>)) mcmdname
|
|
||||||
|
|
||||||
-- run the builtin command according to its type
|
-- run the builtin command according to its type
|
||||||
if
|
if
|
||||||
-- help/doc flag - show command help/docs
|
-- 6.5.1. help/doc flag - show command help/docs
|
||||||
| helpFlag -> pager $ showModeUsage cmdmode ++ "\n"
|
| helpFlag -> pager $ showModeUsage cmdmode ++ "\n"
|
||||||
| tldrFlag -> runTldrForPage tldrpagename
|
| tldrFlag -> runTldrForPage tldrpagename
|
||||||
| infoFlag -> runInfoForTopic "hledger" mcmdname
|
| infoFlag -> runInfoForTopic "hledger" mmodecmdname
|
||||||
| manFlag -> runManForTopic "hledger" mcmdname
|
| manFlag -> runManForTopic "hledger" mmodecmdname
|
||||||
|
|
||||||
-- builtin command which should not require or read the journal - run it
|
-- 6.5.2. builtin command which should not require or read the journal - run it
|
||||||
| cmd `elem` ["demo","help","test"] ->
|
| cmdname `elem` ["demo","help","test"] ->
|
||||||
cmdaction opts $ error' $ cmd++" tried to read the journal but is not supposed to"
|
cmdaction opts $ error' $ cmdname++" tried to read the journal but is not supposed to"
|
||||||
|
|
||||||
-- builtin command which should create the journal if missing - do that and run it
|
-- 6.5.3. builtin command which should create the journal if missing - do that and run it
|
||||||
| cmd `elem` ["add","import"] -> do
|
| cmdname `elem` ["add","import"] -> do
|
||||||
ensureJournalFileExists . NE.head =<< journalFilePathFromOpts opts
|
ensureJournalFileExists . NE.head =<< journalFilePathFromOpts opts
|
||||||
withJournalDo opts (cmdaction opts)
|
withJournalDo opts (cmdaction opts)
|
||||||
|
|
||||||
-- all other builtin commands - read the journal and if successful run the command with it
|
-- 6.5.4. all other builtin commands - read the journal and if successful run the command with it
|
||||||
| otherwise -> withJournalDo opts $ cmdaction opts
|
| otherwise -> withJournalDo opts $ cmdaction opts
|
||||||
|
|
||||||
-- 4.6. external addon command found - run it,
|
-- 6.6. external addon command found - run it,
|
||||||
-- passing any cli arguments written after the command name
|
-- passing any cli arguments written after the command name
|
||||||
-- and any command-specific opts from the config file.
|
-- and any command-specific opts from the config file.
|
||||||
-- Any "--" arguments, which sometimes must be used in the command line
|
-- Any "--" arguments, which sometimes must be used in the command line
|
||||||
@ -375,24 +399,24 @@ main = withGhcDebug' $ do
|
|||||||
-- are not passed since we can't be sure they're supported.
|
-- are not passed since we can't be sure they're supported.
|
||||||
| isaddoncmd -> do
|
| isaddoncmd -> do
|
||||||
let
|
let
|
||||||
addonargs0 = filter (/="--") $ supportedgenargsfromconf <> cmdargsfromconf <> cliargswithoutcmd
|
addonargs0 = filter (/="--") $ supportedgenargsfromconf <> confcmdargs <> cliargswithoutcmd
|
||||||
addonargs = dropCliSpecificOpts addonargs0
|
addonargs = dropCliSpecificOpts addonargs0
|
||||||
shellcmd = printf "%s-%s %s" progname cmd (unwords' addonargs) :: String
|
shellcmd = printf "%s-%s %s" progname cmdname (unwords' addonargs) :: String
|
||||||
dbgIO "addon command selected" cmd
|
dbgIO "addon command selected" cmdname
|
||||||
dbgIO "addon command arguments after removing cli-specific opts" (map quoteIfNeeded addonargs)
|
dbgIO "addon command arguments after removing cli-specific opts" (map quoteIfNeeded addonargs)
|
||||||
dbgIO1 "running addon" shellcmd
|
dbgIO1 "running addon" shellcmd
|
||||||
system shellcmd >>= exitWith
|
system shellcmd >>= exitWith
|
||||||
|
|
||||||
-- deprecated command found
|
-- deprecated command found
|
||||||
-- cmd == "convert" = error' (modeHelp oldconvertmode) >> exitFailure
|
-- cmdname == "convert" = error' (modeHelp oldconvertmode) >> exitFailure
|
||||||
|
|
||||||
-- 4.7. something else (shouldn't happen) - show an error
|
-- 6.7. something else (shouldn't happen) - show an error
|
||||||
| otherwise -> usageError $
|
| otherwise -> usageError $
|
||||||
"could not understand the arguments "++show finalargs
|
"could not understand the arguments "++show finalargs
|
||||||
<> if null genargsfromconf then "" else "\ngeneral arguments added from config file: "++show genargsfromconf
|
<> if null confothergenargs then "" else "\ngeneral arguments added from config file: "++show confothergenargs
|
||||||
<> if null cmdargsfromconf then "" else "\ncommand arguments added from config file: "++show cmdargsfromconf
|
<> if null confcmdargs then "" else "\ncommand arguments added from config file: "++show confcmdargs
|
||||||
|
|
||||||
-- 5. And we're done.
|
-- 7. And we're done.
|
||||||
-- Give ghc-debug a final chance to take control.
|
-- Give ghc-debug a final chance to take control.
|
||||||
when (ghcDebugMode == GDPauseAtEnd) $ ghcDebugPause'
|
when (ghcDebugMode == GDPauseAtEnd) $ ghcDebugPause'
|
||||||
|
|
||||||
@ -409,8 +433,8 @@ argsToCliOpts args addons = do
|
|||||||
let
|
let
|
||||||
(_, _, args0) = moveFlagsAfterCommand args
|
(_, _, args0) = moveFlagsAfterCommand args
|
||||||
args1 = replaceNumericFlags args0
|
args1 = replaceNumericFlags args0
|
||||||
rawopts3 = cmdargsParse "for options" (mainmode addons) args1
|
rawopts = cmdargsParse "for options" (mainmode addons) args1
|
||||||
rawOptsToCliOpts rawopts3
|
rawOptsToCliOpts rawopts
|
||||||
|
|
||||||
-- | Parse the given command line arguments/options with the given cmdargs mode,
|
-- | Parse the given command line arguments/options with the given cmdargs mode,
|
||||||
-- after adding values to any valueless --debug flags,
|
-- after adding values to any valueless --debug flags,
|
||||||
@ -422,6 +446,7 @@ cmdargsParse desc m args0 = process m (ensureDebugFlagHasVal args0)
|
|||||||
& either
|
& either
|
||||||
(\e -> error' $ e <> " while parsing these args " <> desc <> ": " <> unwords (map quoteIfNeeded args0))
|
(\e -> error' $ e <> " while parsing these args " <> desc <> ": " <> unwords (map quoteIfNeeded args0))
|
||||||
(traceOrLogAt verboseDebugLevel ("cmdargs: parsing " <> desc <> ": " <> show args0))
|
(traceOrLogAt verboseDebugLevel ("cmdargs: parsing " <> desc <> ": " <> show args0))
|
||||||
|
-- XXX better error message when cmdargs fails (eg spaced/quoted/malformed flag values) ?
|
||||||
|
|
||||||
-- | cmdargs does not allow flags (options) to appear before the subcommand argument.
|
-- | cmdargs does not allow flags (options) to appear before the subcommand argument.
|
||||||
-- We prefer to hide this restriction from the user, making the CLI more forgiving.
|
-- We prefer to hide this restriction from the user, making the CLI more forgiving.
|
||||||
|
|||||||
@ -512,17 +512,16 @@ You can save a set of command line options and arguments in a file,
|
|||||||
and then reuse them by writing `@FILENAME` as a command line argument.
|
and then reuse them by writing `@FILENAME` as a command line argument.
|
||||||
Eg: `hledger bal @foo.args`.
|
Eg: `hledger bal @foo.args`.
|
||||||
|
|
||||||
(Inside the argument file, each line should contain just one option or argument.
|
An argument file's format is more restrictive than the command line.
|
||||||
|
Each line should contain just one option or argument.
|
||||||
Don't use spaces except inside quotes; write `=` or nothing between a flag and its argument.
|
Don't use spaces except inside quotes; write `=` or nothing between a flag and its argument.
|
||||||
For the special characters mentioned above, use one less level of quoting than
|
If you use quotes, they must enclose the whole line.
|
||||||
you would at the command prompt.)
|
For the special characters mentioned above, use one less level of quoting than you would at the command line.
|
||||||
|
|
||||||
Argument files are now superseded by..
|
|
||||||
|
|
||||||
## Config files
|
## Config files
|
||||||
|
|
||||||
As of hledger 1.40, you can optionally save command line options (or arguments)
|
With hledger 1.40+, you can save extra command line options and arguments
|
||||||
to be used when running hledger commands, in a config file. Here's a small example:
|
in a more featureful hledger config file. Here's a small example:
|
||||||
|
|
||||||
```conf
|
```conf
|
||||||
# General options are listed first, one or more per line.
|
# General options are listed first, one or more per line.
|
||||||
@ -570,14 +569,7 @@ Eg (some operating systems need the `-S`, some don't):
|
|||||||
You can put not only options, but also arguments in a config file.
|
You can put not only options, but also arguments in a config file.
|
||||||
This is probably more useful in special-purpose config files, not an automatic one.
|
This is probably more useful in special-purpose config files, not an automatic one.
|
||||||
|
|
||||||
There's an exception to this: a config file can't provide the command argument, currently
|
The config file feature was added in hledger 1.40 and is considered *experimental*.
|
||||||
([#2231](https://github.com/simonmichael/hledger/issues/2231)).
|
|
||||||
If you need that, you can do it in the shebang line instead. Eg:
|
|
||||||
```
|
|
||||||
#!/usr/bin/env -S hledger balance --conf
|
|
||||||
```
|
|
||||||
|
|
||||||
The config file feature has been added in hledger 1.40 and is considered *experimental*.
|
|
||||||
|
|
||||||
## Shell completions
|
## Shell completions
|
||||||
|
|
||||||
@ -741,7 +733,7 @@ or use `--real` to exclude transactions that use them.
|
|||||||
#### Beancount costs
|
#### Beancount costs
|
||||||
|
|
||||||
Beancount doesn't allow [redundant cost notation](https://hledger.org/hledger.html#combining-costs-and-equity-conversion-postings)
|
Beancount doesn't allow [redundant cost notation](https://hledger.org/hledger.html#combining-costs-and-equity-conversion-postings)
|
||||||
as hledger does. If you have entries like this, you may need to comment out either the costs or the equity postings.
|
as hledger does. If you have entries like this, you will need to comment out either the costs or the equity postings.
|
||||||
|
|
||||||
#### Beancount operating currency
|
#### Beancount operating currency
|
||||||
|
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user