-- Hoogle documentation, generated by Haddock -- See Hoogle, http://www.haskell.org/hoogle/ -- | Create command line interfaces with ease -- @package getopt-generics @version 0.10 module System.Console.GetOpt.Generics -- | simpleCLI converts an IO operation into a program with a proper -- CLI. Retrieves command line arguments through withArgs. -- main (the given IO operation) can have arbitrarily many -- parameters provided all parameters have an instance for Option. -- -- May throw the following exceptions: -- --
-- import System.Console.GetOpt.Generics -- -- main :: IO () -- main = simpleCLI myMain -- -- myMain :: String -> Int -> Bool -> IO () -- myMain s i b = print (s, i, b) ---- -- Using the above program in bash: -- --
-- $ program foo 42 true
-- ("foo",42,True)
-- $ program foo 42 bar
-- cannot parse as BOOL: bar
-- $ program --help
-- program [OPTIONS] STRING INTEGER BOOL
-- -h --help show help and exit
--
simpleCLI :: (SimpleCLI main, All Option (ArgumentTypes main)) => main -> IO ()
class SingI (ArgumentTypes main) => SimpleCLI main where type family ArgumentTypes main :: [*]
-- | Parses command line arguments (gotten from withArgs) and
-- returns the parsed value. This function should be enough for simple
-- use-cases.
--
-- Throws the same exceptions as simpleCLI.
--
-- Here's an example:
--
--
-- {-# LANGUAGE DeriveGeneric #-}
--
-- import GHC.Generics
-- import System.Console.GetOpt.Generics
--
-- -- All you have to do is to define a type and derive some instances:
--
-- data Options
-- = Options {
-- port :: Int,
-- daemonize :: Bool,
-- config :: Maybe FilePath
-- }
-- deriving (Show, GHC.Generics.Generic)
--
-- instance System.Console.GetOpt.Generics.Generic Options
-- instance HasDatatypeInfo Options
--
-- -- Then you can use `getArguments` to create a command-line argument parser:
--
-- main :: IO ()
-- main = do
-- options <- getArguments
-- print (options :: Options)
--
--
-- And this is how the above program behaves:
--
--
-- $ program --port 8080 --config some/path
-- Options {port = 8080, daemonize = False, config = Just "some/path"}
-- $ program --port 8080 --daemonize
-- Options {port = 8080, daemonize = True, config = Nothing}
-- $ program --port foo
-- cannot parse as INTEGER: foo
-- $ program
-- missing option: --port=INTEGER
-- $ program --help
-- program [OPTIONS]
-- --port=INTEGER
-- --daemonize
-- --config=STRING (optional)
-- -h --help show help and exit
--
getArguments :: (Generic a, HasDatatypeInfo a, All2 Option (Code a)) => IO a
-- | Like getArguments but allows you to pass in Modifiers.
modifiedGetArguments :: (Generic a, HasDatatypeInfo a, All2 Option (Code a)) => [Modifier] -> IO a
-- | Pure variant of modifiedGetArguments.
--
-- Does not throw any exceptions.
parseArguments :: (Generic a, HasDatatypeInfo a, All2 Option (Code a)) => String -> [Modifier] -> [String] -> Result a
-- | Type to wrap results from the pure parsing functions.
data Result a
-- | The CLI was used correctly and a value of type a was
-- successfully constructed.
Success :: a -> Result a
-- | The CLI was used incorrectly. The Result contains a list of
-- error messages.
--
-- It can also happen that the data type you're trying to use isn't
-- supported. See the README for details.
Errors :: [String] -> Result a
-- | The CLI was used with --help. The Result contains the
-- help message.
OutputAndExit :: String -> Result a
-- | Modifiers can be used to customize the command line parser.
data Modifier
-- | AddShortOption fieldName c adds the Char c as
-- a short option for the field addressed by fieldName.
AddShortOption :: String -> Char -> Modifier
-- | RenameOption fieldName customName renames the option
-- generated through the fieldName by customName.
RenameOption :: String -> String -> Modifier
-- | RenameOptions f renames all options with the given functions.
-- In case the function returns Nothing the original field name
-- is used.
--
-- Can be used together with stripPrefix.
RenameOptions :: (String -> Maybe String) -> Modifier
-- | UseForPositionalArguments fieldName argumentType fills the
-- field addressed by fieldName with the positional arguments
-- (i.e. arguments that don't correspond to a flag). The field has to
-- have type [String].
--
-- argumentType is used as the type of the positional arguments
-- in the help output.
UseForPositionalArguments :: String -> String -> Modifier
-- | AddOptionHelp fieldName helpText adds a help text for the
-- option fieldName.
AddOptionHelp :: String -> String -> Modifier
-- | AddVersionFlag version adds a --version flag.
AddVersionFlag :: String -> Modifier
-- | Derives AddShortOptions for all fields of the datatype that
-- start with a unique character.
deriveShortOptions :: (HasDatatypeInfo a, SingI (Code a)) => Proxy a -> [Modifier]
-- | Type class for all allowed field types.
--
-- If you want to use custom field types you should implement an
-- instance Option YourCustomType containing implementations of
-- argumentType and parseArgument (the minimal complete
-- definition).
--
-- Here's an example:
--
--
-- {-# LANGUAGE DeriveDataTypeable #-}
--
-- import Data.Typeable
-- import System.Console.GetOpt.Generics
--
-- data File = File FilePath
-- deriving (Show, Typeable)
--
-- instance Option File where
-- argumentType Proxy = "custom-file-type"
-- parseArgument f = Just (File f)
--
-- main :: IO ()
-- main = simpleCLI $ \ file -> do
-- print (file :: File)
--
--
-- This would give you:
--
-- -- $ program some/file -- File "some/file" -- $ program --help -- program [OPTIONS] custom-file-type -- -h --help show help and exit --class Typeable a => Option a where _toOption = ReqArg parseAsFieldState (argumentType (Proxy :: Proxy a)) _emptyOption modifiers flagName = Unset ("missing option: --" ++ mkLongOption modifiers flagName ++ "=" ++ argumentType (Proxy :: Proxy a)) _accumulate _ x = x argumentType :: Option a => Proxy a -> String parseArgument :: Option a => String -> Maybe a -- | The class of representable datatypes. -- -- The SOP approach to generic programming is based on viewing datatypes -- as a representation (Rep) built from the sum of products of its -- components. The components of are datatype are specified using the -- Code type family. -- -- The isomorphism between the original Haskell datatype and its -- representation is witnessed by the methods of this class, from -- and to. So for instances of this class, the following laws -- should (in general) hold: -- --
-- to . from === id :: a -> a -- from . to === id :: Rep a -> Rep a ---- -- You typically don't define instances of this class by hand, but rather -- derive the class instance automatically. -- -- Option 1: Derive via the built-in GHC-generics. For this, you -- need to use the DeriveGeneric extension to first derive an -- instance of the Generic class from module GHC.Generics. -- With this, you can then give an empty instance for Generic, and -- the default definitions will just work. The pattern looks as follows: -- --
-- import qualified GHC.Generics as GHC -- import Generics.SOP -- -- ... -- -- data T = ... deriving (GHC.Generic, ...) -- -- instance Generic T -- empty -- instance HasDatatypeInfo T -- empty, if you want/need metadata ---- -- Option 2: Derive via Template Haskell. For this, you need to -- enable the TemplateHaskell extension. You can then use -- deriveGeneric from module Generics.SOP.TH to have the -- instance generated for you. The pattern looks as follows: -- --
-- import Generics.SOP -- import Generics.SOP.TH -- -- ... -- -- data T = ... -- -- deriveGeneric ''T -- derives HasDatatypeInfo as well ---- -- Tradeoffs: Whether to use Option 1 or 2 is mainly a matter of -- personal taste. The version based on Template Haskell probably has -- less run-time overhead. -- -- Non-standard instances: It is possible to give Generic -- instances manually that deviate from the standard scheme, as long as -- at least -- --
-- to . from === id :: a -> a ---- -- still holds. class (SingI [[*]] (Code a), All [*] (SingI [*]) (Code a)) => Generic a where type family Code a :: [[*]] -- | A class of datatypes that have associated metadata. -- -- It is possible to use the sum-of-products approach to generic -- programming without metadata. If you need metadata in a function, an -- additional constraint on this class is in order. -- -- You typically don't define instances of this class by hand, but rather -- derive the class instance automatically. See the documentation of -- Generic for the options. class HasDatatypeInfo a -- | The code of a datatype. -- -- This is a list of lists of its components. The outer list contains one -- element per constructor. The inner list contains one element per -- constructor argument (field). -- -- Example: The datatype -- --
-- data Tree = Leaf Int | Node Tree Tree ---- -- is supposed to have the following code: -- --
-- type instance Code (Tree a) = -- '[ '[ Int ] -- , '[ Tree, Tree ] -- ] ---- | Require a constraint for every element of a list of lists. -- -- If you have a datatype that is indexed over a type-level list of -- lists, then you can use All2 to indicate that all elements of -- the innert lists must satisfy a given constraint. -- -- Example: The constraint -- --
-- All2 Eq '[ '[ Int ], '[ Bool, Char ] ] ---- -- is equivalent to the constraint -- --
-- (Eq Int, Eq Bool, Eq Char) ---- -- Example: A type signature such as -- --
-- f :: All2 Eq xss => SOP I xs -> ... ---- -- means that f can assume that all elements of the sum of -- product satisfy Eq. -- | Implicit singleton. -- -- A singleton can be used to reveal the structure of a type argument -- that the function is quantified over. -- -- The class SingI should have instances that match the family -- instances for Sing. class SingI (a :: k) -- | A concrete, poly-kinded proxy type data Proxy (t :: k) :: k -> * Proxy :: Proxy