repline-0.4.0.0: Haskeline wrapper for GHCi-like REPL interfaces.
Safe HaskellNone
LanguageHaskell2010

System.Console.Repline

Description

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

Repline Monad

data HaskelineT (m :: * -> *) a Source #

Monad transformer for readline input

Instances

Instances details
MonadTrans HaskelineT Source # 
Instance details

Defined in System.Console.Repline

Methods

lift :: Monad m => m a -> HaskelineT m a #

MonadState s m => MonadState s (HaskelineT m) Source # 
Instance details

Defined in System.Console.Repline

Methods

get :: HaskelineT m s #

put :: s -> HaskelineT m () #

state :: (s -> (a, s)) -> HaskelineT m a #

MonadReader r m => MonadReader r (HaskelineT m) Source # 
Instance details

Defined in System.Console.Repline

Methods

ask :: HaskelineT m r #

local :: (r -> r) -> HaskelineT m a -> HaskelineT m a #

reader :: (r -> a) -> HaskelineT m a #

Monad m => Monad (HaskelineT m) Source # 
Instance details

Defined in System.Console.Repline

Methods

(>>=) :: HaskelineT m a -> (a -> HaskelineT m b) -> HaskelineT m b #

(>>) :: HaskelineT m a -> HaskelineT m b -> HaskelineT m b #

return :: a -> HaskelineT m a #

Functor m => Functor (HaskelineT m) Source # 
Instance details

Defined in System.Console.Repline

Methods

fmap :: (a -> b) -> HaskelineT m a -> HaskelineT m b #

(<$) :: a -> HaskelineT m b -> HaskelineT m a #

MonadFix m => MonadFix (HaskelineT m) Source # 
Instance details

Defined in System.Console.Repline

Methods

mfix :: (a -> HaskelineT m a) -> HaskelineT m a #

MonadFail m => MonadFail (HaskelineT m) Source # 
Instance details

Defined in System.Console.Repline

Methods

fail :: String -> HaskelineT m a #

Applicative m => Applicative (HaskelineT m) Source # 
Instance details

Defined in System.Console.Repline

Methods

pure :: a -> HaskelineT m a #

(<*>) :: HaskelineT m (a -> b) -> HaskelineT m a -> HaskelineT m b #

liftA2 :: (a -> b -> c) -> HaskelineT m a -> HaskelineT m b -> HaskelineT m c #

(*>) :: HaskelineT m a -> HaskelineT m b -> HaskelineT m b #

(<*) :: HaskelineT m a -> HaskelineT m b -> HaskelineT m a #

MonadIO m => MonadIO (HaskelineT m) Source # 
Instance details

Defined in System.Console.Repline

Methods

liftIO :: IO a -> HaskelineT m a #

MonadThrow m => MonadThrow (HaskelineT m) Source # 
Instance details

Defined in System.Console.Repline

Methods

throwM :: Exception e => e -> HaskelineT m a #

MonadCatch m => MonadCatch (HaskelineT m) Source # 
Instance details

Defined in System.Console.Repline

Methods

catch :: Exception e => HaskelineT m a -> (e -> HaskelineT m a) -> HaskelineT m a #

MonadMask m => MonadMask (HaskelineT m) Source # 
Instance details

Defined in System.Console.Repline

Methods

mask :: ((forall a. HaskelineT m a -> HaskelineT m a) -> HaskelineT m b) -> HaskelineT m b #

uninterruptibleMask :: ((forall a. HaskelineT m a -> HaskelineT m a) -> HaskelineT m b) -> HaskelineT m b #

generalBracket :: HaskelineT m a -> (a -> ExitCase b -> HaskelineT m c) -> (a -> HaskelineT m b) -> HaskelineT m (b, c) #

runHaskelineT :: (MonadMask m, MonadIO m) => Settings m -> HaskelineT m a -> m a Source #

Run HaskelineT monad

Toplevel

evalRepl Source #

Arguments

:: (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.

data ReplOpts m Source #

REPL Options datatype

Constructors

ReplOpts 

Fields

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 Options m = [(String, Cmd m)] Source #

Options function synonym

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

Constructors

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

type Command m = String -> m () Source #

Command function synonym

data ExitDecision Source #

Decide whether to exit the REPL or not

Constructors

Continue

Keep the REPL open

Exit

Close the REPL and exit

data MultiLine Source #

Context for the current line if it is part of a multi-line input or not

Constructors

MultiLine 
SingleLine 

Instances

Instances details
Eq MultiLine Source # 
Instance details

Defined in System.Console.Repline

Show MultiLine Source # 
Instance details

Defined in System.Console.Repline

Completers

type CompletionFunc (m :: Type -> Type) = (String, String) -> m (String, [Completion]) #

Performs completions from the given line state.

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.

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

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.