-- Hoogle documentation, generated by Haddock -- See Hoogle, http://www.haskell.org/hoogle/ -- | pattern matching against string based commands -- -- An extensible, format-agnostic command parsing library designed to be -- easy to use and syntactically light weight. -- -- Assuming we write a parser to convert a command such as -- --
-- calculator add 1 2 -v=yes ---- -- Into path and flags such as ["calculator", "add"] and -- Map.fromList [("v","yes")], This library will then match said -- path and flags against a nested record type of commands built up using -- lightweight monadic syntax and tries to execute the associated -- function if the matching and value converting works, or returns an -- error if the path/flags fail to match any command. -- -- To get started, see the documentation for the Commander -- module below. Additionally, an examples folder is included in -- the source illustrating usage - see -- https://github.com/jsdw/hs-commander for more. @package commander @version 0.1.0.0 -- | This module contains the core types and functions for working with -- them. module Commander.Commands -- | This is the type returned from using the commands function -- along with helpers like command and run to build up a -- nested structure of commands. We can manually traverse it by looking -- through the cmdChildren Map to acess nested commands, or -- inspecting the cmdHelp and cmdFunc properties of the -- current command. This makes it easy to do things like autocomplete -- commands, or print out help etc. data Command out Command :: Map String (Command out) -> String -> Maybe (Fn out) -> Command out [cmdChildren] :: Command out -> Map String (Command out) [cmdHelp] :: Command out -> String [cmdFunc] :: Command out -> Maybe (Fn out) -- | You probably won't ever need to interact with this type; it is just a -- State monad on our Command type in order that we can -- use monadic notation to build up our nested structure. type Commands out = State (Command out) -- | A collection of the errors that can be encountered upon trying to get -- and run a Command data CommandError -- | If a parameter's ParamFlags instance returns Just [], -- complain: ErrParamHasNoFlags :: CommandError -- | More input values are provided than the function requires. Provides -- the list of remaining values. ErrTooManyValues :: [String] -> CommandError -- | Not enough input values are provided to the function, so it can't run. ErrNotEnoughValues :: CommandError -- | We didn't find any function with the given path. Provides the possible -- path pieces that could have been supplied to go one level deeper. ErrNotEnoughPath :: [String] -> CommandError -- | We didn't find a path corresponding to some string. Returns the -- possible paths that could have been taken from that location, and the -- failing string. ErrPathNotFound :: [String] -> String -> CommandError -- | We tried converting the flag (provided as the first param) to the type -- asked for, and failed for some reason (provided as the second param). ErrCastingFlag :: String -> String -> CommandError -- | We tried converting some value to the type asked and failed with the -- reason provided. ErrCastingValue :: String -> CommandError -- | Given a Commands type as its only argument, this resolves it to -- a Command object, ready to make use of. This is basically the -- entry point to defining our commands, inside which we can use the -- functions below to populate our structure. commands :: Commands out () -> Command out -- | Nest a command with some name inside the current command. command :: String -> Commands out () -> Commands out () -- | Attach help to the current command. help :: String -> Commands out () -- | Attach a function which will be tried if the current command is -- matched. The parameters to the function must satisfy the -- IsParameter typeclasses, which will automatically make the -- function satisfy the ExtractParameters and -- InjectParameters typeclasses. run :: (ExtractParameters fn out, InjectParameters fn out) => fn -> Commands out () -- | Attempt to run a function inside a Command object, using the -- first argument (a list of strings) to first navigate to the relevant -- subcommand and then have any remainder used as values to be passed to -- the command, and the second argument as a map of flags to be passed to -- the command. evalCommand :: [String] -> Map String String -> Command out -> Either CommandError out -- | Attempt to get hold of the nested Command at the path provided -- inside a provided Command object. getCommand :: [String] -> Command out -> Either CommandError (Command out) -- | A tuple of typeclasses that must all be implemented for function -- parameter types in order that they can be used in the functions -- attached to commands. ToParam is the only mandatory requirement -- (ParamFlags and ParamHelp have default defitions), -- however it is recommended that you implement ParamHelp in all -- cases, and you must implement ParamFlags if you want your new -- type to match against provided flags. An example custom parameter -- implementation: -- --
-- data Verbose = Verbose Bool -- -- instance ParamFlags Verbose where -- paramFlags _ = Just ["v", "verbose"] -- instance ParamHelp Verbose where -- paramHelp _ = "Make the command more verbose" -- instance ToParam Verbose where -- toParam (Just _) = Right (Verbose True) -- toParam Nothing = Right (Verbose False) ---- -- Here, we define a Verbose type that will equal Verbose -- True if the "v" or "verbose" flag is used in the command, or -- Verbose False otherwise. -- -- To extract the value, all we have to do is use (Verbose b) in -- our commands function now, where b will be either -- True or False. -- -- See Params for the definitions of the provided Value -- and Flag parameter types. type IsParameter a = (ToParam a, ParamFlags a, ParamHelp a) -- | Describe how to turn the String parameter given into our -- custom type. The input may be Nothing if the flag/value is -- not provided, else it will be Just str where str is -- the input string. class ToParam a toParam :: ToParam a => Maybe String -> Either String a -- | Should the parameter match against flags? If so, return Just -- [flags] from this. If the param should be a value instead, return -- Nothing. class ParamFlags a where paramFlags _ = Nothing paramFlags :: ParamFlags a => proxy a -> Maybe [String] -- | Return a piece of help text describing what the parameter means. class ParamHelp a where paramHelp _ = "" paramHelp :: ParamHelp a => proxy a -> String -- | Our existential Fn type is used for hiding away the details of -- some provided function. Any function that satisfies the -- IsParameter tuple of type classes can be wrapped in this. data Fn out Fn :: fn -> Fn out -- | given our Fn out type, containing some function that will -- return out on successful execution, attempt to run the -- function by injecting a list of values and a map of flags to it. This -- will either return a CommandError denoting what failed, or the -- output from running the function. injectParams :: [String] -> Map String String -> Fn out -> Either CommandError out -- | Run against our Fn out wrapped function, this will return a -- list of Parameter details for each parameter in the contained -- function. extractParams :: Fn out -> [Parameter] -- | A type containing information about a function parameter. data Parameter Parameter :: Maybe [String] -> String -> Parameter [parameterFlags] :: Parameter -> Maybe [String] [parameterHelp] :: Parameter -> String instance GHC.Show.Show (Commander.Commands.Command out) instance GHC.Show.Show Commander.Commands.CommandError instance GHC.Classes.Eq Commander.Commands.CommandError instance GHC.Classes.Eq Commander.Commands.Parameter instance GHC.Show.Show Commander.Commands.Parameter instance (Commander.Commands.IsParameter a, Commander.Commands.InjectParameters b out) => Commander.Commands.InjectParameters (a -> b) out instance (Commander.Commands.FnOut out ~ out) => Commander.Commands.InjectParameters out out instance (Commander.Commands.IsParameter a, Commander.Commands.ExtractParameters b out) => Commander.Commands.ExtractParameters (a -> b) out instance (Commander.Commands.FnOut out ~ out) => Commander.Commands.ExtractParameters out out instance GHC.Show.Show (Commander.Commands.Fn out) -- | This module provides a couple of basic function parameter types to be -- used in Commands function definitions. By implementing the same -- typeclasses, one can create their own custom types to use instead (or -- as well as) if they prefer. module Commander.Params -- | Use this type in a function embedded in a Command in order to -- require a flag. The type signature for this lists the flags that we -- want to match against, the associated help text, and the output type -- we want the flag to be cast to. -- -- Flags of Maybe or Bool types have special -- handling: if the flag doesnt exist for either of these types, we'll be -- handed back a False/Nothing rather than get an -- error, else if the flag does exist we'll get back a -- True/Just val. Bool flags are expected to -- be provided an empty string as the value; if you care about the value -- but want it to be optional, use Maybe. data Flag (flags :: [Symbol]) (help :: Symbol) a Flag :: a -> Flag a -- | Use this type in a function embedded in a Command in order to -- require a value. The type signature for this contains the associated -- help text for the command, and the type we expect the value to be cast -- to. data Value (help :: Symbol) a Value :: a -> Value a -- | Typeclass used by Flag and Value to convert the provided -- string to the desired haskell type. Anything that satisfies -- Read will satisfy this, but we can override the Read -- behaviour as we see fit on a per type basis by explicitly implementing -- this. class FromString a fromString :: FromString a => String -> Either String a instance Commander.Params.FromString a => Commander.Commands.ToParam (Commander.Params.Flag flags help (GHC.Base.Maybe a)) instance Commander.Commands.ToParam (Commander.Params.Flag flags help GHC.Types.Bool) instance Commander.Params.FromString a => Commander.Commands.ToParam (Commander.Params.Flag flags help a) instance Commander.Params.KnownSymbols flags => Commander.Commands.ParamFlags (Commander.Params.Flag flags help a) instance GHC.TypeLits.KnownSymbol help => Commander.Commands.ParamHelp (Commander.Params.Flag flags help a) instance Commander.Params.FromString a => Commander.Commands.ToParam (Commander.Params.Value help a) instance Commander.Commands.ParamFlags (Commander.Params.Value help a) instance GHC.TypeLits.KnownSymbol help => Commander.Commands.ParamHelp (Commander.Params.Value help a) instance Commander.Params.FromString GHC.Base.String instance GHC.Read.Read a => Commander.Params.FromString a instance (GHC.TypeLits.KnownSymbol s, Commander.Params.KnownSymbols ss) => Commander.Params.KnownSymbols (s : ss) instance Commander.Params.KnownSymbols '[] -- | re-exports everything defined in Commander.Params and -- Commander.Commands for convenience. module Commander