{-# LANGUAGE RecordWildCards, PatternGuards #-}
{-|
    This module provides simple command line argument processing.
    The main function of interest is 'cmdArgs'.
    A simple example is:

    @data Sample = Sample {hello :: String} deriving (Show, Data, Typeable)@

@
sample = Sample{hello = 'def' '&=' 'help' \"World argument\" '&=' 'opt' \"world\"}
         '&=' 'summary' \"Sample v1\"
@

    @main = print =<< 'cmdArgs' sample@

    Attributes are used to control a number of behaviours:

    * The help message: 'help', 'typ', 'details', 'summary', 'program', 'groupname'

    * Flag behaviour: 'opt', 'enum', 'verbosity', 'ignore'

    * Flag name assignment: 'name', 'explicit'

    * Controlling non-flag arguments: 'args', 'argPos'

    * multi-mode programs: 'modes', 'auto'

    /Supported Types/: Each field in the record must be one of the supported
    atomic types (@String@, @Int@, @Integer@, @Float@, @Double@, @Bool@, an
    enumeration, a tuple of atomic types) or a list (@[]@) or @Maybe@ wrapping
    at atomic type.

    /Missing Fields/: If a field is shared by multiple modes, it may be omitted
    in subsequent modes, and will default to the previous value.

    /Purity/: Values created with annotations are not pure - the first
    time they are computed they will include the annotations, but subsequently
    they will not. If you wish to run the above example in a more robust way:

    @sample = 'cmdArgsMode' $ Sample{hello = ... -- as before@

    @main = print =<< 'cmdArgsRun' sample@

    Even using this scheme, sometimes GHC's optimisations may share values who
    have the same annotation. To disable sharing you may need to specify
    @\{\-\# OPTIONS_GHC -fno-cse \#\-\}@ in the module you define the flags.

    /Pure annotations/: Alternatively, you may use pure annotations, which are
    referentially transparent, but less type safe and more verbose. The initial
    example may be written as:

    @sample = 'record' Sample{} [hello := 'def' '+=' 'help' \"World argument\" '+=' 'opt' \"world\"]@
    @         '+=' 'summary' \"Sample v1\"@

    @main = print =<< (cmdArgs_ sample :: IO Sample)@

    All the examples are written using impure annotations. To convert to pure
    annotations follow the rules:

    > Ctor {field1 = value1 &= ann1, field2 = value2} &= ann2 ==> record Ctor{} [field1 := value1 += ann1, field2 := value2] += ann2
    > Ctor (value1 &= ann1) value2 &= ann2 ==> record Ctor{} [atom value1 += ann1, atom value2] += ann2
    > modes [Ctor1{...}, Ctor2{...}] ==> modes_ [record Ctor1{} [...], record Ctor2{} [...]]
    > Ctor {field1 = enum [X &= ann, Y]} ==> record Ctor{} [enum_ field1 [atom X += ann, atom Y]]

    If you are willing to use TemplateHaskell, you can write in the impure syntax,
    but have your code automatically translated to the pure style. For more details see
    "System.Console.CmdArgs.Quote".

-}
module System.Console.CmdArgs.Implicit(
    -- * Running command lines
    cmdArgs, cmdArgsMode, cmdArgsRun, cmdArgs_, cmdArgsMode_, cmdArgsApply, CmdArgs(..), -- cmdArgsReform,
    -- * Constructing command lines
    -- | Attributes can work on a flag (inside a field), on a mode (outside the record),
    --   or on all modes (outside the 'modes' call).
    module System.Console.CmdArgs.Implicit.UI,
    -- ** Impure
    (&=), modes, enum,
    -- ** Pure
    (+=), record, atom, Annotate((:=)), enum_, modes_,
    -- * Re-exported for convenience
    -- | Provides a few opaque types (for writing type signatures),
    --   verbosity control, default values with 'def' and the
    --   @Data@/@Typeable@ type classes.
    module System.Console.CmdArgs.Verbosity,
    module System.Console.CmdArgs.Default,
    Ann, Mode,
    Data, Typeable
    ) where

import Data.Data
import Data.Maybe
import Data.Generics.Any
import System.Exit
import System.Console.CmdArgs.Explicit(Mode,processArgs,remap,modeReform)
import System.Console.CmdArgs.Implicit.Ann
import System.Console.CmdArgs.Annotate hiding ((&=))
import qualified System.Console.CmdArgs.Annotate as A((&=))
import System.Console.CmdArgs.Implicit.Type
import System.Console.CmdArgs.Implicit.Local
import System.Console.CmdArgs.Implicit.Global
import System.Console.CmdArgs.Implicit.UI
import System.Console.CmdArgs.Verbosity
import System.Console.CmdArgs.Default


-- | Take impurely annotated records and run the corresponding command line.
--   Shortcut for @'cmdArgsRun' . 'cmdArgsMode'@.
--
--   To use 'cmdArgs' with custom command line arguments see
--   'System.Environment.withArgs'.
cmdArgs :: Data a => a -> IO a
cmdArgs :: a -> IO a
cmdArgs = Mode (CmdArgs a) -> IO a
forall a. Mode (CmdArgs a) -> IO a
cmdArgsRun (Mode (CmdArgs a) -> IO a) -> (a -> Mode (CmdArgs a)) -> a -> IO a
forall b c a. (b -> c) -> (a -> b) -> a -> c
. a -> Mode (CmdArgs a)
forall a. Data a => a -> Mode (CmdArgs a)
cmdArgsMode


-- | Take purely annotated records and run the corresponding command line.
--   Shortcut for @'cmdArgsRun' . 'cmdArgsMode_'@.
--
--   To use 'cmdArgs_' with custom command line arguments see
--   'System.Environment.withArgs'.
cmdArgs_ :: Data a => Annotate Ann -> IO a
cmdArgs_ :: Annotate Ann -> IO a
cmdArgs_ = Mode (CmdArgs a) -> IO a
forall a. Mode (CmdArgs a) -> IO a
cmdArgsRun (Mode (CmdArgs a) -> IO a)
-> (Annotate Ann -> Mode (CmdArgs a)) -> Annotate Ann -> IO a
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Annotate Ann -> Mode (CmdArgs a)
forall a. Data a => Annotate Ann -> Mode (CmdArgs a)
cmdArgsMode_


cmdArgsCapture :: Data a => Capture Ann -> Mode (CmdArgs a)
cmdArgsCapture :: Capture Ann -> Mode (CmdArgs a)
cmdArgsCapture = (CmdArgs Any -> CmdArgs a)
-> (CmdArgs a -> (CmdArgs Any, CmdArgs Any -> CmdArgs a))
-> Mode (CmdArgs Any)
-> Mode (CmdArgs a)
forall (m :: * -> *) a b.
Remap m =>
(a -> b) -> (b -> (a, a -> b)) -> m a -> m b
remap CmdArgs Any -> CmdArgs a
embed CmdArgs a -> (CmdArgs Any, CmdArgs Any -> CmdArgs a)
forall (f :: * -> *) a.
(Functor f, Data a) =>
f a -> (f Any, CmdArgs Any -> CmdArgs a)
proj (Mode (CmdArgs Any) -> Mode (CmdArgs a))
-> (Capture Ann -> Mode (CmdArgs Any))
-> Capture Ann
-> Mode (CmdArgs a)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Prog_ -> Mode (CmdArgs Any)
global (Prog_ -> Mode (CmdArgs Any))
-> (Capture Ann -> Prog_) -> Capture Ann -> Mode (CmdArgs Any)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Capture Ann -> Prog_
local
    where embed :: CmdArgs Any -> CmdArgs a
embed = (Any -> a) -> CmdArgs Any -> CmdArgs a
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap Any -> a
forall a. Typeable a => Any -> a
fromAny
          proj :: f a -> (f Any, CmdArgs Any -> CmdArgs a)
proj f a
x = ((a -> Any) -> f a -> f Any
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap a -> Any
forall a. Data a => a -> Any
Any f a
x, CmdArgs Any -> CmdArgs a
embed)


-- | Take impurely annotated records and turn them in to a 'Mode' value, that can
--   make use of the "System.Console.CmdArgs.Explicit" functions (i.e. 'process').
--
--   Annotated records are impure, and will only contain annotations on
--   their first use. The result of this function is pure, and can be reused.
cmdArgsMode :: Data a => a -> Mode (CmdArgs a)
cmdArgsMode :: a -> Mode (CmdArgs a)
cmdArgsMode = Capture Ann -> Mode (CmdArgs a)
forall a. Data a => Capture Ann -> Mode (CmdArgs a)
cmdArgsCapture (Capture Ann -> Mode (CmdArgs a))
-> (a -> Capture Ann) -> a -> Mode (CmdArgs a)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. a -> Capture Ann
forall val ann. (Data val, Data ann) => val -> Capture ann
capture


-- | Take purely annotated records and turn them in to a 'Mode' value, that can
--   make use of the "System.Console.CmdArgs.Explicit" functions (i.e. 'process').
cmdArgsMode_ :: Data a => Annotate Ann -> Mode (CmdArgs a)
cmdArgsMode_ :: Annotate Ann -> Mode (CmdArgs a)
cmdArgsMode_ = Capture Ann -> Mode (CmdArgs a)
forall a. Data a => Capture Ann -> Mode (CmdArgs a)
cmdArgsCapture (Capture Ann -> Mode (CmdArgs a))
-> (Annotate Ann -> Capture Ann)
-> Annotate Ann
-> Mode (CmdArgs a)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Annotate Ann -> Capture Ann
forall a. Show a => Annotate a -> Capture a
capture_


-- | Run a Mode structure. This function reads the command line arguments
--   and then performs as follows:
--
--   * If invalid arguments are given, it will display the error message
--     and exit.
--
--   * If @--help@ is given, it will display the help message and exit.
--
--   * If @--version@ is given, it will display the version and exit.
--
--   * In all other circumstances the program will return a value.
--
--   * Additionally, if either @--quiet@ or @--verbose@ is given (see 'verbosity')
--     it will set the verbosity (see 'setVerbosity').
cmdArgsRun :: Mode (CmdArgs a) -> IO a
cmdArgsRun :: Mode (CmdArgs a) -> IO a
cmdArgsRun Mode (CmdArgs a)
m = CmdArgs a -> IO a
forall a. CmdArgs a -> IO a
cmdArgsApply (CmdArgs a -> IO a) -> IO (CmdArgs a) -> IO a
forall (m :: * -> *) a b. Monad m => (a -> m b) -> m a -> m b
=<< Mode (CmdArgs a) -> IO (CmdArgs a)
forall a. Mode a -> IO a
processArgs Mode (CmdArgs a)
m


-- | Perform the necessary actions dictated by a 'CmdArgs' structure.
--
--   * If 'cmdArgsHelp' is @Just@, it will display the help message and exit.
--
--   * If 'cmdArgsVersion' is @Just@, it will display the version and exit.
--
--   * In all other circumstances it will return a value.
--
--   * Additionally, if 'cmdArgsVerbosity' is @Just@ (see 'verbosity')
--     it will set the verbosity (see 'setVerbosity').
cmdArgsApply :: CmdArgs a -> IO a
cmdArgsApply :: CmdArgs a -> IO a
cmdArgsApply CmdArgs{a
Maybe String
Maybe Verbosity
CmdArgsPrivate
cmdArgsPrivate :: forall a. CmdArgs a -> CmdArgsPrivate
cmdArgsVerbosity :: forall a. CmdArgs a -> Maybe Verbosity
cmdArgsVersion :: forall a. CmdArgs a -> Maybe String
cmdArgsHelp :: forall a. CmdArgs a -> Maybe String
cmdArgsValue :: forall a. CmdArgs a -> a
cmdArgsPrivate :: CmdArgsPrivate
cmdArgsVerbosity :: Maybe Verbosity
cmdArgsVersion :: Maybe String
cmdArgsHelp :: Maybe String
cmdArgsValue :: a
..}
    | Just String
x <- Maybe String
cmdArgsHelp = do String -> IO ()
putStr String
x; IO a
forall a. IO a
exitSuccess
    | Just String
x <- Maybe String
cmdArgsVersion = do String -> IO ()
putStr String
x; IO a
forall a. IO a
exitSuccess
    | Bool
otherwise = do
        IO () -> (Verbosity -> IO ()) -> Maybe Verbosity -> IO ()
forall b a. b -> (a -> b) -> Maybe a -> b
maybe (() -> IO ()
forall (m :: * -> *) a. Monad m => a -> m a
return ()) Verbosity -> IO ()
setVerbosity Maybe Verbosity
cmdArgsVerbosity
        a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return a
cmdArgsValue


-- | Produce command line arguments that would generate the given value. This
--   function is useful for taking a value resulting from a command line,
--   modifying it (perhaps changing the value of a flag) and generating fresh
--   command line arguments.
--
-- > forall mode values constructed by cmdArgsMode/cmdArgsMode:
-- > forall args which successfully parse with mode
-- > let x = processValue mode args
-- > processValue mode (cmdArgsReform mode $ fromRight x) == x
_cmdArgsReform :: Mode (CmdArgs a) -> CmdArgs a -> [String]
_cmdArgsReform :: Mode (CmdArgs a) -> CmdArgs a -> [String]
_cmdArgsReform Mode (CmdArgs a)
m CmdArgs a
x = [String] -> Maybe [String] -> [String]
forall a. a -> Maybe a -> a
fromMaybe (String -> [String]
forall a. HasCallStack => String -> a
error String
err) (Maybe [String] -> [String]) -> Maybe [String] -> [String]
forall a b. (a -> b) -> a -> b
$ Mode (CmdArgs a) -> CmdArgs a -> Maybe [String]
forall a. Mode a -> a -> Maybe [String]
modeReform Mode (CmdArgs a)
m CmdArgs a
x
    where err :: String
err = String
"System.Console.CmdArgs.Implicit.cmdArgsReform: cannot reform the arguments, perhaps the mode was not " String -> String -> String
forall a. [a] -> [a] -> [a]
++
                String
"generated by cmdArgsMode/cmdArgsMode_ ?"


-- | Modes: \"I want a program with multiple modes, like darcs or cabal.\"
--
--   Takes a list of modes, and creates a mode which includes them all.
--   If you want one of the modes to be chosen by default, see 'auto'.
--
-- > data Modes = Mode1 | Mode2 | Mode3 deriving Data
-- > cmdArgs $ modes [Mode1,Mode2,Mode3]
modes :: Data val => [val] -> val
modes :: [val] -> val
modes = [val] -> val
forall val. Data val => [val] -> val
many

-- | Flag: \"I want several different flags to set this one field to different values.\"
--
--   This annotation takes a type which is an enumeration, and provides multiple
--   separate flags to set the field to each value. The first element in the list
--   is used as the value of the field.
--
-- > data State = On | Off deriving Data
-- > data Mode = Mode {state :: State}
-- > cmdArgs $ Mode {state = enum [On &= help "Turn on",Off &= help "Turn off"]}
-- >   --on   Turn on
-- >   --off  Turn off
--
--   This annotation can be used to allow multiple flags within a field:
--
-- > data Mode = Mode {state :: [State]}
-- > cmdArgs $ Mode {state = enum [[] &= ignore, [On] &= help "Turn on", [Off] &= help "Turn off"]}
--
--   Now @--on --off@ would produce @Mode [On,Off]@.
enum :: Data val => [val] -> val
enum :: [val] -> val
enum = [val] -> val
forall val. Data val => [val] -> val
many


-- | Add an annotation to a value. Note that if the value is evaluated
--   more than once the annotation will only be available the first time.
{-# INLINE (&=) #-}
(&=) :: Data val => val -> Ann -> val
&= :: val -> Ann -> val
(&=) = val -> Ann -> val
forall val ann. (Data val, Data ann) => val -> ann -> val
(A.&=)


-- | Like 'enum', but using the pure annotations.
enum_ :: (Data c, Data f) => (c -> f) -> [Annotate Ann] -> Annotate Ann
enum_ :: (c -> f) -> [Annotate Ann] -> Annotate Ann
enum_ = (c -> f) -> [Annotate Ann] -> Annotate Ann
forall ann c f.
(Data c, Data f) =>
(c -> f) -> [Annotate ann] -> Annotate ann
(:=+)

-- | Like 'modes', but using the pure annotations.
modes_ :: [Annotate Ann] -> Annotate Ann
modes_ :: [Annotate Ann] -> Annotate Ann
modes_ = [Annotate Ann] -> Annotate Ann
forall a. [Annotate a] -> Annotate a
many_