structured-cli 2.3.0.0 → 2.4.0.0
raw patch · 3 files changed
+48/−43 lines, 3 filesPVP ok
version bump matches the API change (PVP)
API changes (from Hackage documentation)
- System.Console.StructuredCLI: instance GHC.Base.Monad m => Data.Default.Class.Default (System.Console.StructuredCLI.Parser m)
- System.Console.StructuredCLI: instance GHC.Base.Monad m => Data.Default.Class.Default (System.Console.StructuredCLI.Validator m)
- System.Console.StructuredCLI: instance GHC.Show.Show System.Console.StructuredCLI.ParseResult
+ System.Console.StructuredCLI: instance GHC.Base.Monad m => Data.Default.Class.Default (System.Console.StructuredCLI.Parser m GHC.Base.String)
+ System.Console.StructuredCLI: instance GHC.Base.Monad m => Data.Default.Class.Default (System.Console.StructuredCLI.Validator m GHC.Base.String)
+ System.Console.StructuredCLI: instance GHC.Show.Show a => GHC.Show.Show (System.Console.StructuredCLI.ParseResult a)
- System.Console.StructuredCLI: Done :: String -> String -> String -> ParseResult
+ System.Console.StructuredCLI: Done :: a -> String -> String -> ParseResult a
- System.Console.StructuredCLI: Fail :: String -> String -> ParseResult
+ System.Console.StructuredCLI: Fail :: String -> String -> ParseResult a
- System.Console.StructuredCLI: NoMatch :: ParseResult
+ System.Console.StructuredCLI: NoMatch :: ParseResult a
- System.Console.StructuredCLI: Partial :: [(String, String)] -> String -> ParseResult
+ System.Console.StructuredCLI: Partial :: [(String, String)] -> String -> ParseResult a
- System.Console.StructuredCLI: [getDoneMatched] :: ParseResult -> String
+ System.Console.StructuredCLI: [getDoneMatched] :: ParseResult a -> String
- System.Console.StructuredCLI: [getDoneRemaining] :: ParseResult -> String
+ System.Console.StructuredCLI: [getDoneRemaining] :: ParseResult a -> String
- System.Console.StructuredCLI: [getFailMessage] :: ParseResult -> String
+ System.Console.StructuredCLI: [getFailMessage] :: ParseResult a -> String
- System.Console.StructuredCLI: [getFailRemaining] :: ParseResult -> String
+ System.Console.StructuredCLI: [getFailRemaining] :: ParseResult a -> String
- System.Console.StructuredCLI: [getOutput] :: ParseResult -> String
+ System.Console.StructuredCLI: [getOutput] :: ParseResult a -> a
- System.Console.StructuredCLI: [getPartialHints] :: ParseResult -> [(String, String)]
+ System.Console.StructuredCLI: [getPartialHints] :: ParseResult a -> [(String, String)]
- System.Console.StructuredCLI: [getPartialRemaining] :: ParseResult -> String
+ System.Console.StructuredCLI: [getPartialRemaining] :: ParseResult a -> String
- System.Console.StructuredCLI: custom :: Monad m => String -> String -> Parser m -> m Bool -> Handler m -> CommandsT m ()
+ System.Console.StructuredCLI: custom :: Monad m => String -> String -> Parser m a -> m Bool -> Handler m a -> CommandsT m ()
- System.Console.StructuredCLI: data ParseResult
+ System.Console.StructuredCLI: data ParseResult a
- System.Console.StructuredCLI: labelParser :: Monad m => Node m -> String -> m ParseResult
+ System.Console.StructuredCLI: labelParser :: Monad m => Node m -> String -> m (ParseResult String)
- System.Console.StructuredCLI: param :: Monad m => String -> String -> Validator m -> Handler m -> CommandsT m ()
+ System.Console.StructuredCLI: param :: Monad m => String -> String -> Validator m a -> Handler m a -> CommandsT m ()
- System.Console.StructuredCLI: param' :: Monad m => String -> String -> Validator m -> m Bool -> Handler m -> CommandsT m ()
+ System.Console.StructuredCLI: param' :: Monad m => String -> String -> Validator m a -> m Bool -> Handler m a -> CommandsT m ()
- System.Console.StructuredCLI: type Handler m = String -> m Action
+ System.Console.StructuredCLI: type Handler m a = a -> m Action
- System.Console.StructuredCLI: type Parser m = Node m -> String -> m ParseResult
+ System.Console.StructuredCLI: type Parser m a = Node m -> String -> m (ParseResult a)
- System.Console.StructuredCLI: type Validator m = String -> m (Maybe String)
+ System.Console.StructuredCLI: type Validator m a = String -> m (Maybe a)
Files
- example/Main.hs +4/−5
- src/System/Console/StructuredCLI.hs +43/−37
- structured-cli.cabal +1/−1
example/Main.hs view
@@ -33,10 +33,9 @@ bar = param "bar" "<number of bars>" parseBars setBars >+ do basic frob- where setBars str = do- let b = read str+ where setBars int = do bars <- gets bars- modify $ \s -> s { bars = bars + b }+ modify $ \s -> s { bars = bars + int } return NewLevel baz :: CommandsT StateM ()@@ -55,8 +54,8 @@ liftIO . putStrLn $ "frobbing " ++ show n ++ " bars" return NoAction -parseBars :: Validator StateM-parseBars = return . fmap show . (readMaybe :: String -> Maybe Int)+parseBars :: Validator StateM Int+parseBars = return . readMaybe main :: IO () main = do
src/System/Console/StructuredCLI.hs view
@@ -1,5 +1,6 @@ {-# LANGUAGE CPP, ImplicitParams,+ ExistentialQuantification, FlexibleContexts, FlexibleInstances, RecordWildCards,@@ -132,7 +133,7 @@ type StateM m = StateT (State m) m -type Handler m = String -> m Action+type Handler m a = a -> m Action -- | An 'Action' is returned as the result of a command handler provided by the user and -- it instructs the CLI of any changes in the CLI state@@ -150,28 +151,29 @@ -- | The 'Node' type contains the internal representation of a command. Normally there is no -- need to be concerned with it other than perhaps passing it opaquely to any utility parsers -- (like 'labelParser' for example), when writing a custom parser-data Node m = Node { getLabel :: String,- getHint :: String,- getBranches :: [Node m],- runParser :: Parser m,- isEnabled :: m Bool,- handle :: Handler m }+data Node m = forall a . Node {+ getLabel :: String,+ getHint :: String,+ getBranches :: [Node m],+ runParser :: Parser m a,+ isEnabled :: m Bool,+ handle :: Handler m a } -type Parser m = Node m -> String -> m ParseResult+type Parser m a = Node m -> String -> m (ParseResult a) -- | A 'Validator' is a function to which a parsed string is given in order to perform -- any checks for validity that may be applicable, or even transforming the argument if -- necessary. Note that the validator runs in the "user" monad-type Validator m = String -> m (Maybe String)+type Validator m a = String -> m (Maybe a) type ExceptionHandler m = CLIException -> m (Either CLIException ()) -- | There is no need to concern oneself with the 'ParseResult' type unless one is writing -- a custom parser, which should actually be rarer than not.-data ParseResult =+data ParseResult a = Done { -- | Output string to be fed to the command action handler- getOutput :: String,+ getOutput :: a, -- | Part of the string matched during parsing of a command getDoneMatched :: String, -- | Remaining input data@@ -264,11 +266,11 @@ instance (MonadIO m) => Default (Settings m) where def = Settings Nothing "" (return " > ") False defExceptionHandler -instance (Monad m) => Default (Parser m) where+instance (Monad m) => Default (Parser m String) where def = labelParser -instance (Monad m) => Default (Validator m) where- def = return . pure . id+instance (Monad m) => Default (Validator m String) where+ def = return . pure type ParserT m = ExceptT CLIException (HL.InputT (StateM m)) @@ -285,7 +287,7 @@ execCommandsT = fmap snd . runCommandsT data SearchResult m = Completed { completedNode :: Node m,- completedOutput :: String,+ completedAction :: m Action, completedMatched :: String, completedRemaining :: String } | Incomplete { incompleteNode :: Node m,@@ -361,10 +363,10 @@ -- | Build a command node that takes one parameter (delimited by space). The parsed parameter -- is fed to the validator monadic function (in the "user" monad) and the resulting string -- if any is fed in turn as an argument to the handler action (also in the "user" monad).-param :: (Monad m) => String -- ^ Command keyword- -> String -- ^ Help text for this command (including argument description)- -> Validator m -- ^ Monadic validator (in the "user" monad)- -> Handler m -- ^ Handling action. Takes the validator output as argument+param :: (Monad m) => String -- ^ Command keyword+ -> String -- ^ Help text for this command (including argument description)+ -> Validator m a -- ^ Monadic validator (in the "user" monad)+ -> Handler m a -- ^ Handling action. Takes the validator output as argument -> CommandsT m () param label hint validator handler = param' label hint validator (return True) handler@@ -372,22 +374,22 @@ -- | A variation of 'param' that allows for "disabling" the command at runtime by -- running the given "enable" monadic action (as always in the "user" monad) to check -- if the command should be displayed as an option and/or accepted or not.-param' :: (Monad m) => String -- ^ Command keyword- -> String -- ^ Help text for this command (including argument description)- -> Validator m -- ^ Monadic validator (in the "user" monad)- -> m Bool -- ^ Enable action in the "user" monad- -> Handler m -- ^ Handling action. Takes the validator output as argument+param' :: (Monad m) => String -- ^ Command keyword+ -> String -- ^ Help text for this command (including argument description)+ -> Validator m a -- ^ Monadic validator (in the "user" monad)+ -> m Bool -- ^ Enable action in the "user" monad+ -> Handler m a -- ^ Handling action. Takes the validator output as argument -> CommandsT m () param' label hint validator enable handler = do custom label hint parser enable handler where parser = paramParser hint validator -- | Create a command using a custom parser, providing thus complete flexibility-custom :: (Monad m) => String -- ^ Command keyword- -> String -- ^ Help text for this command- -> Parser m -- ^ Custom parser (runs in the "user" monad)- -> m Bool -- ^ Enable action in the "user" monad- -> Handler m -- ^ Handling action. Takes the validator output as argument+custom :: (Monad m) => String -- ^ Command keyword+ -> String -- ^ Help text for this command+ -> Parser m a -- ^ Custom parser (runs in the "user" monad)+ -> m Bool -- ^ Enable action in the "user" monad+ -> Handler m a -- ^ Handling action. Takes the validator output as argument -> CommandsT m () custom label hint parser enable handler = do let node = Node { getLabel = label,@@ -416,7 +418,7 @@ -- | A utility parser that reads an input and parses a command label. It can be used as part of -- custom parsers to first read the command keyword before parsing any arguments etc.-labelParser :: (Monad m) => Node m -> String -> m ParseResult+labelParser :: (Monad m) => Node m -> String -> m (ParseResult String) labelParser Node{..} input = do case nextWord input of ("?", remaining) ->@@ -432,7 +434,7 @@ (-.-) :: (b -> c) -> (a -> a1 -> b) -> a -> a1 -> c (-.-) = (.).(.) -paramParser :: (Monad m) => String -> (String -> m (Maybe String)) -> Node m -> String -> m ParseResult+paramParser :: Monad m => String -> (String -> m (Maybe a)) -> Node m -> String -> m (ParseResult a) paramParser hint validator = parseParam -.- labelParser where parseParam = flip (>>=) parseParam' parseParam' (Done _ matched rest) =@@ -444,8 +446,11 @@ (word, remaining) -> do v <- validator word return $ maybe (badArg rest) (\x -> Done x (matched ++ ' ':word) remaining) v- parseParam' result =- return result+ parseParam' (Fail x y) =+ return $ Fail x y+ parseParam' (Partial x y) =+ return $ Partial x y+ parseParam' NoMatch = return NoMatch badArg = Fail hint nextWord :: String -> (String, String)@@ -520,9 +525,10 @@ _ -> return () - where buildPrompt ns = intercalate " " . (: reverse ns) <$> getPrompt ?settings+ where buildPrompt ns = (showStack ns ++) <$> getPrompt ?settings withLabels = fmap fst <$> getStack restore stack = liftStateM . modify $ \s -> s { stack = stack }+ showStack = intercalate " " . reverse getStack :: (Monad m) => ParserT m [Level m] getStack = liftStateM $ gets stack@@ -565,7 +571,7 @@ case result of [Completed{ completedNode=node@Node{..}, ..}] -> do push completedMatched node- action <- liftUserM $ handle completedOutput+ action <- liftUserM completedAction process' completedRemaining node action _ -> if checkForHelp . dropWhile isSpace $ reverse input then do@@ -621,11 +627,11 @@ enabled <- lift isEnabled if enabled then do result <- lift $ runParser node input- debugM $ "ran " ++ getLabel ++ " parser on " ++ show input ++ ": " ++ show result+ debugM $ "ran " ++ getLabel ++ " parser on " ++ show input ++ ": " -- ++ show result case result of Done output matched rest -> return Completed { completedNode = node,- completedOutput = output,+ completedAction = handle output, completedMatched = matched, completedRemaining = rest } Fail msg rest ->
structured-cli.cabal view
@@ -1,5 +1,5 @@ name: structured-cli-version: 2.3.0.0+version: 2.4.0.0 synopsis: Application library for building interactive console CLIs description: This module provides the tools to build a complete "structured" CLI application, similar to those found in systems like Cisco IOS or console configuration utilities etc. It aims to be easy for implementors to use. homepage: https://gitlab.com/codemonkeylabs/structured-cli#readme