The `options` package lets library and application developers easily work with command-line options. This document discusses a handful of the utilities in this package. See the API documentation for the `Options` module for more. ## Introductory example The following example is a full program that can accept two options, `--message` and `--quiet`: ```haskell import Control.Applicative import Options data MainOptions = MainOptions { optMessage :: String , optQuiet :: Bool } . instance Options MainOptions where defineOptions = pure MainOptions <*> simpleOption "message" "Hello world!" "A message to show the user." <*> simpleOption "quiet" False "Whether to be quiet." main :: IO () main = runCommand $ \opts args -> if optQuiet opts then return () else putStrLn (optMessage opts) ``` ``` $ ./hello Hello world! $ ./hello --message='ciao mondo' ciao mondo $ ./hello --quiet $ ``` In addition, this library will automatically create documentation options such as `--help` and `--help-all`: ``` $ ./hello --help Help Options: -h, --help Show option summary. --help-all Show all help options. Application Options: --message :: text A message to show the user. default: "Hello world!" --quiet :: bool Whether to be quiet. default: false ``` ## Defining options ### optionType_bool `optionType_bool` stores an option as a `Bool`. The option's value must be either `"true"` or `"false"`. Boolean options are unary, which means that their value is optional when specified on the command line. If a flag is present, the option is set to `True`. ``` $ ./app -q $ ./app --quiet ``` Boolean options may still be specified explicitly by using long flags with the `--flag=value` format. This is the only way to set a unary flag to `"false"`. ``` $ ./app --quiet=true $ ./app --quiet=false ``` ### optionType_enum `optionType_enum` store an option as one of a set of possible values. The type must be a bounded enumeration, and the type's `Show` instance will be used to implement the parser. This is a simplistic implementation, useful for quick scripts. Users with more complex requirements for enum parsing are encouraged to define their own option types using `optionType`. Example: ```haskell data Action = Hello | Goodbye deriving (Bounded, Enum, Show) data MainOptions = MainOptions { optAction :: Action } instance Options MainOptions where defineOptions = pure MainOptions <*> defineOption (optionType_enum "action") (\o -> o { optionLongFlags = ["action"] , optionDefault = Hello }) main = runCommand $ \opts args -> do putStrLn ("Running action " ++ show (optAction opts)) ``` ``` $ ./app Running action Hello $ ./app --action=Goodbye Running action Goodbye ``` ## Parsing argument lists ### parseOptions `parseOptions` attempts to convert a list of command-line arguments into an options value. This can be used by application developers who want finer control over error handling, or who want to perform additional validation on the options value. The argument list must be in the same encoding as the result of `System.Environment.getArgs`. Use `parsedOptions`, `parsedArguments`, `parsedError`, and `parsedHelp` to inspect the result of `parseOptions`. Example: ```haskell getOptionsOrDie :: Options a => IO a getOptionsOrDie = do argv <- System.Environment.getArgs let parsed = parseOptions argv case parsedOptions parsed of Just opts -> return opts Nothing -> case parsedError parsed of Just err -> do hPutStrLn stderr (parsedHelp parsed) hPutStrLn stderr err exitFailure Nothing -> do hPutStr stdout (parsedHelp parsed) exitSuccess ``` ### parseSubcommand `parseSubcommand` attempts to convert a list of command-line arguments into a subcommand action. This can be used by application developers who want finer control over error handling, or who want subcommands that run in an unusual monad. The argument list must be in the same encoding as the result of `System.Environment.getArgs`. Use `parsedSubcommand`, `parsedError`, and `parsedHelp` to inspect the result of `parseSubcommand`. Example: ```haskell runSubcommand :: Options cmdOpts => [Subcommand cmdOpts (IO a)] -> IO a runSubcommand subcommands = do argv <- System.Environment.getArgs let parsed = parseSubcommand subcommands argv case parsedSubcommand parsed of Just cmd -> cmd Nothing -> case parsedError parsed of Just err -> do hPutStrLn stderr (parsedHelp parsed) hPutStrLn stderr err exitFailure Nothing -> do hPutStr stdout (parsedHelp parsed) exitSuccess ``` ## Running main with options ### runCommand `runCommand` retrieves `System.Environment.getArgs` and attempts to parse it into a valid value of an `Options` type plus a list of left-over arguments. The options and arguments are then passed to the provided computation. If parsing fails, this computation will print an error and call `exitFailure`. If parsing succeeds, and the user has passed a `--help` flag, and the developer is using the default help flag definitions, then this computation will print documentation and call `exitSuccess`. ### runSubcommand `runSubcommand` is used to run applications that are split into subcommands. Use `subcommand` to define available commands and their actions, then pass them to this computation to select one and run it. If the user specifies an invalid subcommand, this computation will print an error and call `exitFailure`. In handling of invalid flags or `--help`, `runSubcommand` acts like `runCommand`. Example: ```haskell import Control.Applicative import Control.Monad (unless) import Options data MainOptions = MainOptions { optQuiet :: Bool } instance Options MainOptions where defineOptions = pure MainOptions <*> simpleOption "quiet" False "Whether to be quiet." data HelloOpts = HelloOpts { optHello :: String } instance Options HelloOpts where defineOptions = pure HelloOpts <*> simpleOption "hello" "Hello!" "How to say hello." data ByeOpts = ByeOpts { optName :: String } instance Options ByeOpts where defineOptions = pure ByeOpts <*> simpleOption "name" "" "The user's name." hello :: MainOptions -> HelloOpts -> [String] -> IO () hello mainOpts opts args = unless (optQuiet mainOpts) $ do putStrLn (optHello opts) bye :: MainOptions -> ByeOpts -> [String] -> IO () bye mainOpts opts args = unless (optQuiet mainOpts) $ do putStrLn ("Good bye " ++ optName opts) main :: IO () main = runSubcommand [ subcommand "hello" hello , subcommand "bye" bye ] ``` ``` $ ./app hello Hello! $ ./app hello --hello='Allo!' Allo! $ ./app bye Good bye $ ./app bye --name='Alice' Good bye Alice ```