    {-# LANGUAGE ScopedTypeVariables, CPP #-}
    {-|
        This module constructs command lines. You may either use the helper functions
        ('flagNone', 'flagOpt', 'mode' etc.) or construct the type directly. These
        types are intended to give all the necessary power to the person constructing
        a command line parser.

        For people constructing simpler command line parsers, the module
        "System.Console.CmdArgs.Implicit" may be more appropriate.

        As an example of a parser:

        @
        arguments :: 'Mode' [(String,String)]
        arguments = 'mode' \"explicit\" [] \"Explicit sample program\" ('flagArg' (upd \"file\") \"FILE\")
            ['flagOpt' \"world\" [\"hello\",\"h\"] (upd \"world\") \"WHO\" \"World argument\"
            ,'flagReq' [\"greeting\",\"g\"] (upd \"greeting\") \"MSG\" \"Greeting to give\"
            ,'flagHelpSimple' ((\"help\",\"\"):)]
            where upd msg x v = Right $ (msg,x):v
        @

        And this can be invoked by:

        @
        main = do
            xs <- 'processArgs' arguments
            if (\"help\",\"\") \`elem\` xs then
                print $ 'helpText' [] 'HelpFormatDefault' arguments
             else
                print xs
        @

        /Groups/: The 'Group' structure allows flags/modes to be grouped for the purpose of
        displaying help. When processing command lines, the group structure is ignored.

        /Modes/: The Explicit module allows multiple mode programs by placing additional modes
        in 'modeGroupModes'. Every mode is allowed sub-modes, and thus multiple levels of mode
        may be created. Given a mode @x@ with sub-modes @xs@, if the first argument corresponds
        to the name of a sub-mode, then that sub-mode will be applied. If not, then the arguments
        will be processed by mode @x@. Consequently, if you wish to force the user to explicitly
        enter a mode, simply give sub-modes, and leave 'modeArgs' as @Nothing@. Alternatively, if
        you want one sub-mode to be selected by default, place all it's flags both in the sub-mode
        and the outer mode.

        /Parsing rules/: Command lines are parsed as per most GNU programs. Short arguments single
        letter flags start with @-@, longer flags start with @--@, and everything else is considered
        an argument. Anything after @--@ alone is considered to be an argument. For example:

      > -f --flag argument1 -- --argument2

        This command line passes one single letter flag (@f@), one longer flag (@flag@) and two arguments
        (@argument1@ and @--argument2@).
    -}
    module System.Console.CmdArgs.Explicit(
        -- * Running command lines
        process, processArgs, processValue, processValueIO,
        -- * Constructing command lines
        module System.Console.CmdArgs.Explicit.Type,
        flagHelpSimple, flagHelpFormat, flagVersion, flagNumericVersion, flagsVerbosity,
        -- * Displaying help
        module System.Console.CmdArgs.Explicit.Help,
        -- * Utilities for working with command lines
        module System.Console.CmdArgs.Explicit.ExpandArgsAt,
        module System.Console.CmdArgs.Explicit.SplitJoin,
        Complete(..), complete
        ) where

    import System.Console.CmdArgs.Explicit.Type
    import System.Console.CmdArgs.Explicit.Process
    import System.Console.CmdArgs.Explicit.Help
    import System.Console.CmdArgs.Explicit.ExpandArgsAt
    import System.Console.CmdArgs.Explicit.SplitJoin
    import System.Console.CmdArgs.Explicit.Complete
    import System.Console.CmdArgs.Default
    import System.Console.CmdArgs.Helper
    import System.Console.CmdArgs.Text
    import System.Console.CmdArgs.Verbosity

    import Control.Monad
    import Data.Char
    import Data.Maybe
    import System.Environment
    import System.Exit
    import System.IO

    -- | Process the flags obtained by @'getArgs'@ and @'expandArgsAt'@ with a mode. Displays
    --   an error and exits with failure if the command line fails to parse, or returns
    --   the associated value. Implemented in terms of 'process'. This function makes
    --   use of the following environment variables:
    --
    -- * @$CMDARGS_COMPLETE@ - causes the program to produce completions using 'complete', then exit.
    --   Completions are based on the result of 'getArgs', the index of the current argument is taken
    --   from @$CMDARGS_COMPLETE@ (set it to @-@ to complete the last argument), and the index within
    --   that argument is taken from @$CMDARGS_COMPLETE_POS@ (if set).
    --
    -- * @$CMDARGS_HELPER@\/@$CMDARGS_HELPER_/PROG/@ - uses the helper mechanism for entering command
    --   line programs as described in "System.Console.CmdArgs.Helper".
    processArgs :: Mode a -> IO a
    processArgs :: forall a. Mode a -> IO a
    processArgs Mode a
    m = do
        [(String, String)]
    env <- IO [(String, String)]
    getEnvironment
        case String -> [(String, String)] -> Maybe String
    forall a b. Eq a => a -> [(a, b)] -> Maybe b
    lookup String
    "CMDARGS_COMPLETE" [(String, String)]
    env of
            Just String
    x -> do
                [String]
    args <- IO [String]
    getArgs
                let argInd :: Int
    argInd = Int -> Maybe Int -> Int
    forall a. a -> Maybe a -> a
    fromMaybe ([String] -> Int
    forall a. [a] -> Int
    forall (t :: * -> *) a. Foldable t => t a -> Int
    length [String]
    args Int -> Int -> Int
    forall a. Num a => a -> a -> a
    - Int
    1) (Maybe Int -> Int) -> Maybe Int -> Int
    forall a b. (a -> b) -> a -> b
    $ String -> Maybe Int
    forall a. Read a => String -> Maybe a
    readMay String
    x
                    argPos :: Int
    argPos = Int -> Maybe Int -> Int
    forall a. a -> Maybe a -> a
    fromMaybe (if Int
    argInd Int -> Int -> Bool
    forall a. Ord a => a -> a -> Bool
    >= Int
    0 Bool -> Bool -> Bool
    && Int
    argInd Int -> Int -> Bool
    forall a. Ord a => a -> a -> Bool
    < [String] -> Int
    forall a. [a] -> Int
    forall (t :: * -> *) a. Foldable t => t a -> Int
    length [String]
    args then String -> Int
    forall a. [a] -> Int
    forall (t :: * -> *) a. Foldable t => t a -> Int
    length ([String]
    args [String] -> Int -> String
    forall a. HasCallStack => [a] -> Int -> a
    !! Int
    argInd) else Int
    0) (Maybe Int -> Int) -> Maybe Int -> Int
    forall a b. (a -> b) -> a -> b
    $
                             String -> Maybe Int
    forall a. Read a => String -> Maybe a
    readMay (String -> Maybe Int) -> Maybe String -> Maybe Int
    forall (m :: * -> *) a b. Monad m => (a -> m b) -> m a -> m b
    =<< String -> [(String, String)] -> Maybe String
    forall a b. Eq a => a -> [(a, b)] -> Maybe b
    lookup String
    "CMDARGS_COMPLETE_POS" [(String, String)]
    env
                [Complete] -> IO ()
    forall a. Show a => a -> IO ()
    print ([Complete] -> IO ()) -> [Complete] -> IO ()
    forall a b. (a -> b) -> a -> b
    $ Mode a -> [String] -> (Int, Int) -> [Complete]
    forall a. Mode a -> [String] -> (Int, Int) -> [Complete]
    complete Mode a
    m ((String -> [String]) -> [String] -> [String]
    forall (t :: * -> *) a b. Foldable t => (a -> [b]) -> t a -> [b]
    concatMap String -> [String]
    words [String]
    args) (Int
    argInd,Int
    argPos)
                ExitCode -> IO a
    forall a. ExitCode -> IO a
    exitWith ExitCode
    ExitSuccess
            Maybe String
    Nothing -> do
                String
    nam <- IO String
    getProgName
                let var :: Maybe String
    var = Maybe String -> Maybe String -> Maybe String
    forall a. Maybe a -> Maybe a -> Maybe a
    forall (m :: * -> *) a. MonadPlus m => m a -> m a -> m a
    mplus (String -> [(String, String)] -> Maybe String
    forall a b. Eq a => a -> [(a, b)] -> Maybe b
    lookup (String
    "CMDARGS_HELPER_" String -> String -> String
    forall a. [a] -> [a] -> [a]
    ++ String -> String
    forall a. Show a => a -> String
    show ((Char -> Char) -> String -> String
    forall a b. (a -> b) -> [a] -> [b]
    map Char -> Char
    toUpper (String -> String) -> String -> String
    forall a b. (a -> b) -> a -> b
    $ [String] -> String
    forall a. HasCallStack => [a] -> a
    head ([String] -> String) -> [String] -> String
    forall a b. (a -> b) -> a -> b
    $ Mode a -> [String]
    forall a. Mode a -> [String]
    modeNames Mode a
    m [String] -> [String] -> [String]
    forall a. [a] -> [a] -> [a]
    ++ [String
    nam])) [(String, String)]
    env)
                                (String -> [(String, String)] -> Maybe String
    forall a b. Eq a => a -> [(a, b)] -> Maybe b
    lookup String
    "CMDARGS_HELPER" [(String, String)]
    env)
                case Maybe String
    var of
                    Maybe String
    Nothing -> Mode a -> [String] -> IO a
    forall a. Mode a -> [String] -> IO a
    processValueIO Mode a
    m ([String] -> IO a) -> IO [String] -> IO a
    forall (m :: * -> *) a b. Monad m => (a -> m b) -> m a -> m b
    =<< (if Mode a -> Bool
    forall a. Mode a -> Bool
    modeExpandAt Mode a
    m then [String] -> IO [String]
    expandArgsAt else [String] -> IO [String]
    forall a. a -> IO a
    forall (m :: * -> *) a. Monad m => a -> m a
    return) ([String] -> IO [String]) -> IO [String] -> IO [String]
    forall (m :: * -> *) a b. Monad m => (a -> m b) -> m a -> m b
    =<< IO [String]
    getArgs
                    Just String
    cmd -> do
                        Either String [String]
    res <- String -> Mode a -> [String] -> IO (Either String [String])
    forall a.
    String -> Mode a -> [String] -> IO (Either String [String])
    execute String
    cmd Mode a
    m []
                        case Either String [String]
    res of
                            Left String
    err -> do
                                Handle -> String -> IO ()
    hPutStrLn Handle
    stderr (String -> IO ()) -> String -> IO ()
    forall a b. (a -> b) -> a -> b
    $ String
    "Error when running helper " String -> String -> String
    forall a. [a] -> [a] -> [a]
    ++ String
    cmd
                                Handle -> String -> IO ()
    hPutStrLn Handle
    stderr String
    err
                                IO a
    forall a. IO a
    exitFailure
                            Right [String]
    args -> Mode a -> [String] -> IO a
    forall a. Mode a -> [String] -> IO a
    processValueIO Mode a
    m [String]
    args

    readMay :: Read a => String -> Maybe a
    readMay :: forall a. Read a => String -> Maybe a
    readMay String
    s = case [a
    x | (a
    x,String
    t) <- ReadS a
    forall a. Read a => ReadS a
    reads String
    s, (String
    "",String
    "") <- ReadS String
    lex String
    t] of
                    [a
    x] -> a -> Maybe a
    forall a. a -> Maybe a
    Just a
    x
                    [a]
    _ -> Maybe a
    forall a. Maybe a
    Nothing

    #if __GLASGOW_HASKELL__ < 800
    errorWithoutStackTrace :: String -> a
    errorWithoutStackTrace = error
    #endif

    -- | Process a list of flags (usually obtained from @'getArgs'@ and @'expandArgsAt'@) with a mode.
    --   Throws an error if the command line fails to parse, or returns
    --   the associated value. Implemeneted in terms of 'process'. This function
    --   does not take account of any environment variables that may be set
    --   (see 'processArgs').
    --
    --   If you are in 'IO' you will probably get a better user experience by calling 'processValueIO'.
    processValue :: Mode a -> [String] -> a
    processValue :: forall a. Mode a -> [String] -> a
    processValue Mode a
    m [String]
    xs = case Mode a -> [String] -> Either String a
    forall a. Mode a -> [String] -> Either String a
    process Mode a
    m [String]
    xs of
        Left String
    x -> String -> a
    forall a. String -> a
    errorWithoutStackTrace String
    x
        Right a
    x -> a
    x

    -- | Like 'processValue' but on failure prints to stderr and exits the program.
    processValueIO :: Mode a -> [String] -> IO a
    processValueIO :: forall a. Mode a -> [String] -> IO a
    processValueIO Mode a
    m [String]
    xs = case Mode a -> [String] -> Either String a
    forall a. Mode a -> [String] -> Either String a
    process Mode a
    m [String]
    xs of
        Left String
    x -> do Handle -> String -> IO ()
    hPutStrLn Handle
    stderr String
    x; IO a
    forall a. IO a
    exitFailure
        Right a
    x -> a -> IO a
    forall a. a -> IO a
    forall (m :: * -> *) a. Monad m => a -> m a
    return a
    x

    -- | Create a help flag triggered by @-?@/@--help@.
    flagHelpSimple :: (a -> a) -> Flag a
    flagHelpSimple :: forall a. (a -> a) -> Flag a
    flagHelpSimple a -> a
    f = [String] -> (a -> a) -> String -> Flag a
    forall a. [String] -> (a -> a) -> String -> Flag a
    flagNone [String
    "help",String
    "?"] a -> a
    f String
    "Display help message"

    -- | Create a help flag triggered by @-?@/@--help@. The user
    --   may optionally modify help by specifying the format, such as:
    --
    -- > --help=all          - help for all modes
    -- > --help=html         - help in HTML format
    -- > --help=100          - wrap the text at 100 characters
    -- > --help=100,one      - full text wrapped at 100 characters
    flagHelpFormat :: (HelpFormat -> TextFormat -> a -> a) -> Flag a
    flagHelpFormat :: forall a. (HelpFormat -> TextFormat -> a -> a) -> Flag a
    flagHelpFormat HelpFormat -> TextFormat -> a -> a
    f = (String -> [String] -> Update a -> String -> String -> Flag a
    forall a.
    String -> [String] -> Update a -> String -> String -> Flag a
    flagOpt String
    "" [String
    "help",String
    "?"] Update a
    upd String
    "" String
    "Display help message"){flagInfo = FlagOptRare ""}
        where
            upd :: Update a
    upd String
    s a
    v = case String -> Either String (HelpFormat, TextFormat)
    format String
    s of
                Left String
    e -> String -> Either String a
    forall a b. a -> Either a b
    Left String
    e
                Right (HelpFormat
    a,TextFormat
    b) -> a -> Either String a
    forall a b. b -> Either a b
    Right (a -> Either String a) -> a -> Either String a
    forall a b. (a -> b) -> a -> b
    $ HelpFormat -> TextFormat -> a -> a
    f HelpFormat
    a TextFormat
    b a
    v

            format :: String -> Either String (HelpFormat,TextFormat)
            format :: String -> Either String (HelpFormat, TextFormat)
    format String
    xs = (Either String (HelpFormat, TextFormat)
     -> String -> Either String (HelpFormat, TextFormat))
    -> Either String (HelpFormat, TextFormat)
    -> [String]
    -> Either String (HelpFormat, TextFormat)
    forall b a. (b -> a -> b) -> b -> [a] -> b
    forall (t :: * -> *) b a.
    Foldable t =>
    (b -> a -> b) -> b -> t a -> b
    foldl (\Either String (HelpFormat, TextFormat)
    acc String
    x -> String
    -> (HelpFormat, TextFormat)
    -> Either String (HelpFormat, TextFormat)
    f String
    x ((HelpFormat, TextFormat)
     -> Either String (HelpFormat, TextFormat))
    -> Either String (HelpFormat, TextFormat)
    -> Either String (HelpFormat, TextFormat)
    forall (m :: * -> *) a b. Monad m => (a -> m b) -> m a -> m b
    =<< Either String (HelpFormat, TextFormat)
    acc) ((HelpFormat, TextFormat) -> Either String (HelpFormat, TextFormat)
    forall a b. b -> Either a b
    Right (HelpFormat, TextFormat)
    forall a. Default a => a
    def) (String -> [String]
    sep String
    xs)
                where
                    sep :: String -> [String]
    sep = String -> [String]
    words (String -> [String]) -> (String -> String) -> String -> [String]
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . (Char -> Char) -> String -> String
    forall a b. (a -> b) -> [a] -> [b]
    map (\Char
    x -> if Char
    x Char -> String -> Bool
    forall a. Eq a => a -> [a] -> Bool
    forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
    `elem` String
    ":," then Char
    ' ' else Char -> Char
    toLower Char
    x)
                    f :: String
    -> (HelpFormat, TextFormat)
    -> Either String (HelpFormat, TextFormat)
    f String
    x (HelpFormat
    a,TextFormat
    b) = case String
    x of
                        String
    "all" -> (HelpFormat, TextFormat) -> Either String (HelpFormat, TextFormat)
    forall a b. b -> Either a b
    Right (HelpFormat
    HelpFormatAll,TextFormat
    b)
                        String
    "one" -> (HelpFormat, TextFormat) -> Either String (HelpFormat, TextFormat)
    forall a b. b -> Either a b
    Right (HelpFormat
    HelpFormatOne,TextFormat
    b)
                        String
    "def" -> (HelpFormat, TextFormat) -> Either String (HelpFormat, TextFormat)
    forall a b. b -> Either a b
    Right (HelpFormat
    HelpFormatDefault,TextFormat
    b)
                        String
    "html" -> (HelpFormat, TextFormat) -> Either String (HelpFormat, TextFormat)
    forall a b. b -> Either a b
    Right (HelpFormat
    a,TextFormat
    HTML)
                        String
    "text" -> (HelpFormat, TextFormat) -> Either String (HelpFormat, TextFormat)
    forall a b. b -> Either a b
    Right (HelpFormat
    a,TextFormat
    defaultWrap)
                        String
    "bash" -> (HelpFormat, TextFormat) -> Either String (HelpFormat, TextFormat)
    forall a b. b -> Either a b
    Right (HelpFormat
    HelpFormatBash,Int -> TextFormat
    Wrap Int
    1000000)
                        String
    "zsh"  -> (HelpFormat, TextFormat) -> Either String (HelpFormat, TextFormat)
    forall a b. b -> Either a b
    Right (HelpFormat
    HelpFormatZsh ,Int -> TextFormat
    Wrap Int
    1000000)
                        String
    _ | (Char -> Bool) -> String -> Bool
    forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Bool
    all Char -> Bool
    isDigit String
    x -> (HelpFormat, TextFormat) -> Either String (HelpFormat, TextFormat)
    forall a b. b -> Either a b
    Right (HelpFormat
    a,Int -> TextFormat
    Wrap (Int -> TextFormat) -> Int -> TextFormat
    forall a b. (a -> b) -> a -> b
    $ String -> Int
    forall a. Read a => String -> a
    read String
    x)
                        String
    _ -> String -> Either String (HelpFormat, TextFormat)
    forall a b. a -> Either a b
    Left String
    "unrecognised help format, expected one of: all one def html text <NUMBER>"

    -- | Create a version flag triggered by @-V@/@--version@.
    flagVersion :: (a -> a) -> Flag a
    flagVersion :: forall a. (a -> a) -> Flag a
    flagVersion a -> a
    f = [String] -> (a -> a) -> String -> Flag a
    forall a. [String] -> (a -> a) -> String -> Flag a
    flagNone [String
    "version",String
    "V"] a -> a
    f String
    "Print version information"

    -- | Create a version flag triggered by @--numeric-version@.
    flagNumericVersion :: (a -> a) -> Flag a
    flagNumericVersion :: forall a. (a -> a) -> Flag a
    flagNumericVersion a -> a
    f = [String] -> (a -> a) -> String -> Flag a
    forall a. [String] -> (a -> a) -> String -> Flag a
    flagNone [String
    "numeric-version"] a -> a
    f String
    "Print just the version number"

    -- | Create verbosity flags triggered by @-v@/@--verbose@ and
    --   @-q@/@--quiet@
    flagsVerbosity :: (Verbosity -> a -> a) -> [Flag a]
    flagsVerbosity :: forall a. (Verbosity -> a -> a) -> [Flag a]
    flagsVerbosity Verbosity -> a -> a
    f =
        [[String] -> (a -> a) -> String -> Flag a
    forall a. [String] -> (a -> a) -> String -> Flag a
    flagNone [String
    "verbose",String
    "v"] (Verbosity -> a -> a
    f Verbosity
    Loud) String
    "Loud verbosity"
        ,[String] -> (a -> a) -> String -> Flag a
    forall a. [String] -> (a -> a) -> String -> Flag a
    flagNone [String
    "quiet",String
    "q"] (Verbosity -> a -> a
    f Verbosity
    Quiet) String
    "Quiet verbosity"]