Safe Haskell | None |
---|---|
Language | Haskell2010 |
Provides Commands for REPLs. Commands are there to provide high-level handling of user input and to offer functionality in a standard, composable way.
Use cases:
- Asking the user for input that has to be of the right format or fulfil
specific constraints, such as asking for an
Int
between 0 and 10, or asking for a username that has to exist in some database. - Creating command hierarchies, e.g.
>>>
myVersionControl commit "my first commit" only-binaries
In this example, we could have commit
as a root command that
consumes the commit name "my first commit" and hands over to
the sub-command only-binaries
.
- Creating a REPL out of individual commands. Let us say that we have
a version control system with
commit, revert, diff
commands, plus an exit command like "exit", and one that prints some "command not recognized" message if the user's input doesn't match any commands. We can compose these commands withmakeREPL
, providing robust command selection and obviating the need for manually writing the input handling loop.
Commands can take their input in one line, e.g.
>>>
:cmd param1 "param2 with spaces" param3
or they can ask for missing parameters if so configured:
>>>
:cmd param1 "param2 with spaces"
Please enter param3:
- data Command m i a = Command {
- commandName :: Text
- commandTest :: i -> Bool
- commandDesc :: Text
- runPartialCommand :: [i] -> m (a, [i])
- runCommand :: (Functor m, Monad m, MonadThrow m) => Command m Text a -> Text -> m a
- runSingleCommand :: (MonadThrow m, Functor m) => Command m Text a -> Text -> m a
- oneOf :: Monoid i => Text -> Text -> [Command m i a] -> Command m i a
- subcommand :: (Functor m, Monad m, Monoid i) => Command m i a -> [a -> Command m i b] -> Command m i b
- makeREPL :: (Functor m, MonadIO m, MonadCatch m, Functor f, Foldable f) => [Command m Text a] -> Command m Text b -> Command m Text c -> m Text -> f (Handler m ()) -> m ()
- data SomeCommandError = forall e . Exception e => SomeCommandError e
- data MalformedParamsError = MalformedParamsError Text
- data TooFewParamsError = TooFewParamsError Int Int
- data TooManyParamsError = TooManyParamsError Int Int
- readArgs :: MonadThrow m => Text -> m [Text]
- getName :: (Functor m, MonadThrow m) => Text -> m Text
- quoteArg :: Text -> Text
- summarizeCommands :: MonadIO m => [Command m2 i z] -> m ()
- makeCommand :: (MonadIO m, MonadCatch m, Functor m, Monoid i) => Text -> (i -> Bool) -> Text -> (i -> m z) -> Command m i z
- makeCommand1 :: (MonadIO m, MonadCatch m, Functor m) => Text -> (Text -> Bool) -> Text -> Bool -> Asker m a -> (Text -> a -> m z) -> Command m Text z
- makeCommand2 :: (MonadIO m, MonadCatch m, Functor m) => Text -> (Text -> Bool) -> Text -> Bool -> Asker m a -> Asker m b -> (Text -> a -> b -> m z) -> Command m Text z
- makeCommand3 :: (MonadIO m, MonadCatch m, Functor m) => Text -> (Text -> Bool) -> Text -> Bool -> Asker m a -> Asker m b -> Asker m c -> (Text -> a -> b -> c -> m z) -> Command m Text z
- makeCommand4 :: (MonadIO m, MonadCatch m, Functor m) => Text -> (Text -> Bool) -> Text -> Bool -> Asker m a -> Asker m b -> Asker m c -> Asker m d -> (Text -> a -> b -> c -> d -> m z) -> Command m Text z
- makeCommand5 :: (MonadIO m, MonadCatch m, Functor m) => Text -> (Text -> Bool) -> Text -> Bool -> Asker m a -> Asker m b -> Asker m c -> Asker m d -> Asker m e -> (Text -> a -> b -> c -> d -> e -> m z) -> Command m Text z
- makeCommand6 :: (MonadIO m, MonadCatch m, Functor m) => Text -> (Text -> Bool) -> Text -> Bool -> Asker m a -> Asker m b -> Asker m c -> Asker m d -> Asker m e -> Asker m f -> (Text -> a -> b -> c -> d -> e -> f -> m z) -> Command m Text z
- makeCommand7 :: (MonadIO m, MonadCatch m, Functor m) => Text -> (Text -> Bool) -> Text -> Bool -> Asker m a -> Asker m b -> Asker m c -> Asker m d -> Asker m e -> Asker m f -> Asker m g -> (Text -> a -> b -> c -> d -> e -> f -> g -> m z) -> Command m Text z
- makeCommand8 :: (MonadIO m, MonadCatch m, Functor m) => Text -> (Text -> Bool) -> Text -> Bool -> Asker m a -> Asker m b -> Asker m c -> Asker m d -> Asker m e -> Asker m f -> Asker m g -> Asker m h -> (Text -> a -> b -> c -> d -> e -> f -> g -> h -> m z) -> Command m Text z
- makeCommandN :: (MonadIO m, MonadCatch m, Functor m) => Text -> (Text -> Bool) -> Text -> Bool -> [Asker m a] -> [Asker m a] -> (Text -> [a] -> m z) -> Command m Text z
Command class
A REPL command, possibly with parameters.
Command | |
|
runCommand :: (Functor m, Monad m, MonadThrow m) => Command m Text a -> Text -> m a Source
Runs the command with the input text as parameter, discarding any left-over input.
runSingleCommand :: (MonadThrow m, Functor m) => Command m Text a -> Text -> m a Source
Runs the command with the input text as parameter. If any input is left unconsumed, an error is thrown.
Takes a list xs
and executes the first command in a list whose
commandTest
matches the input.
Note that the resultant command c
s
runPartialCommand
should only be
executed with an input t
if 'commandTest c t' == True', where t'
is either
head (readArgs t)
or mempty
if t
is empty.
Otherwise, the result is undefined.
:: (Functor m, Monad m, Monoid i) | |
=> Command m i a | The root command. |
-> [a -> Command m i b] | The subcommands that may follow it. This list must be finite. |
-> Command m i b |
Adds a list of possible subcommands after a command (that should leave some input unconsumed). Ignoring all the required parameters for a moment,
subcommand x xs = x >>- oneOf xs
:: (Functor m, MonadIO m, MonadCatch m, Functor f, Foldable f) | |
=> [Command m Text a] | The regular commands. |
-> Command m Text b | The "exit" command which terminates the loop. |
-> Command m Text c | The command that is called when none of the others match.
This one's |
-> m Text | The asker to execute before each command (i.e. the prompt). |
-> f (Handler m ()) | Handlers for any exceptions that may arise. Generally, you
will want to handle at least the exceptions of this module
( |
-> m () | Asks the user repeatedly for input, until the input matches the command test of the "exit" command. |
Runs a REPL based on a set of commands. For a line of input, the commands are tried in following order:
- the "exit" command,
- all regular commands, and then
- the "unknown" command.
Exceptions
These are the exceptions that can be thrown during the course of command invocation (in addition to those that you throw yourself, of course).
SomeCommandError is an abstract exception and all others are its concrete subclasses. See the example in Control.Exception for details.
data SomeCommandError Source
Generic error related to command execution.
forall e . Exception e => SomeCommandError e |
data MalformedParamsError Source
The input of a command was malformed and could not interpreted. I.e.
the input contained inadmissible characters, or quotes were mismatched.
The Text
argument contains the parser error.
data TooFewParamsError Source
Too few parameters were given to a command. The first value is the minium, the second the actual number.
data TooManyParamsError Source
Too many parameters were given to a command. The first value is the maximum, the second the actual number.
Dealing with arguments
readArgs :: MonadThrow m => Text -> m [Text] Source
Splits and trims the input of a command. If the input cannot be parsed, a
MalformedCommand
exception is thrown.
- - * Format
Any non-whitespace sequence of characters is interpreted as one argument, unless double quotes (") are used, in which case they demarcate an argument. Each argument is parsed as a haskell string literal (quote-less arguments have quotes inserted around them).
Arguments are parsed using parsec's stringLiteral
(haskell-style),
meaning that escape sequences and unicode characters are handled automatically.
getName :: (Functor m, MonadThrow m) => Text -> m Text Source
Gets the first part of a command string, or the empty string, if the comand string is empty.
quoteArg :: Text -> Text Source
Surrounds an argument in quote marks, if necessary.
This is useful when arguments were extracted via readArgs
, which deletes
quote marks. Quotes are placed around the input iff it is empty or contains
whitespace.
Helpers
summarizeCommands :: MonadIO m => [Command m2 i z] -> m () Source
Prints out a list of command names, with their descriptions.
Making commands
:: (MonadIO m, MonadCatch m, Functor m, Monoid i) | |
=> Text | Command name. |
-> (i -> Bool) | Command test. |
-> Text | Command description. |
-> (i -> m z) | Command function. It will receive the first part of the input (customarily the command name), or the empty string if the input only contained whitespace. |
-> Command m i z |
Creates a command without parameters.
:: (MonadIO m, MonadCatch m, Functor m) | |
=> Text | Command name. |
-> (Text -> Bool) | Command test. |
-> Text | Command description |
-> Bool | Whether the command can ask for input.
^If True, running the command will run the Asker's
IO action if not enough input is provided. If False
a |
-> Asker m a |
|
-> (Text -> a -> m z) | Command function. |
-> Command m Text z |
Creates a command with one parameter.
:: (MonadIO m, MonadCatch m, Functor m) | |
=> Text | Command name. |
-> (Text -> Bool) | Command test. |
-> Text | Command description |
-> Bool | Whether the command can ask for input. |
-> Asker m a |
|
-> Asker m b |
|
-> (Text -> a -> b -> m z) | Command function. |
-> Command m Text z |
Creates a command with two parameters.
:: (MonadIO m, MonadCatch m, Functor m) | |
=> Text | Command name. |
-> (Text -> Bool) | Command test. |
-> Text | Command description |
-> Bool | Whether the command can ask for input. |
-> Asker m a |
|
-> Asker m b |
|
-> Asker m c |
|
-> (Text -> a -> b -> c -> m z) | Command function. |
-> Command m Text z |
Creates a command with three parameters.
:: (MonadIO m, MonadCatch m, Functor m) | |
=> Text | Command name. |
-> (Text -> Bool) | Command test. |
-> Text | Command description |
-> Bool | Whether the command can ask for input. |
-> Asker m a |
|
-> Asker m b |
|
-> Asker m c |
|
-> Asker m d |
|
-> (Text -> a -> b -> c -> d -> m z) | Command function. |
-> Command m Text z |
Creates a command with four parameters.
:: (MonadIO m, MonadCatch m, Functor m) | |
=> Text | Command name. |
-> (Text -> Bool) | Command test. |
-> Text | Command description |
-> Bool | Whether the command can ask for input. |
-> Asker m a |
|
-> Asker m b |
|
-> Asker m c |
|
-> Asker m d |
|
-> Asker m e |
|
-> (Text -> a -> b -> c -> d -> e -> m z) | Command function. |
-> Command m Text z |
Creates a command with five parameters.
:: (MonadIO m, MonadCatch m, Functor m) | |
=> Text | Command name. |
-> (Text -> Bool) | Command test. |
-> Text | Command description |
-> Bool | Whether the command can ask for input. |
-> Asker m a |
|
-> Asker m b |
|
-> Asker m c |
|
-> Asker m d |
|
-> Asker m e |
|
-> Asker m f |
|
-> (Text -> a -> b -> c -> d -> e -> f -> m z) | Command function. |
-> Command m Text z |
Creates a command with six parameters.
:: (MonadIO m, MonadCatch m, Functor m) | |
=> Text | Command name. |
-> (Text -> Bool) | Command test. |
-> Text | Command description |
-> Bool | Whether the command can ask for input. |
-> Asker m a |
|
-> Asker m b |
|
-> Asker m c |
|
-> Asker m d |
|
-> Asker m e |
|
-> Asker m f |
|
-> Asker m g |
|
-> (Text -> a -> b -> c -> d -> e -> f -> g -> m z) | Command function. |
-> Command m Text z |
Creates a command with seven parameters.
:: (MonadIO m, MonadCatch m, Functor m) | |
=> Text | Command name. |
-> (Text -> Bool) | Command test. |
-> Text | Command description |
-> Bool | Whether the command can ask for input. |
-> Asker m a |
|
-> Asker m b |
|
-> Asker m c |
|
-> Asker m d |
|
-> Asker m e |
|
-> Asker m f |
|
-> Asker m g |
|
-> Asker m h |
|
-> (Text -> a -> b -> c -> d -> e -> f -> g -> h -> m z) | Command function. |
-> Command m Text z |
Creates a command with eight parameters.
:: (MonadIO m, MonadCatch m, Functor m) | |
=> Text | Command name. |
-> (Text -> Bool) | Command test. |
-> Text | Command description |
-> Bool | Whether the command can ask for input. This only affects the necessary parameters. |
-> [Asker m a] |
|
-> [Asker m a] |
|
-> (Text -> [a] -> m z) | |
-> Command m Text z |
Creates a command with a list of parameters.
The first list necc
of Asker
s indicates the necessary parameters;
the user must at least provide this many. The second list opt
contains
Asker
s for additional, optional parameters, and may be infinite.
If the number of passed parameters exceeds
length necc + length opt
, or if any Asker
fails,
the command returns an AskFailure
.