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.
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 arg = do
_ <- liftIO $ callCommand $ "cowsay" ++ " " ++ arg
return ()
(You may need the following import in pull callCommand into scope)
import System.Process (callCommand)
Now we need only map these functions to their commands.
The first String argument is the contents of the line to the left of the cursor,
reversed.
The second String argument is the contents of the line to the right of the cursor.
The output String is the unused portion of the left half of the line, reversed.