imp:cli: --no-pager -> --pager, make this and --color safe options
This commit is contained in:
parent
7fee69d7ab
commit
711d921774
@ -9,6 +9,7 @@ more easily by hledger commands/scripts in this and other packages.
|
|||||||
|
|
||||||
module Hledger.Data.RawOptions (
|
module Hledger.Data.RawOptions (
|
||||||
RawOpts,
|
RawOpts,
|
||||||
|
YNA,
|
||||||
mkRawOpts,
|
mkRawOpts,
|
||||||
overRawOpts,
|
overRawOpts,
|
||||||
setopt,
|
setopt,
|
||||||
@ -26,7 +27,9 @@ module Hledger.Data.RawOptions (
|
|||||||
posintopt,
|
posintopt,
|
||||||
maybeintopt,
|
maybeintopt,
|
||||||
maybeposintopt,
|
maybeposintopt,
|
||||||
maybecharopt
|
maybecharopt,
|
||||||
|
maybeynopt,
|
||||||
|
maybeynaopt,
|
||||||
)
|
)
|
||||||
where
|
where
|
||||||
|
|
||||||
@ -35,6 +38,8 @@ import Data.Default (Default(..))
|
|||||||
import Safe (headMay, lastMay, readDef)
|
import Safe (headMay, lastMay, readDef)
|
||||||
|
|
||||||
import Hledger.Utils
|
import Hledger.Utils
|
||||||
|
import Data.Char (toLower)
|
||||||
|
import Data.List (intercalate)
|
||||||
|
|
||||||
|
|
||||||
-- | The result of running cmdargs: an association list of option names to string values.
|
-- | The result of running cmdargs: an association list of option names to string values.
|
||||||
@ -139,3 +144,22 @@ maybeclippedintopt minVal maxVal name =
|
|||||||
++ " must lie in the range "
|
++ " must lie in the range "
|
||||||
++ show minVal ++ " to " ++ show maxVal
|
++ show minVal ++ " to " ++ show maxVal
|
||||||
++ ", but is " ++ show n
|
++ ", but is " ++ show n
|
||||||
|
|
||||||
|
maybeynopt :: String -> RawOpts -> Maybe Bool
|
||||||
|
maybeynopt name rawopts =
|
||||||
|
case maybestringopt name rawopts of
|
||||||
|
Just v | map toLower v `elem` ["y","yes","always"] -> Just True
|
||||||
|
Just v | map toLower v `elem` ["n","no","never"] -> Just False
|
||||||
|
Just _ -> error' $ name <> " value should be one of " <> (intercalate ", " ["y","yes","n","no"])
|
||||||
|
_ -> Nothing
|
||||||
|
|
||||||
|
data YNA = Yes | No | Auto deriving (Eq,Show)
|
||||||
|
|
||||||
|
maybeynaopt :: String -> RawOpts -> Maybe YNA
|
||||||
|
maybeynaopt name rawopts =
|
||||||
|
case maybestringopt name rawopts of
|
||||||
|
Just v | map toLower v `elem` ["y","yes","always"] -> Just Yes
|
||||||
|
Just v | map toLower v `elem` ["n","no","never"] -> Just No
|
||||||
|
Just v | map toLower v `elem` ["a","auto"] -> Just Auto
|
||||||
|
Just _ -> error' $ name <> " value should be one of " <> (intercalate ", " ["y","yes","n","no","a","auto"])
|
||||||
|
_ -> Nothing
|
||||||
|
|||||||
@ -346,7 +346,7 @@ ynopt opt rawopts = case maybestringopt opt rawopts of
|
|||||||
Just "never" -> Just False
|
Just "never" -> Just False
|
||||||
Just "no" -> Just False
|
Just "no" -> Just False
|
||||||
Just "n" -> Just False
|
Just "n" -> Just False
|
||||||
Just _ -> usageError "--pretty's argument should be \"yes\" or \"no\" (or y, n, always, never)"
|
Just _ -> usageError "this argument should be one of y, yes, n, no"
|
||||||
_ -> Nothing
|
_ -> Nothing
|
||||||
|
|
||||||
balanceAccumulationOverride :: RawOpts -> Maybe BalanceAccumulation
|
balanceAccumulationOverride :: RawOpts -> Maybe BalanceAccumulation
|
||||||
|
|||||||
@ -20,8 +20,8 @@ module Hledger.Utils.IO (
|
|||||||
pprint',
|
pprint',
|
||||||
|
|
||||||
-- * Viewing with pager
|
-- * Viewing with pager
|
||||||
pager,
|
|
||||||
setupPager,
|
setupPager,
|
||||||
|
runPager,
|
||||||
|
|
||||||
-- * Terminal size
|
-- * Terminal size
|
||||||
getTerminalHeightWidth,
|
getTerminalHeightWidth,
|
||||||
@ -32,6 +32,9 @@ module Hledger.Utils.IO (
|
|||||||
progArgs,
|
progArgs,
|
||||||
outputFileOption,
|
outputFileOption,
|
||||||
hasOutputFile,
|
hasOutputFile,
|
||||||
|
splitFlagsAndVals,
|
||||||
|
getLongOpt,
|
||||||
|
parseYN,
|
||||||
|
|
||||||
-- * ANSI color
|
-- * ANSI color
|
||||||
colorOption,
|
colorOption,
|
||||||
@ -130,6 +133,7 @@ import Text.Pretty.Simple
|
|||||||
defaultOutputOptionsDarkBg, defaultOutputOptionsNoColor, pShowOpt, pPrintOpt)
|
defaultOutputOptionsDarkBg, defaultOutputOptionsNoColor, pShowOpt, pPrintOpt)
|
||||||
|
|
||||||
import Hledger.Utils.Text (WideBuilder(WideBuilder))
|
import Hledger.Utils.Text (WideBuilder(WideBuilder))
|
||||||
|
import Data.Char (toLower)
|
||||||
|
|
||||||
|
|
||||||
-- Pretty showing/printing with pretty-simple
|
-- Pretty showing/printing with pretty-simple
|
||||||
@ -210,13 +214,18 @@ setupPager = do
|
|||||||
-- supports those, the pager should be configured to display those, otherwise
|
-- supports those, the pager should be configured to display those, otherwise
|
||||||
-- users will see junk on screen (#2015).
|
-- users will see junk on screen (#2015).
|
||||||
-- Call "setupPager" at program startup to make that less likely.
|
-- Call "setupPager" at program startup to make that less likely.
|
||||||
pager :: String -> IO ()
|
--
|
||||||
|
-- Pager use is influenced by the --pager option, at least.
|
||||||
|
-- Rather than pass in a huge CliOpts, or duplicate conditional logic at every call site,
|
||||||
|
-- this does some redundant local options parsing.
|
||||||
|
runPager :: String -> IO ()
|
||||||
#ifdef mingw32_HOST_OS
|
#ifdef mingw32_HOST_OS
|
||||||
pager = putStr
|
runPager = putStr
|
||||||
#else
|
#else
|
||||||
pager s = do
|
runPager s = do
|
||||||
-- disable pager when --no-pager is specified
|
-- disable pager with --pager=no
|
||||||
nopager <- elem "--no-pager" <$> getArgs
|
mpager <- getLongOpt "pager"
|
||||||
|
let nopager = not $ maybe True parseYN mpager
|
||||||
-- disable pager when TERM=dumb (for Emacs shell users)
|
-- disable pager when TERM=dumb (for Emacs shell users)
|
||||||
dumbterm <- (== Just "dumb") <$> lookupEnv "TERM"
|
dumbterm <- (== Just "dumb") <$> lookupEnv "TERM"
|
||||||
-- disable pager with single-line output (https://github.com/pharpend/pager/issues/2)
|
-- disable pager with single-line output (https://github.com/pharpend/pager/issues/2)
|
||||||
@ -238,6 +247,33 @@ pager s = do
|
|||||||
s
|
s
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
-- | Given a list of arguments, split any of the form --flag=val into --flag, val.
|
||||||
|
splitFlagsAndVals :: [String] -> [String]
|
||||||
|
splitFlagsAndVals =
|
||||||
|
concatMap
|
||||||
|
(\a ->
|
||||||
|
if "--" `isPrefixOf` a && '=' `elem` a
|
||||||
|
then let (x,y) = break (=='=') a in [x, drop 1 y]
|
||||||
|
else [a])
|
||||||
|
|
||||||
|
-- | Read the value of the rightmost long option of this name from the command line arguments.
|
||||||
|
-- If the value is missing raise an error.
|
||||||
|
getLongOpt :: String -> IO (Maybe String)
|
||||||
|
getLongOpt name = do
|
||||||
|
rargs <- reverse . splitFlagsAndVals <$> getArgs
|
||||||
|
let flag = "--"<>name
|
||||||
|
return $
|
||||||
|
case break (==flag) rargs of
|
||||||
|
([],_) -> error' $ flag <> " requires a value"
|
||||||
|
(argsafter,_) -> Just $ last argsafter
|
||||||
|
|
||||||
|
-- | Parse y/yes/always or n/no/never to true or false, or with any other value raise an error.
|
||||||
|
parseYN :: String -> Bool
|
||||||
|
parseYN s
|
||||||
|
| l `elem` ["y","yes","always"] = True
|
||||||
|
| l `elem` ["n","no","never"] = False
|
||||||
|
| otherwise = error' $ "value should be one of " <> (intercalate ", " ["y","yes","n","no"])
|
||||||
|
where l = map toLower s
|
||||||
|
|
||||||
-- Command line arguments
|
-- Command line arguments
|
||||||
|
|
||||||
|
|||||||
@ -75,7 +75,7 @@ hledgerUiMain = withGhcDebug' $ withProgName "hledger-ui.log" $ do -- force Hle
|
|||||||
let copts' = copts{inputopts_=iopts{forecast_=forecast_ iopts <|> Just nulldatespan}}
|
let copts' = copts{inputopts_=iopts{forecast_=forecast_ iopts <|> Just nulldatespan}}
|
||||||
|
|
||||||
case True of
|
case True of
|
||||||
_ | boolopt "help" rawopts -> pager $ showModeUsage uimode ++ "\n"
|
_ | boolopt "help" rawopts -> runPager $ showModeUsage uimode ++ "\n"
|
||||||
_ | boolopt "tldr" rawopts -> runTldrForPage "hledger-ui"
|
_ | boolopt "tldr" rawopts -> runTldrForPage "hledger-ui"
|
||||||
_ | boolopt "info" rawopts -> runInfoForTopic "hledger-ui" Nothing
|
_ | boolopt "info" rawopts -> runInfoForTopic "hledger-ui" Nothing
|
||||||
_ | boolopt "man" rawopts -> runManForTopic "hledger-ui" Nothing
|
_ | boolopt "man" rawopts -> runManForTopic "hledger-ui" Nothing
|
||||||
|
|||||||
@ -55,7 +55,7 @@ hledgerWebMain = withGhcDebug' $ do
|
|||||||
wopts@WebOpts{cliopts_=copts@CliOpts{debug_, rawopts_}} <- getHledgerWebOpts
|
wopts@WebOpts{cliopts_=copts@CliOpts{debug_, rawopts_}} <- getHledgerWebOpts
|
||||||
when (debug_ > 0) $ printf "%s\n" prognameandversion >> printf "opts: %s\n" (show wopts)
|
when (debug_ > 0) $ printf "%s\n" prognameandversion >> printf "opts: %s\n" (show wopts)
|
||||||
if
|
if
|
||||||
| boolopt "help" rawopts_ -> pager $ showModeUsage webmode ++ "\n"
|
| boolopt "help" rawopts_ -> runPager $ showModeUsage webmode ++ "\n"
|
||||||
| boolopt "tldr" rawopts_ -> runTldrForPage "hledger-web"
|
| boolopt "tldr" rawopts_ -> runTldrForPage "hledger-web"
|
||||||
| boolopt "info" rawopts_ -> runInfoForTopic "hledger-web" Nothing
|
| boolopt "info" rawopts_ -> runInfoForTopic "hledger-web" Nothing
|
||||||
| boolopt "man" rawopts_ -> runManForTopic "hledger-web" Nothing
|
| boolopt "man" rawopts_ -> runManForTopic "hledger-web" Nothing
|
||||||
|
|||||||
@ -1,3 +1,6 @@
|
|||||||
# This is an empty config file, to disable your personal hledger config
|
# This is an empty config file, to disable your personal hledger config
|
||||||
# while developing and testing hledger in this directory.
|
# while developing and testing hledger in this directory.
|
||||||
# For an example config, see hledger.conf.sample.
|
# For an example config, see hledger.conf.sample.
|
||||||
|
--pager yes
|
||||||
|
# --color=no
|
||||||
|
# --debug
|
||||||
|
|||||||
@ -345,7 +345,7 @@ main = withGhcDebug' $ do
|
|||||||
withArgs (progname:finalargs) $
|
withArgs (progname:finalargs) $
|
||||||
if
|
if
|
||||||
-- 6.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 -> runPager $ 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
|
||||||
@ -375,7 +375,7 @@ main = withGhcDebug' $ do
|
|||||||
-- run the builtin command according to its type
|
-- run the builtin command according to its type
|
||||||
if
|
if
|
||||||
-- 6.5.1. help/doc flag - show command help/docs
|
-- 6.5.1. help/doc flag - show command help/docs
|
||||||
| helpFlag -> pager $ showModeUsage cmdmode ++ "\n"
|
| helpFlag -> runPager $ showModeUsage cmdmode ++ "\n"
|
||||||
| tldrFlag -> runTldrForPage tldrpagename
|
| tldrFlag -> runTldrForPage tldrpagename
|
||||||
| infoFlag -> runInfoForTopic "hledger" mmodecmdname
|
| infoFlag -> runInfoForTopic "hledger" mmodecmdname
|
||||||
| manFlag -> runManForTopic "hledger" mmodecmdname
|
| manFlag -> runManForTopic "hledger" mmodecmdname
|
||||||
|
|||||||
@ -22,8 +22,8 @@ module Hledger.Cli.CliOptions (
|
|||||||
-- * cmdargs flags & modes
|
-- * cmdargs flags & modes
|
||||||
inputflags,
|
inputflags,
|
||||||
reportflags,
|
reportflags,
|
||||||
terminalflags,
|
|
||||||
helpflags,
|
helpflags,
|
||||||
|
terminalflags,
|
||||||
helpflagstitle,
|
helpflagstitle,
|
||||||
flattreeflags,
|
flattreeflags,
|
||||||
confflags,
|
confflags,
|
||||||
@ -240,17 +240,17 @@ helpflags = [
|
|||||||
-- flagOpt would be more correct for --debug, showing --debug[=LVL] rather than --debug=[LVL] in help.
|
-- flagOpt would be more correct for --debug, showing --debug[=LVL] rather than --debug=[LVL] in help.
|
||||||
-- But flagReq plus special handling in Cli.hs makes the = optional, removing a source of confusion.
|
-- But flagReq plus special handling in Cli.hs makes the = optional, removing a source of confusion.
|
||||||
,flagReq ["debug"] (\s opts -> Right $ setopt "debug" s opts) "[1-9]" "show this much debug output (default: 1)"
|
,flagReq ["debug"] (\s opts -> Right $ setopt "debug" s opts) "[1-9]" "show this much debug output (default: 1)"
|
||||||
]
|
] -- XXX why are these duplicated in defCommandMode below ?
|
||||||
-- XXX why are these duplicated in defCommandMode below ?
|
|
||||||
<> terminalflags
|
<> terminalflags
|
||||||
|
|
||||||
-- Low-level flags affecting terminal output.
|
-- Low-level flags affecting terminal output.
|
||||||
-- These are included in helpflags so they appear everywhere.
|
-- These are included in helpflags so they appear everywhere.
|
||||||
terminalflags = [
|
terminalflags = [
|
||||||
flagNone ["no-pager"] (setboolopt "no-pager") "don't use a pager for long output"
|
flagReq ["pager"] (\s opts -> Right $ setopt "pager" s opts) "YN"
|
||||||
|
"use pager for long output ? y/yes or n/no"
|
||||||
-- This has special support in hledger-lib:colorOption, keep synced
|
-- This has special support in hledger-lib:colorOption, keep synced
|
||||||
,flagReq ["color","colour"] (\s opts -> Right $ setopt "color" s opts) "YN"
|
,flagReq ["color","colour"] (\s opts -> Right $ setopt "color" s opts) "YN"
|
||||||
"use ANSI color in terminal ? 'y'/'yes', 'n'/'no', or 'auto' (default)"
|
"use ANSI color ? y/yes, n/no, or auto (default)"
|
||||||
]
|
]
|
||||||
|
|
||||||
-- | Flags for selecting flat/tree mode, used for reports organised by account.
|
-- | Flags for selecting flat/tree mode, used for reports organised by account.
|
||||||
@ -542,6 +542,8 @@ data CliOpts = CliOpts {
|
|||||||
,reportspec_ :: ReportSpec
|
,reportspec_ :: ReportSpec
|
||||||
,output_file_ :: Maybe FilePath
|
,output_file_ :: Maybe FilePath
|
||||||
,output_format_ :: Maybe String
|
,output_format_ :: Maybe String
|
||||||
|
,pageropt_ :: Maybe Bool -- ^ --pager
|
||||||
|
,coloropt_ :: Maybe YNA -- ^ --color. Controls use of ANSI color and ANSI styles.
|
||||||
,debug_ :: Int -- ^ debug level, set by @--debug[=N]@. See also 'Hledger.Utils.debugLevel'.
|
,debug_ :: Int -- ^ debug level, set by @--debug[=N]@. See also 'Hledger.Utils.debugLevel'.
|
||||||
,no_new_accounts_ :: Bool -- add
|
,no_new_accounts_ :: Bool -- add
|
||||||
,width_ :: Maybe String -- ^ the --width value provided, if any
|
,width_ :: Maybe String -- ^ the --width value provided, if any
|
||||||
@ -563,6 +565,8 @@ defcliopts = CliOpts
|
|||||||
, reportspec_ = def
|
, reportspec_ = def
|
||||||
, output_file_ = Nothing
|
, output_file_ = Nothing
|
||||||
, output_format_ = Nothing
|
, output_format_ = Nothing
|
||||||
|
, pageropt_ = Nothing
|
||||||
|
, coloropt_ = Nothing
|
||||||
, debug_ = 0
|
, debug_ = 0
|
||||||
, no_new_accounts_ = False
|
, no_new_accounts_ = False
|
||||||
, width_ = Nothing
|
, width_ = Nothing
|
||||||
@ -621,6 +625,8 @@ rawOptsToCliOpts rawopts = do
|
|||||||
,reportspec_ = rspec
|
,reportspec_ = rspec
|
||||||
,output_file_ = maybestringopt "output-file" rawopts
|
,output_file_ = maybestringopt "output-file" rawopts
|
||||||
,output_format_ = maybestringopt "output-format" rawopts
|
,output_format_ = maybestringopt "output-format" rawopts
|
||||||
|
,pageropt_ = maybeynopt "pager" rawopts
|
||||||
|
,coloropt_ = maybeynaopt "color" rawopts
|
||||||
,debug_ = posintopt "debug" rawopts
|
,debug_ = posintopt "debug" rawopts
|
||||||
,no_new_accounts_ = boolopt "no-new-accounts" rawopts -- add
|
,no_new_accounts_ = boolopt "no-new-accounts" rawopts -- add
|
||||||
,width_ = maybestringopt "width" rawopts
|
,width_ = maybestringopt "width" rawopts
|
||||||
|
|||||||
@ -327,7 +327,7 @@ printCommandsList progversion installedaddons =
|
|||||||
seq (length $ dbg8 "uninstalledknownaddons" uninstalledknownaddons) $ -- for debug output
|
seq (length $ dbg8 "uninstalledknownaddons" uninstalledknownaddons) $ -- for debug output
|
||||||
seq (length $ dbg8 "installedknownaddons" installedknownaddons) $
|
seq (length $ dbg8 "installedknownaddons" installedknownaddons) $
|
||||||
seq (length $ dbg8 "installedunknownaddons" installedunknownaddons) $
|
seq (length $ dbg8 "installedunknownaddons" installedunknownaddons) $
|
||||||
pager $ unlines $ map unplus $ filter (not.isuninstalledaddon) $
|
runPager $ unlines $ map unplus $ filter (not.isuninstalledaddon) $
|
||||||
commandsList progversion installedunknownaddons
|
commandsList progversion installedunknownaddons
|
||||||
where
|
where
|
||||||
knownaddons = knownAddonCommands
|
knownaddons = knownAddonCommands
|
||||||
|
|||||||
@ -130,7 +130,7 @@ writeOutput opts s = do
|
|||||||
writeOutputLazyText :: CliOpts -> TL.Text -> IO ()
|
writeOutputLazyText :: CliOpts -> TL.Text -> IO ()
|
||||||
writeOutputLazyText opts s = do
|
writeOutputLazyText opts s = do
|
||||||
f <- outputFileFromOpts opts
|
f <- outputFileFromOpts opts
|
||||||
maybe (pager . TL.unpack) TL.writeFile f s
|
maybe (runPager . TL.unpack) TL.writeFile f s
|
||||||
|
|
||||||
-- -- | Get a journal from the given string and options, or throw an error.
|
-- -- | Get a journal from the given string and options, or throw an error.
|
||||||
-- readJournal :: CliOpts -> String -> IO Journal
|
-- readJournal :: CliOpts -> String -> IO Journal
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user