cmdlib 0.2.1 → 0.3
raw patch · 4 files changed
+103/−35 lines, 4 filesdep ~basePVP ok
version bump matches the API change (PVP)
Dependency ranges changed: base
API changes (from Hackage documentation)
- System.Console.CmdLib: RecordMode :: String -> Constr -> RecordMode cmd
- System.Console.CmdLib: data RecordMode cmd
- System.Console.CmdLib: rec_cmdname :: RecordMode cmd -> String
- System.Console.CmdLib: rec_initial :: RecordMode cmd -> Constr
+ System.Console.CmdLib: commandNames :: Bool -> [CommandWrap] -> [String]
+ System.Console.CmdLib: data CommandWrap
+ System.Console.CmdLib: dispatchOr :: (String -> IO ()) -> [DispatchOpt] -> [CommandWrap] -> [String] -> IO ()
+ System.Console.CmdLib: mode_help :: RecordCommand cmd => cmd -> String
- System.Console.CmdLib: (<%) :: (Keys keys) => Attribute -> keys -> AttributeMap Key
+ System.Console.CmdLib: (<%) :: Keys keys => Attribute -> keys -> AttributeMap Key
- System.Console.CmdLib: attributes :: (Attributes a) => a -> AttributeMap Key
+ System.Console.CmdLib: attributes :: Attributes a => a -> AttributeMap Key
- System.Console.CmdLib: class (Typeable a) => Data a
+ System.Console.CmdLib: class Typeable a => Data a
- System.Console.CmdLib: class (Data cmd) => RecordCommand cmd
+ System.Console.CmdLib: class Data cmd => RecordCommand cmd
- System.Console.CmdLib: cmd :: (Command cmd flag) => cmd
+ System.Console.CmdLib: cmd :: Command cmd flag => cmd
- System.Console.CmdLib: cmd_flag_empty :: (Command cmd flag) => cmd -> Folded flag
+ System.Console.CmdLib: cmd_flag_empty :: Command cmd flag => cmd -> Folded flag
- System.Console.CmdLib: cmdname :: (Command cmd flag) => cmd -> String
+ System.Console.CmdLib: cmdname :: Command cmd flag => cmd -> String
- System.Console.CmdLib: commandGroup :: (Commands a) => String -> a -> [CommandWrap]
+ System.Console.CmdLib: commandGroup :: Commands a => String -> a -> [CommandWrap]
- System.Console.CmdLib: data (Attributes adt) => ADT adt
+ System.Console.CmdLib: data Attributes adt => ADT adt
- System.Console.CmdLib: data (Attributes rec) => Record rec
+ System.Console.CmdLib: data Attributes rec => Record rec
- System.Console.CmdLib: dispatchR :: (Eq (Record cmd), Attributes cmd, RecordCommand cmd, Command (RecordMode cmd) f, (Folded f) ~ cmd) => [DispatchOpt] -> cmd -> [String] -> IO cmd
+ System.Console.CmdLib: dispatchR :: (Eq cmd, Eq (Record cmd), Attributes cmd, RecordCommand cmd, Command (RecordMode cmd) f, (Folded f) ~ cmd) => [DispatchOpt] -> [String] -> IO cmd
- System.Console.CmdLib: everywhere :: (Eq k) => Attribute -> AttributeMap k
+ System.Console.CmdLib: everywhere :: Eq k => Attribute -> AttributeMap k
- System.Console.CmdLib: execute :: (Command cmd f) => cmd -> [String] -> IO ()
+ System.Console.CmdLib: execute :: Command cmd f => cmd -> [String] -> IO ()
- System.Console.CmdLib: executeR :: (Eq (Record cmd), Attributes cmd, RecordCommand cmd) => cmd -> [String] -> IO cmd
+ System.Console.CmdLib: executeR :: (Eq cmd, Eq (Record cmd), Attributes cmd, RecordCommand cmd) => cmd -> [String] -> IO cmd
- System.Console.CmdLib: globalFlag :: a -> (a -> IO (), IO a)
+ System.Console.CmdLib: globalFlag :: Typeable a => a -> (a -> IO (), IO a)
- System.Console.CmdLib: group :: (AttributeMapLike k a) => String -> a -> AttributeMap k
+ System.Console.CmdLib: group :: AttributeMapLike k a => String -> a -> AttributeMap k
- System.Console.CmdLib: help :: (Command cmd flag) => cmd -> String
+ System.Console.CmdLib: help :: Command cmd flag => cmd -> String
- System.Console.CmdLib: helpOptions :: (Command cmd f) => cmd -> String
+ System.Console.CmdLib: helpOptions :: Command cmd f => cmd -> String
- System.Console.CmdLib: mode_summary :: (RecordCommand cmd) => cmd -> String
+ System.Console.CmdLib: mode_summary :: RecordCommand cmd => cmd -> String
- System.Console.CmdLib: optionStyle :: (Command cmd flag) => cmd -> OptionStyle
+ System.Console.CmdLib: optionStyle :: Command cmd flag => cmd -> OptionStyle
- System.Console.CmdLib: options :: (Command cmd flag) => cmd -> AttributeMap Key
+ System.Console.CmdLib: options :: Command cmd flag => cmd -> AttributeMap Key
- System.Console.CmdLib: readCommon :: (Data a) => String -> a
+ System.Console.CmdLib: readCommon :: Data a => String -> a
- System.Console.CmdLib: rec_options :: (RecordCommand cmd) => cmd -> AttributeMap Key
+ System.Console.CmdLib: rec_options :: RecordCommand cmd => cmd -> AttributeMap Key
- System.Console.CmdLib: recordCommands :: (Eq (Record cmd), Data cmd, RecordCommand cmd, Attributes cmd) => cmd -> [CommandWrap]
+ System.Console.CmdLib: recordCommands :: (Eq cmd, Eq (Record cmd), Data cmd, RecordCommand cmd, Attributes cmd) => cmd -> [CommandWrap]
- System.Console.CmdLib: run :: (Command cmd flag) => cmd -> Folded flag -> [String] -> IO ()
+ System.Console.CmdLib: run :: Command cmd flag => cmd -> Folded flag -> [String] -> IO ()
- System.Console.CmdLib: run' :: (RecordCommand cmd) => cmd -> [String] -> IO ()
+ System.Console.CmdLib: run' :: RecordCommand cmd => cmd -> [String] -> IO ()
- System.Console.CmdLib: summary :: (Command cmd flag) => cmd -> String
+ System.Console.CmdLib: summary :: Command cmd flag => cmd -> String
- System.Console.CmdLib: supercommand :: (Command cmd flag) => cmd -> Bool
+ System.Console.CmdLib: supercommand :: Command cmd flag => cmd -> Bool
- System.Console.CmdLib: synopsis :: (Command cmd flag) => cmd -> String
+ System.Console.CmdLib: synopsis :: Command cmd flag => cmd -> String
Files
- System/Console/CmdLib.hs +19/−11
- System/Console/CmdLib/Command.hs +23/−5
- System/Console/CmdLib/Record.hs +35/−11
- cmdlib.cabal +26/−8
System/Console/CmdLib.hs view
@@ -44,6 +44,14 @@ module System.Console.CmdLib ( -- * News --+ -- | Since version 0.3: "dispatchR" no longer takes a cmd argument, as it was+ -- never used for anything and was simply confusing. A new function,+ -- "dispatchOr" has been added to allow the program to continue despite+ -- otherwise fatal errors (unknown command, unknown flags). New function,+ -- "commandNames", has been added, to go from [CommandWrap] to [String]. The+ -- "CommandWrap" type is now exported (opaque). The "RecordCommand" class+ -- now has a mode_help method. "RecordMode" is no longer exported.+ -- -- | Since version 0.2: The Positional arguments are no longer required to be -- strings. A default (fallback) command may be provided to -- "dispatch"/"dispatchR" (this has also incompatibly changed their@@ -66,21 +74,21 @@ -- | Flags (commandline options) can be represented in two basic styles, -- either as a plain ADT (algebraic data type) or as a record type. These two- -- styles are implemented using "ADTFlag" and "ADT" for the former and- -- "RecordFlag" and "Record" for the latter. The *Flag classes can be used to- -- attach attributes to flags and to override the parser for option- -- arguments. However, an empty instance is valid for both cases. The "ADT"- -- and "Record" newtype wrappers are then used in a "Command" or- -- "RecordCommand" instance declaration.+ -- styles are implemented using the "ADT" wrapper for the former and and a+ -- "Record" wrapper for the latter. You need to make your type an instance of+ -- the "Attributes" class, which can be used to attach attributes to the+ -- flags. , ADT, Record, Attributes(..) -- * Commands- , (%:), commandGroup, Command(..), dispatch, execute, helpCommands, helpOptions+ , (%:), commandGroup, Command(..), dispatch, dispatchOr, execute, helpCommands, helpOptions , noHelp, defaultCommand, OptionStyle(..)+ , CommandWrap -- just the type (for signatures in users code)+ , commandNames -- * Record-based commands- , RecordCommand(..), RecordMode(..), recordCommands, dispatchR, executeR+ , RecordCommand(..), recordCommands, dispatchR, executeR -- * Utilities , globalFlag, readCommon, (<+<), HelpCommand(..), die@@ -109,11 +117,11 @@ -- > data Flag = Wibblify Int | Verbose Bool -- > (setVerbose, isVerbose) = globalFlag False -- >--- > instance ADTFlag Flag where--- > adt_attrs _ = Verbose %> Global setVerbose+-- > instance Attributes Flag where+-- > attributes _ = Verbose %> Global setVerbose -- > -- > putVerbose str = isVerbose >>= flip when (putStrLn str)-globalFlag :: a -> (a -> IO (), IO a)+globalFlag :: Typeable a => a -> (a -> IO (), IO a) globalFlag def = unsafePerformIO $ do ref <- newIORef def return (writeIORef ref, readIORef ref) {-# NOINLINE globalFlag #-}
System/Console/CmdLib/Command.hs view
@@ -114,6 +114,16 @@ one (CommandGroup name l) = "\n" ++ name ++ ":\n" ++ helpCommands l pad str = (take 15 $ str ++ replicate 15 ' ') ++ " " +-- | This could be used to implement a disambiguation function+--+-- Note that there isn't presently a notion of hidden commands,+-- but we're taking them into account now for future API stability+commandNames :: Bool -- ^ show hidden commands too+ -> [CommandWrap] -> [String]+commandNames _ x = concatMap one x+ where one (CommandWrap c) = [cmdname c]+ one (CommandGroup _ cs) = concatMap one cs+ execute' :: forall cmd f. (Command cmd f) => cmd -> [String] -> IO (Maybe (Folded f, [String])) execute' cmd opts | "--help" `elem` opts && not (supercommand cmd) = printHelp cmd >> return Nothing@@ -191,11 +201,12 @@ printHelp c = putStr $ helpOptions c printCommands comms = putStr $ helpCommands comms -dispatch' :: [DispatchOpt] -> [CommandWrap] -> [String] -> IO (Maybe (CommandWrap, [String]))-dispatch' dopt comms' args = case args of+dispatch' :: (String -> IO ()) -- ^ fail+ -> [DispatchOpt] -> [CommandWrap] -> [String] -> IO (Maybe (CommandWrap, [String]))+dispatch' diefn dopt comms' args = case args of [] | isNothing def -> dieHelp "Command required." | otherwise -> return $ Just (fromJust def, [])- ("--help":_) -> printCommands comms >> return Nothing+ ("--help":x) -> dispatch' diefn dopt comms' ("help":x) (cmd:args') -> case findCommand cmd comms of Nothing -> case def of Nothing -> dieHelp $ "No such command " ++ cmd@@ -203,7 +214,7 @@ Just x -> return $ Just (x, args') where comms | null [ () | NoHelp <- dopt ] = HelpCommand comms %: comms' | otherwise = comms'- dieHelp msg = printCommands comms >> die msg >> return Nothing+ dieHelp msg = printCommands comms >> diefn msg >> return Nothing def | (DefaultCommand n:_) <- [ o | o@(DefaultCommand _) <- dopt ] = Just n | otherwise = Nothing @@ -217,9 +228,16 @@ -- and transfer control to the command. This function also implements the -- @help@ pseudocommand. dispatch :: [DispatchOpt] -> [CommandWrap] -> [String] -> IO ()-dispatch dopt comms opts = dispatch' dopt comms opts >>= \c -> case c of+dispatch = dispatchOr die++-- | Like 'dispatch' but with the ability to control what happens when there+-- is an error on user input+dispatchOr :: (String -> IO ()) -- ^ eg. 'die'+ -> [DispatchOpt] -> [CommandWrap] -> [String] -> IO ()+dispatchOr die dopt comms opts = dispatch' die dopt comms opts >>= \c -> case c of Nothing -> return () Just (CommandWrap c, opts') -> execute c opts'+ -- | Helper for dying with an error message (nicely, at least compared to -- "fail" in IO).
System/Console/CmdLib/Record.hs view
@@ -38,7 +38,7 @@ -- TODO: List-based option types should be accumulated instead of overriden. data (Attributes rec) => Record rec = Record rec String deriving Eq -instance (Eq (Record rec), Data rec, Attributes rec) => FlagType (Record rec) where+instance (Eq rec, Eq (Record rec), Data rec, Attributes rec) => FlagType (Record rec) where type Folded (Record rec) = rec flag_attrkey (Record _ f) = KeyF (typeOf (undefined :: rec)) f@@ -68,7 +68,8 @@ flag_value (Record _ field) folded = getField field folded flag_set (Record _ field) v = \x -> setField field x (errcast v)- where errcast x = case cast x of+ where errcast :: (Typeable a, Typeable b) => a -> b+ errcast x = case cast x of Just x -> x Nothing -> error "BUG: flag_set in Record used with wrong value type" @@ -112,21 +113,26 @@ rec_options :: cmd -> AttributeMap Key rec_options _ = EmptyMap - -- | Provide a help string for each mode. Used in help output. Again, pattern- -- match like in @run'@.+ -- | Provide a summary help string for each mode. Used in help output. Again,+ -- pattern match like in @run'@. mode_summary :: cmd -> String mode_summary _ = "" + -- | Provide a help blurb for each mode. Use patterns like in @run'@.+ mode_help :: cmd -> String+ mode_help _ = ""+ data RecordMode cmd = RecordMode { rec_cmdname :: String , rec_initial :: Constr } deriving (Typeable) -instance (Eq (Record cmd), RecordCommand cmd, Data cmd, Attributes cmd)+instance (Eq cmd, Eq (Record cmd), RecordCommand cmd, Data cmd, Attributes cmd) => Command (RecordMode cmd) (Record cmd) where cmdname = rec_cmdname run _ = run' summary cmd = mode_summary $ (fromConstr $ rec_initial cmd :: cmd)+ help cmd = mode_help $ (fromConstr $ rec_initial cmd :: cmd) options cmd = rec_options ctor %% available %% everywhere disable where available = [ (KeyF (typeOf (undefined :: cmd)) opt, [enable])@@ -136,8 +142,10 @@ cmd_flag_empty cmd = fromConstr $ rec_initial cmd -- | Construct a command list (for "dispatch"/"helpCommands") from a--- multi-constructor record data type. See also "RecordCommand".-recordCommands :: forall cmd. (Eq (Record cmd), Data cmd, RecordCommand cmd, Attributes cmd) => cmd -> [CommandWrap]+-- multi-constructor record data type. See also "RecordCommand". Alternatively,+-- you can use "dispatchR" directly.+recordCommands :: forall cmd. (Eq cmd, Eq (Record cmd), Data cmd, RecordCommand cmd, Attributes cmd)+ => cmd -> [CommandWrap] recordCommands _ = go $ dataTypeConstrs $ dataTypeOf (undefined :: cmd) where go = map $ CommandWrap . rec_cmd rec_cmd :: Constr -> RecordMode cmd@@ -166,10 +174,16 @@ errcast :: forall a b. (Typeable a, Typeable b) => a -> b errcast = fromMaybe (error $ "BUG: getField used with wrong type on " ++ field) . cast -dispatchR :: forall cmd f. (Eq (Record cmd), Attributes cmd, RecordCommand cmd,+-- | A command parsing & dispatch entry point for record-based+-- commands. Ex. (see "RecordCommand"):+--+-- > main = getArgs >>= dispatchR [] >>= \x -> case x of+-- > Foo {} -> putStrLn $ "You asked for foo. Wibble = " ++ show (wibble x)+-- > Bar {} -> putStrLn $ "You asked for bar. ..."+dispatchR :: forall cmd f. (Eq cmd, Eq (Record cmd), Attributes cmd, RecordCommand cmd, Command (RecordMode cmd) f,- Folded f ~ cmd) => [DispatchOpt] -> cmd -> [String] -> IO cmd-dispatchR dopt _ opts = dispatch' dopt (recordCommands (undefined :: cmd)) opts >>= \c -> case c of+ Folded f ~ cmd) => [DispatchOpt] -> [String] -> IO cmd+dispatchR dopt opts = dispatch' die dopt (recordCommands (undefined :: cmd)) opts >>= \c -> case c of Nothing -> exitWith ExitSuccess >> return undefined Just (CommandWrap x, opts') -> execute' x opts' >>= \c -> case c of Just (command, opts') -> case (cast command) of@@ -177,7 +191,17 @@ Nothing -> execute x opts' >> exitWith ExitSuccess >> return undefined Nothing -> exitWith ExitSuccess >> return undefined -executeR :: forall cmd. (Eq (Record cmd), Attributes cmd, RecordCommand cmd) => cmd -> [String] -> IO cmd+-- | Like "execute", but you get the flags as a return value. This is useful to+-- implement non-modal applications with record-based flags, eg.:+--+-- > data Main = Main { greeting :: String, again :: Bool }+-- > deriving (Typeable, Data, Eq)+-- > instance Attributes Main where -- (...)+-- > instance RecordCommand Main+-- > main = getArgs >>= executeR Main {} >>= \opts -> do+-- > putStrLn (greeting opts) -- (...)+executeR :: forall cmd. (Eq cmd, Eq (Record cmd), Attributes cmd, RecordCommand cmd)+ => cmd -> [String] -> IO cmd executeR cmd opts = execute' cmd' opts >>= \c -> case c of Just (command, _) -> return command Nothing -> exitWith ExitSuccess >> return undefined
cmdlib.cabal view
@@ -1,12 +1,30 @@-name: cmdlib-version: 0.2.1-synopsis: a library for command line parsing & online help+name: cmdlib+version: 0.3+synopsis: a library for command line parsing & online help -description: An alternative to cmdargs, based on getopt. Comes with a powerful- attribute system. Supports complex interfaces with many options- and commands, with option & command grouping, while at the same- time keeping simple things simple.+description: A commandline parsing library, based on getopt. Comes with a+ powerful attribute system. Supports complex interfaces with many+ options and commands, with option & command grouping, with simple+ and convenient API. Even though quite powerful, it strives to keep+ simple things simple. The library uses "System.Console.GetOpt" as+ its backend.+ .+ In comparison to the other commandline handling libraries:+ .+ Compared to cmdargs, cmdlib has a pure attribute system and is+ based on GetOpt for help formatting & argument parsing. Cmdlib may+ also be more extendable due to typeclass design, and can use+ user-supplied types for option arguments.+ .+ Cmdargs >= 0.4 can optionally use a pure attribute system,+ although this is clearly an add-on and the API is a second-class+ citizen in relation to the impure version.+ .+ GetOpt and parseargs both require explicit flag representation, so+ they live a level below cmdlib. GetOpt is in fact used as a+ backend by cmdlib. + -- The license under which the package is released. -- copyright: license: BSD3@@ -35,7 +53,7 @@ System.Console.CmdLib.ADTs System.Console.CmdLib.Record - build-depends: base < 5, syb, mtl, split+ build-depends: base >= 4 && < 5, syb, mtl, split flag test default: False