Safe Haskell | None |
---|---|
Language | Haskell2010 |
Repline exposes an additional monad transformer on top of Haskeline called HaskelineT
. It simplifies several
aspects of composing Haskeline with State and Exception monads in modern versions of mtl.
type Repl a = HaskelineT IO a
The evaluator evalRepl
evaluates a HaskelineT
monad transformer by constructing a shell with several
custom functions and evaluating it inside of IO:
- Commands: Handled on ordinary input.
- Completions: Handled when tab key is pressed.
- Options: Handled when a command prefixed by a prefix character is entered.
- Command prefix character: Optional command prefix ( passing Nothing ignores the Options argument ).
- Multi-line command: Optional command name that switches to a multi-line input. (Press Ctrl-D to exit and commit the multi-line input). Passing Nothing disables multi-line input support.
- Banner: Text Displayed at initialisation. It takes an argument so it can take into account if the current line is part of a multi-line input.
- Initialiser: Run at initialisation.
- Finaliser: Run on Ctrl-D, it can be used to output a custom exit message or to choose whether to exit or not depending on the application state
A simple evaluation function might simply echo the output back to the screen.
-- Evaluation : handle each line user inputs cmd :: String -> Repl () cmd input = liftIO $ print input
Several tab completion options are available, the most common is the WordCompleter
which completes on single
words separated by spaces from a list of matches. The internal logic can be whatever is required and can also
access a StateT instance to query application state.
-- Tab Completion: return a completion for partial words entered completer :: Monad m => WordCompleter m completer n = do let names = ["kirk", "spock", "mccoy"] return $ filter (isPrefixOf n) names
Input which is prefixed by a colon (commands like ":type" and ":help") queries an association list of
functions which map to custom logic. The function takes a space-separated list of augments in it's first
argument. If the entire line is desired then the unwords
function can be used to concatenate.
-- Commands help :: [String] -> Repl () help args = liftIO $ print $ "Help: " ++ show args say :: [String] -> Repl () say args = do _ <- liftIO $ system $ "cowsay" ++ " " ++ (unwords args) return ()
Now we need only map these functions to their commands.
options :: [(String, [String] -> Repl ())] options = [ ("help", help) -- :help , ("say", say) -- :say ]
The initialiser function is simply an IO action that is called at the start of the shell.
ini :: Repl () ini = liftIO $ putStrLn "Welcome!"
The finaliser function is an IO action that is called at the end of the shell.
final :: Repl ExitDecision final = do liftIO $ putStrLn "Goodbye!" return Exit
Putting it all together we have a little shell.
main :: IO () main = evalRepl (pure ">>> ") cmd options (Just ':') (Word completer) ini
Alternatively instead of initialising the repl from position arguments you
can pass the ReplOpts
record with explicitly named arguments.
main_alt :: IO () main_alt = evalReplOpts $ ReplOpts { banner = const (pure ">>> ") , command = cmd , options = opts , prefix = Just ':' , multilineCommand = Nothing , tabComplete = (Word0 completer) , initialiser = ini , finaliser = final }
Putting this in a file we can test out our cow-trek shell.
$ runhaskell Main.hs Welcome! >>> <TAB> kirk spock mccoy >>> k<TAB> kirk >>> spam "spam" >>> :say Hello Haskell _______________ < Hello Haskell > --------------- \ ^__^ \ (oo)\_______ (__)\ )\/\ ||----w | || ||
See https://github.com/sdiehl/repline for more examples.
Synopsis
- data HaskelineT (m :: * -> *) a
- runHaskelineT :: (MonadMask m, MonadIO m) => Settings m -> HaskelineT m a -> m a
- evalRepl :: (MonadMask m, MonadIO m) => (MultiLine -> HaskelineT m String) -> Command (HaskelineT m) -> Options (HaskelineT m) -> Maybe Char -> Maybe String -> CompleterStyle m -> HaskelineT m a -> HaskelineT m ExitDecision -> m ()
- data ReplOpts m = ReplOpts {
- banner :: MultiLine -> HaskelineT m String
- command :: Command (HaskelineT m)
- options :: Options (HaskelineT m)
- prefix :: Maybe Char
- multilineCommand :: Maybe String
- tabComplete :: CompleterStyle m
- initialiser :: HaskelineT m ()
- finaliser :: HaskelineT m ExitDecision
- evalReplOpts :: (MonadMask m, MonadIO m) => ReplOpts m -> m ()
- type Cmd m = String -> m ()
- type Options m = [(String, Cmd m)]
- type WordCompleter m = String -> m [String]
- type LineCompleter m = String -> String -> m [Completion]
- data CompleterStyle m
- = Word (WordCompleter m)
- | Word0 (WordCompleter m)
- | Cursor (LineCompleter m)
- | File
- | Prefix (CompletionFunc m) [(String, CompletionFunc m)]
- | Combine (CompleterStyle m) (CompleterStyle m)
- | Custom (CompletionFunc m)
- type Command m = String -> m ()
- data ExitDecision
- data MultiLine
- type CompletionFunc (m :: Type -> Type) = (String, String) -> m (String, [Completion])
- fallbackCompletion :: Monad m => CompletionFunc m -> CompletionFunc m -> CompletionFunc m
- wordCompleter :: Monad m => WordCompleter m -> CompletionFunc m
- listCompleter :: Monad m => [String] -> CompletionFunc m
- fileCompleter :: MonadIO m => CompletionFunc m
- listWordCompleter :: Monad m => [String] -> WordCompleter m
- runMatcher :: Monad m => [(String, CompletionFunc m)] -> CompletionFunc m -> CompletionFunc m
- trimComplete :: String -> Completion -> Completion
- abort :: MonadThrow m => HaskelineT m a
- tryAction :: (MonadMask m, MonadIO m) => HaskelineT m a -> HaskelineT m a
- dontCrash :: (MonadIO m, MonadCatch m) => m () -> m ()
Repline Monad
data HaskelineT (m :: * -> *) a Source #
Monad transformer for readline input
Instances
runHaskelineT :: (MonadMask m, MonadIO m) => Settings m -> HaskelineT m a -> m a Source #
Run HaskelineT monad
Toplevel
:: (MonadMask m, MonadIO m) | |
=> (MultiLine -> HaskelineT m String) | Banner |
-> Command (HaskelineT m) | Command function |
-> Options (HaskelineT m) | Options list and commands |
-> Maybe Char | Optional command prefix ( passing Nothing ignores the Options argument ) |
-> Maybe String | Optional multi-line command ( passing Nothing disables multi-line support ) |
-> CompleterStyle m | Tab completion function |
-> HaskelineT m a | Initialiser |
-> HaskelineT m ExitDecision | Finaliser ( runs on Ctrl-D ) |
-> m () |
Evaluate the REPL logic into a MonadCatch context.
REPL Options datatype
ReplOpts | |
|
evalReplOpts :: (MonadMask m, MonadIO m) => ReplOpts m -> m () Source #
Evaluate the REPL logic into a MonadCatch context from the ReplOpts configuration.
Repline Types
type Cmd m = String -> m () Source #
Command function synonym
The argument corresponds to the arguments of the command, it may contain spaces or newlines (when input is multi-line).
For example, with prefix
and command :
"command"
the argument String
for:
:command some arguments
is "some arguments"
type WordCompleter m = String -> m [String] Source #
Word completer
type LineCompleter m = String -> String -> m [Completion] Source #
Line completer
data CompleterStyle m Source #
Tab completer types
Word (WordCompleter m) | Completion function takes single word. |
Word0 (WordCompleter m) | Completion function takes single word ( no space ). |
Cursor (LineCompleter m) | Completion function takes tuple of full line. |
File | Completion function completes files in CWD. |
Prefix (CompletionFunc m) [(String, CompletionFunc m)] | Conditional tab completion based on prefix. |
Combine (CompleterStyle m) (CompleterStyle m) | Combine two completions |
Custom (CompletionFunc m) | Custom completion |
data ExitDecision Source #
Decide whether to exit the REPL or not
Context for the current line if it is part of a multi-line input or not
Instances
Completers
type CompletionFunc (m :: Type -> Type) = (String, String) -> m (String, [Completion]) #
fallbackCompletion :: Monad m => CompletionFunc m -> CompletionFunc m -> CompletionFunc m #
If the first completer produces no suggestions, fallback to the second completer's output.
wordCompleter :: Monad m => WordCompleter m -> CompletionFunc m Source #
Word completer function
listCompleter :: Monad m => [String] -> CompletionFunc m Source #
List completer function
fileCompleter :: MonadIO m => CompletionFunc m Source #
File completer function
listWordCompleter :: Monad m => [String] -> WordCompleter m Source #
List word completer
runMatcher :: Monad m => [(String, CompletionFunc m)] -> CompletionFunc m -> CompletionFunc m Source #
Return a completion function a line fragment
trimComplete :: String -> Completion -> Completion Source #
Trim completion
Utilities
abort :: MonadThrow m => HaskelineT m a Source #
Abort the current REPL loop, and continue.
tryAction :: (MonadMask m, MonadIO m) => HaskelineT m a -> HaskelineT m a Source #
Wrap a HasklineT action so that if an interrupt is thrown the shell continues as normal.
dontCrash :: (MonadIO m, MonadCatch m) => m () -> m () Source #
Catch all toplevel failures.