• Stars
    star
    107
  • Rank 323,587 (Top 7 %)
  • Language
    Haskell
  • License
    MIT License
  • Created over 10 years ago
  • Updated over 1 year ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

Haskeline wrapper for GHCi-like REPL interfaces

Repline

Build Status Hackage

Slightly higher level wrapper for creating GHCi-like REPL monads that are composable with normal MTL transformers. Mostly exists because I got tired of implementing the same interface for simple shells over and over and decided to canonize the giant pile of hacks that I use to make Haskeline work.

See Documentation for more detailed usage.

Examples

Migration from 0.3.x

This release adds two parameters to the ReplOpts constructor and evalRepl function.

  • finaliser
  • multilineCommand

The finaliser function is a function run when the Repl monad is is exited.

-- | Decide whether to exit the REPL or not
data ExitDecision
  = Continue -- | Keep the REPL open
  | Exit     -- | Close the REPL and exit

For example:

final :: Repl ExitDecision
final = do
  liftIO $ putStrLn "Goodbye!"
  return Exit

The multilineCommand argument takes a command which invokes a multiline edit mode in which the user can paste/enter text across multiple lines terminating with a Ctrl-D / EOF. This can be used in conjunction with a customBanner function to indicate the entry mode.

customBanner :: MultiLine -> Repl String
customBanner SingleLine = pure ">>> "
customBanner MultiLine = pure "| "

See Multiline for a complete example.

Migration from 0.2.x

The underlying haskeline library that provides readline support had a breaking API change in 0.8.0.0 which removed the bespoke System.Console.Haskeline.MonadException module in favour of using the exceptions package. This is a much better design and I strongly encourage upgrading. To migrate simply add the following bounds to your Cabal file.

build-depends:
  repline   >= 0.3.0.0
  haskeline >= 0.8.0.0

You may also need to add the following to your stack.yaml file if using Stack.

resolver: lts-15.0
packages:
  - .
extra-deps:
  - haskeline-0.8.0.0
  - repline-0.3.0.0

Usage

type Repl a = HaskelineT IO a

-- Evaluation : handle each line user inputs
cmd :: String -> Repl ()
cmd input = liftIO $ print input

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

-- Commands
help :: [String] -> Repl ()
help args = liftIO $ print $ "Help: " ++ show args

say :: [String] -> Repl ()
say args = do
  _ <- liftIO $ system $ "cowsay" ++ " " ++ (unwords args)
  return ()

options :: [(String, [String] -> Repl ())]
options = [
    ("help", help)  -- :help
  , ("say", say)    -- :say
  ]

ini :: Repl ()
ini = liftIO $ putStrLn "Welcome!"

repl :: IO ()
repl = evalRepl (pure ">>> ") cmd options Nothing (Word completer) ini

Trying it out:

$ stack repl Simple.hs
Prelude> main

Welcome!
>>> <TAB>
kirk spock mccoy

>>> k<TAB>
kirk

>>> spam
"spam"

>>> :say Hello Haskell
 _______________
< Hello Haskell >
 ---------------
        \   ^__^
         \  (oo)\_______
            (__)\       )\/\
                ||----w |
                ||     ||

Stateful Tab Completion

Quite often tab completion is dependent on the internal state of the Repl so we'd like to query state of the interpreter for tab completions based on actions performed themselves within the Repl, this is modeleted naturally as a monad transformer stack with StateT on top of HaskelineT.

type IState = Set.Set String
type Repl a = HaskelineT (StateT IState IO) a

-- Evaluation
cmd :: String -> Repl ()
cmd input = modify $ \s -> Set.insert input s

-- Completion
comp :: (Monad m, MonadState IState m) => WordCompleter m
comp n = do
  ns <- get
  return  $ filter (isPrefixOf n) (Set.toList ns)

-- Commands
help :: [String] -> Repl ()
help args = liftIO $ print $ "Help!" ++ show args

puts :: [String] -> Repl ()
puts args = modify $ \s -> Set.union s (Set.fromList args)

opts :: [(String, [String] -> Repl ())]
opts = [
    ("help", help) -- :help
  , ("puts", puts) -- :puts
  ]

ini :: Repl ()
ini = return ()

-- Tab completion inside of StateT
repl :: IO ()
repl = flip evalStateT Set.empty
     $ evalRepl (pure ">>> ") cmd opts Nothing (Word comp) ini

Prefix Completion

Just as GHCi will provide different tab completion for kind-level vs type-level symbols based on which prefix the user has entered, we can also set up a provide this as a first-level construct using a Prefix tab completer which takes care of the string matching behind the API.

type Repl a = HaskelineT IO a

-- Evaluation
cmd :: String -> Repl ()
cmd input = liftIO $ print input

-- Prefix tab completeter
defaultMatcher :: MonadIO m => [(String, CompletionFunc m)]
defaultMatcher = [
    (":file"    , fileCompleter)
  , (":holiday" , listCompleter ["christmas", "thanksgiving", "festivus"])
  ]

-- Default tab completer
byWord :: Monad m => WordCompleter m
byWord n = do
  let names = ["picard", "riker", "data", ":file", ":holiday"]
  return $ filter (isPrefixOf n) names

files :: [String] -> Repl ()
files args = liftIO $ do
  contents <- readFile (unwords args)
  putStrLn contents

holidays :: [String] -> Repl ()
holidays [] = liftIO $ putStrLn "Enter a holiday."
holidays xs = liftIO $ do
  putStrLn $ "Happy " ++ unwords xs ++ "!"

opts :: [(String, [String] -> Repl ())]
opts = [
    ("file", files)
  , ("holiday", holidays)
  ]

init :: Repl ()
init = return ()

repl :: IO ()
repl = evalRepl (pure ">>> ") cmd opts Nothing (Prefix (wordCompleter byWord) defaultMatcher) init

Trying it out:

$ stack repl examples/Prefix.hs
Prelude> main

>>> :file <TAB>
sample1.txt sample2.txt

>>> :file sample1.txt

>>> :holiday <TAB>
christmas thanksgiving festivus

License

Copyright (c) 2014-2020, Stephen Diehl Released under the MIT License

More Repositories

1

write-you-a-haskell

Building a modern functional compiler from first principles. (http://dev.stephendiehl.com/fun/)
Haskell
3,347
star
2

wiwinwlh

What I Wish I Knew When Learning Haskell
Haskell
2,565
star
3

kaleidoscope

Haskell LLVM JIT Compiler Tutorial
Haskell
1,029
star
4

bulletproofs

Bulletproofs are short non-interactive zero-knowledge proofs that require no trusted setup
Haskell
535
star
5

numpile

A tiny 1000 line LLVM-based numeric specializer for scientific Python code.
Jupyter Notebook
403
star
6

gevent-tutorial

Gevent tutorial for the Working Python Developer
HTML
382
star
7

wasm

Haskell compiler infastructure for WebAssembly
WebAssembly
358
star
8

tinyjit

Haskell JIT
Haskell
181
star
9

minichat

Minimal realtime chat application ( Tutorial )
Python
132
star
10

kaylee

MapReduce with ZeroMQ
Python
121
star
11

papers

95
star
12

popping-the-crypto-bubble

A no holds barred and unrelenting hatchet job of the crypto community, with all its bad ideas and bad actors put into a historical context of market manias and financial populism.
TeX
91
star
13

dive-into-ghc

Dive into GHC
Haskell
82
star
14

arithmetic-circuits

Arithmetic circuits for zero knowledge proof systems
Haskell
82
star
15

zurihac-crypto

Small minimal examples of modern cryptographic techniques in Haskell
Haskell
79
star
16

schnorr-nizk

Schnorr Protocol for Non-interactive Zero-Knowledge Proofs
Haskell
74
star
17

cabal-edit

A utility for managing Hackage dependencies and manipulating Cabal files from the command line.
Haskell
74
star
18

haskell-vim-proto

Basic starter config for Vim and Haskell
Vim Script
64
star
19

double-ratchet

Double ratchet algorithm for E2E encryption
Haskell
59
star
20

pairing

Optimised bilinear pairings over elliptic curves
Haskell
55
star
21

zeromq-chat

A gevent + Django + Socket.IO + ZeroMQ chat example
Python
53
star
22

galois-field

Finite field and algebraic extension field arithmetic
Haskell
50
star
23

aos-signature

Abe-Ohkubo-Suzuki Linkable Ring Signatures
Haskell
48
star
24

pynanomsg

Python bindings for nanomsg
Python
47
star
25

sonic

Zero-Knowledge SNARKs from Linear-Size Universal and Updatable Structured Reference Strings
Haskell
45
star
26

subpy

Python subsets
Python
41
star
27

elliptic-curve

A polymorphic interface for elliptic curve operations
Haskell
41
star
28

vim-ormolu

Plugin for formatting Haskell source code
Vim Script
39
star
29

llvm-tutorial-standalone

DEPRECATED (Use: https://github.com/llvm-hs/llvm-hs-kaleidoscope )
Haskell
37
star
30

oblivious-transfer

Oblivious transfer for multiparty computation
Haskell
36
star
31

cats

Generate commutative diagrams inside of Pandoc with Tikz
TeX
35
star
32

hakyll-bootstrap

Basic Hakyll + Bootstrap site
HTML
28
star
33

pyrewrite

Python term rewriting
Python
27
star
34

paris-fp

Paris Functional Programming Meetup
Haskell
27
star
35

dotfiles

My config files
Vim Script
24
star
36

llvm-codegen

Code generation utils for LLVM
Haskell
23
star
37

numpush

Shared Memory Numpy ( Deprecated, See https://github.com/ContinuumIO/blaze )
Python
22
star
38

shamir

Shamir Secret Sharing
Haskell
19
star
39

galois-fft

Finite field polynomial arithmetic based on fast Fourier transforms
Haskell
19
star
40

datetime

Financial datetimes and holiday recurrence rules
Haskell
18
star
41

haskell-picosat

Haskell bindings for PicoSAT solver
C
16
star
42

haskell-warp-rest

A Haskell web application using acid-state and scotty
JavaScript
16
star
43

vim-cabalfmt

Cabal-fmt vim plugin for formatting Cabal package files
Vim Script
15
star
44

picologic

Symbolic logic expressions
Haskell
14
star
45

jquery-mathml

Superset of jQuery for working with MathML
JavaScript
12
star
46

cooking-generics

http://www.stephendiehl.com/posts/generics.html
Haskell
12
star
47

print

Simple printing with Text
Haskell
11
star
48

beamer_template

A toolchain to make beautiful Beamer presentations without fussing with LaTeX.
Python
11
star
49

haskell-linenoise

Lightweight readline library for Haskell
C
10
star
50

llvm-pp

A pretty printer for llvm-general-pure. (DEPRECATED: https://github.com/llvm-hs/llvm-hs-pretty/ )
Haskell
7
star
51

gevent_viz

Visualize gevent Greenlet context switches
Python
7
star
52

bnlc

Binary lambda calculus
Python
6
star
53

pycraig

Python library for scraping data from Craigslist
C
6
star
54

commentary

HTML
5
star
55

ts

C
5
star
56

validation

Applicative data validation
Haskell
5
star
57

cfrac

Continued fractions for arithmetic
Haskell
5
star
58

concurrent-timer

Concurrent timer
Haskell
4
star
59

websocket-logger

A in-browser logging console for debugging realtime communication
JavaScript
3
star
60

agents-experiment

Toy language
Haskell
3
star
61

unirewrite

Generic term rewriting
Haskell
3
star
62

tipy

Preprocessor for Python tutorials
Python
3
star
63

equation-editor

A lightweight extensible Javascript equation editor
JavaScript
3
star
64

pretty-latex

Utilities for pretty printing LaTeX from Haskell
Haskell
3
star
65

py-control-flow

Visualize python control flow
Python
3
star
66

pure-python

Cython interface for Pure
C
2
star
67

church-numbers

Lambda Calculus in Python
Python
2
star
68

vector-eigenvalues

C
2
star
69

pymathml

Fork of sourceforge.net/projects/pymathml
Python
1
star
70

rpygtk

A GTK based frontend for R
Python
1
star