I would like to add synonyms for the subcommands in my Haskell command line tool. For example summarise
and summarize
should yield the same result. Of course I could just add an entirely separate command summarize
, that appears as an own element in the output of --help
. But maybe there is a more elegant way.
Here is a self-contained example in a stack script opt_ex.hs
:
#!/usr/bin/env stack
-- stack --resolver lts-18.17 script --package optparse-applicative
import Options.Applicative
import Data.Semigroup ((<>))
data Options = CmdGreet GreetArgs | CmdGroot GreetArgs
newtype GreetArgs = GreetArgs String
main :: IO ()
main = do
cmdOpts <- customExecParser (prefs showHelpOnEmpty) (info optParser fullDesc)
runCmd cmdOpts
optParser :: Parser Options
optParser = subparser (
command "greet" (info (CmdGreet <$> sample) (progDesc "Print greeting 1")) <>
command "groot" (info (CmdGroot <$> sample) (progDesc "Print greeting 2"))
)
runCmd :: Options -> IO ()
runCmd o = case o of
CmdGreet opts -> greet opts
CmdGroot opts -> groot opts
greet :: GreetArgs -> IO ()
greet (GreetArgs h) = putStrLn $ "Hello, " ++ h ++ "!"
groot :: GreetArgs -> IO ()
groot (GreetArgs h) = putStrLn $ "Howdy, " ++ h ++ "!"
sample :: Parser GreetArgs
sample = GreetArgs <$> strArgument ( metavar "TARGET" )
You can run this with ./opt_ex.hs greet John
to get Hello, John!
and with ./opt_ex.hs groot John
to get Howdy, John!
. Running ./opt_ex.hs
will give you the following overview:
Usage: opt_ex.hs COMMAND
Available commands:
greet Print greeting 1
groot Print greeting 2
What would be the most elegant way, to add a command gruut
in this example, which behaves exactly like greet
, but produces the least amount of overhead, both in the code and for the user?
Ideally I would like ./opt_ex.hs
to yield something like this:
Usage: opt_ex.hs COMMAND
Available commands:
greet|gruut Print greeting 1
groot Print greeting 2
I don't think you can do this. It works fine for options, because the definition of OptField contains a list of OptName, and adds to that list when you use
(<>)
. But the definition of CommandFields, the thing returned bycommand
, isEach String name is thus associated with a different ParserInfo. Of course, you can define a variable containing any ParserInfo you like, and reuse it across two commands, so you won't have to repeat the ParserInfo. But as far as optparse-applicative is concerned, those two commands are distinct, so it will list them separately in the help text. For your example, this would look like
and indeed, when run we see both commands listed: