System.Console.Repline

repline-0.4.2.0: Haskeline wrapper for GHCi-like REPL interfaces.

Safe Haskell | None
Language | Haskell2010

System.Console.Repline

Contents

- Repline Monad
- Toplevel
- Repline Types
- Completers
- Utilities

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

    options :: Options (HaskelineT IO)
    options = [
        ("help", help . words)  -- :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 (const . pure $ ">>> ") cmd options (Just ':') (Just "paste") (Word completer) ini final

Synopsis

- data HaskelineT (m :: Type -> Type) a
- runHaskelineT :: (MonadMask m, MonadIO m) => Settings m -> HaskelineT m a -> m a
- class MonadCatch m => MonadHaskeline (m :: Type -> Type)
- 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 :: Type -> Type) = 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 :: Type -> Type) = String -> m ()
- type Options (m :: Type -> Type) = [(String, Cmd m)]
- type WordCompleter (m :: Type -> Type) = String -> m [String]
- type LineCompleter (m :: Type -> Type) = String -> String -> m [Completion]
- data CompleterStyle (m :: Type -> Type)
  - = 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 :: Type -> Type) = String -> m ()
- data ExitDecision
  - = Continue
  - | Exit
- data MultiLine
  - = MultiLine
  - | SingleLine
- 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 :: forall (m :: Type -> Type) a. MonadThrow m => HaskelineT m a
- tryAction :: forall (m :: Type -> Type) a. (MonadMask m, MonadIO m) => HaskelineT m a -> HaskelineT m a
- dontCrash :: (MonadIO m, MonadCatch m) => m () -> m ()

# Repline Monad

data HaskelineT (m :: Type -> Type) a #

Monad transformer for readline input

#### Instances

Instances details

MonadTrans HaskelineT # |
Instance details Defined in System.Console.Repline Methods lift :: Monad m => m a -> HaskelineT m a #
MonadReader r m => MonadReader r (HaskelineT m) # |
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 #
MonadState s m => MonadState s (HaskelineT m) # |
Instance details Defined in System.Console.Repline Methods get :: HaskelineT m s # put :: s -> HaskelineT m () # state :: (s -> (a, s)) -> HaskelineT m a #
MonadIO m => MonadIO (HaskelineT m) # |
Instance details Defined in System.Console.Repline Methods liftIO :: IO a -> HaskelineT m a #
MonadCatch m => MonadCatch (HaskelineT m) # |
Instance details Defined in System.Console.Repline Methods catch :: (HasCallStack, Exception e) => HaskelineT m a -> (e -> HaskelineT m a) -> HaskelineT m a #
MonadMask m => MonadMask (HaskelineT m) # |
Instance details Defined in System.Console.Repline Methods mask :: HasCallStack => ((forall a. HaskelineT m a -> HaskelineT m a) -> HaskelineT m b) -> HaskelineT m b # uninterruptibleMask :: HasCallStack => ((forall a. HaskelineT m a -> HaskelineT m a) -> HaskelineT m b) -> HaskelineT m b # generalBracket :: HasCallStack => HaskelineT m a -> (a -> ExitCase b -> HaskelineT m c) -> (a -> HaskelineT m b) -> HaskelineT m (b, c) #
MonadThrow m => MonadThrow (HaskelineT m) # |
Instance details Defined in System.Console.Repline Methods throwM :: (HasCallStack, Exception e) => e -> HaskelineT m a #
Applicative m => Applicative (HaskelineT m) # |
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 #
Functor m => Functor (HaskelineT m) # |
Instance details Defined in System.Console.Repline Methods fmap :: (a -> b) -> HaskelineT m a -> HaskelineT m b # (<$) :: a -> HaskelineT m b -> HaskelineT m a #
Monad m => Monad (HaskelineT m) # |
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 #
MonadFail m => MonadFail (HaskelineT m) # |
Instance details Defined in System.Console.Repline Methods fail :: String -> HaskelineT m a #
MonadFix m => MonadFix (HaskelineT m) # |
Instance details Defined in System.Console.Repline Methods mfix :: (a -> HaskelineT m a) -> HaskelineT m a #
(MonadMask m, MonadIO m) => MonadHaskeline (HaskelineT m) # |
Instance details Defined in System.Console.Repline Methods getInputLine :: String -> HaskelineT m (Maybe String) getInputChar :: String -> HaskelineT m (Maybe Char) outputStr :: String -> HaskelineT m () outputStrLn :: String -> HaskelineT m ()

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

Run HaskelineT monad

class MonadCatch m => MonadHaskeline (m :: Type -> Type) #

Minimal complete definition

getInputLine, getInputChar, outputStr, outputStrLn

#### Instances

Instances details

(MonadMask m, MonadIO m) => MonadHaskeline (InputT m) # |
Instance details Defined in System.Console.Repline Methods getInputLine :: String -> InputT m (Maybe String) getInputChar :: String -> InputT m (Maybe Char) outputStr :: String -> InputT m () outputStrLn :: String -> InputT m ()
(MonadMask m, MonadIO m) => MonadHaskeline (HaskelineT m) # |
Instance details Defined in System.Console.Repline Methods getInputLine :: String -> HaskelineT m (Maybe String) getInputChar :: String -> HaskelineT m (Maybe Char) outputStr :: String -> HaskelineT m () outputStrLn :: String -> HaskelineT m ()
MonadHaskeline m => MonadHaskeline (StateT s m) # |
Instance details Defined in System.Console.Repline Methods getInputLine :: String -> StateT s m (Maybe String) getInputChar :: String -> StateT s m (Maybe Char) outputStr :: String -> StateT s m () outputStrLn :: String -> StateT s m ()

# Toplevel

evalRepl #

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 :: Type -> Type) #

REPL Options datatype

Constructors

ReplOpts |
Fields banner :: MultiLine -> HaskelineT m String Banner command :: Command (HaskelineT m) Command function options :: Options (HaskelineT m) Options list and commands prefix :: Maybe Char Optional command prefix ( passing Nothing ignores the Options argument ) multilineCommand :: Maybe String Optional multi-line command ( passing Nothing disables multi-line support ) tabComplete :: CompleterStyle m Tab completion function initialiser :: HaskelineT m () Initialiser finaliser :: HaskelineT m ExitDecision Finaliser ( runs on Ctrl-D )

evalReplOpts :: (MonadMask m, MonadIO m) => ReplOpts m -> m () #

Evaluate the REPL logic into a MonadCatch context from the ReplOpts configuration.

# Repline Types

type Cmd (m :: Type -> Type) = String -> m () #

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

Options function synonym

type WordCompleter (m :: Type -> Type) = String -> m [String] #

Word completer

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

Line completer

data CompleterStyle (m :: Type -> Type) #

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 :: Type -> Type) = String -> m () #

Command function synonym

data ExitDecision #

Decide whether to exit the REPL or not

Constructors

Continue | Keep the REPL open
Exit | Close the REPL and exit

data MultiLine #

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

Constructors

MultiLine |
SingleLine |

#### Instances

Instances details

Show MultiLine # |
Instance details Defined in System.Console.Repline Methods showsPrec :: Int -> MultiLine -> ShowS # show :: MultiLine -> String # showList :: [MultiLine] -> ShowS #
Eq MultiLine # |
Instance details Defined in System.Console.Repline Methods (==) :: MultiLine -> MultiLine -> Bool # (/=) :: MultiLine -> MultiLine -> Bool #

# 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 #

Word completer function

listCompleter :: Monad m => [String] -> CompletionFunc m #

List completer function

fileCompleter :: MonadIO m => CompletionFunc m #

File completer function

listWordCompleter :: Monad m => [String] -> WordCompleter m #

List word completer

runMatcher :: Monad m => [(String, CompletionFunc m)] -> CompletionFunc m -> CompletionFunc m #

Return a completion function a line fragment

trimComplete :: String -> Completion -> Completion #

Trim completion

# Utilities

abort :: forall (m :: Type -> Type) a. MonadThrow m => HaskelineT m a #

Abort the current REPL loop, and continue.

tryAction :: forall (m :: Type -> Type) a. (MonadMask m, MonadIO m) => HaskelineT m a -> HaskelineT m a #

Wrap a HasklineT action so that if an interrupt is thrown the shell continues as normal.

dontCrash :: (MonadIO m, MonadCatch m) => m () -> m () #

Catch all toplevel failures.