content: {-# 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 = cmdArgsRun . 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_ = cmdArgsRun . cmdArgsMode_
  
  
  cmdArgsCapture :: Data a => Capture Ann -> Mode (CmdArgs a)
  cmdArgsCapture = remap embed proj . global . local
      where embed = fmap fromAny
            proj x = (fmap Any x, 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 = cmdArgsCapture . 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_ = cmdArgsCapture . 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 m = cmdArgsApply =<< processArgs 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{..}
      | Just x <- cmdArgsHelp = do putStr x; exitSuccess
      | Just x <- cmdArgsVersion = do putStr x; exitSuccess
      | otherwise = do
          maybe (return ()) setVerbosity cmdArgsVerbosity
          return 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 m x = fromMaybe (error err) $ modeReform m x
      where err = "System.Console.CmdArgs.Implicit.cmdArgsReform: cannot reform the arguments, perhaps the mode was not " ++
                  "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 = 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 = 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
  (&=) = (A.&=)
  
  
  -- | Like 'enum', but using the pure annotations.
  enum_ :: (Data c, Data f) => (c -> f) -> [Annotate Ann] -> Annotate Ann
  enum_ = (:=+)
  
  -- | Like 'modes', but using the pure annotations.
  modes_ :: [Annotate Ann] -> Annotate Ann
  modes_ = many_
  