Fast, friendly GHCi
ghcitty is a tiny Rust binary that wraps GHCi with a snappy, delightful frontend

(demo) Tab completion, ghost hints, smart multiline
Show output (records, lists, tuples)At the end of the day, ghcitty is just a modest GHCi frontend w/ a tiny memory footprint to give some niceties to an already formidable, fun and proven REPL.
You just need a GHC and Rust installed
cargo install ghcitty
And use with:
ghcitty
git clone https://github.com/mattlianje/ghcitty.git
cd ghcitty
cargo install --path .
nix profile install github:mattlianje/ghcitty
Run ghcitty from a directory with any of
stack.yml
cabal.project
*.cabal
and it launches via stack ghci or cabal repl (the startup banner shows which)
Pass --plain to force bare ghci
Anything after -- is forwarded verbatim to the underlying invocation uv-style...
ghcitty -- --flag mypkg:dev # stack ghci --flag mypkg:dev
ghcitty -- lib:mylib -O0 # cabal repl lib:mylib -O0
ghcitty --plain -- -package text # ghci -package text
ghcitty Interactive REPL
ghcitty eval "map (+1) [1,2,3]" One-shot eval
ghcitty --json eval "1 + 1" JSON output
ghcitty --session work Named session
ghcitty --continue Restore last session
Multiline is auto-detected. Up/Down to move between lines, blank line to submit.
:{ :} blocks also work as per the usual, with in-buffer navigation.
:hoogle to search by name or type, :doc for Haddock docs.
Vi keybindings. Ctrl+G opens $EDITOR, evals on save.
Edit a loaded file and ghcitty picks up the changes automatically without :r
All GHCi : commands pass through. Extras:
:hoogle <???> Search Hoogle for <???>
:doc <???> Haddock docs for <???> via Hoogle
:/ OR :/<???> Show all bindings OR fuzzy search for <???> binding
:e OR :edit OR <CTRL> + g Open $EDITOR, eval on save
:scratch Open the persistent Scratch.hs in $EDITOR, :load on save (no args)
:undo <N> Undo last <N> expressions
:config List runtime config
:config_<key> [value] Toggle a bool, or set a value (session-only)
~/.ghcitty (key=value) sets the persisted defaults:
pretty_errors = true
pretty_print = true
max_output_lines = 50 # 0 disables
max_output_chars = 3000 # 0 disable
show_timing = false # show eval timing (default: false)
Tweak any of these for the current session with :config_<key>. Bool keys
toggle when called with no argument:
:config_pretty_print
:config_max_output_lines 200
:config_max_output_lines 0
# Show all options...
:config
Why a GHCi wrapper?
First and foremost, for personal use (and frivolous good fun ... to each his own). The precise goal was to have a smooth and aesthetic way to interact with Haskell programs.
It might also be of small use to happy hackers who still program.
How does it work?
:type expr first to capture the type, then the expression itself.: commands pass through. The one exception is :set prompt: ghcitty drives GHCi via a sentinel prompt, so it rejects prompt changes rather than deadlocking.Ctrl+C is forwarded to GHCi via the PTY so a long-running expression aborts instead of killing the REPL.How do the multiline heuristics work?
Basically "automatic" multiline uses a pretty simple and reliable heuristic...
=, do, where, etc, unbalanced brackets, etcBlank line + <RET> submits your expression:{/:} blockHow does completion work?
<TAB> opens a columnar menu using :complete repl with full line context, so :m + Data.Li<Tab> completes module names.:scratch, :config_*, :edit, :undo, :doc, :hoogle) appear in completions and ghost hints too.How does the hoogle integration work?
It tries the local hoogle CLI first, falls back to web API...
How do sessions work?
Every eval is appended to ~/.local/share/ghcitty/<session>.hs. --continue replays on startup.
37 commits
Rust
99.2%
Fast, friendly GHCi
ghcitty is a tiny Rust binary that wraps GHCi with a snappy, delightful frontend

(demo) Tab completion, ghost hints, smart multiline
Show output (records, lists, tuples)At the end of the day, ghcitty is just a modest GHCi frontend w/ a tiny memory footprint to give some niceties to an already formidable, fun and proven REPL.
You just need a GHC and Rust installed
cargo install ghcitty
And use with:
ghcitty
git clone https://github.com/mattlianje/ghcitty.git
cd ghcitty
cargo install --path .
nix profile install github:mattlianje/ghcitty
Run ghcitty from a directory with any of
stack.yml
cabal.project
*.cabal
and it launches via stack ghci or cabal repl (the startup banner shows which)
Pass --plain to force bare ghci
Anything after -- is forwarded verbatim to the underlying invocation uv-style...
ghcitty -- --flag mypkg:dev # stack ghci --flag mypkg:dev
ghcitty -- lib:mylib -O0 # cabal repl lib:mylib -O0
ghcitty --plain -- -package text # ghci -package text
ghcitty Interactive REPL
ghcitty eval "map (+1) [1,2,3]" One-shot eval
ghcitty --json eval "1 + 1" JSON output
ghcitty --session work Named session
ghcitty --continue Restore last session
Multiline is auto-detected. Up/Down to move between lines, blank line to submit.
:{ :} blocks also work as per the usual, with in-buffer navigation.
:hoogle to search by name or type, :doc for Haddock docs.
Vi keybindings. Ctrl+G opens $EDITOR, evals on save.
Edit a loaded file and ghcitty picks up the changes automatically without :r
All GHCi : commands pass through. Extras:
:hoogle <???> Search Hoogle for <???>
:doc <???> Haddock docs for <???> via Hoogle
:/ OR :/<???> Show all bindings OR fuzzy search for <???> binding
:e OR :edit OR <CTRL> + g Open $EDITOR, eval on save
:scratch Open the persistent Scratch.hs in $EDITOR, :load on save (no args)
:undo <N> Undo last <N> expressions
:config List runtime config
:config_<key> [value] Toggle a bool, or set a value (session-only)
~/.ghcitty (key=value) sets the persisted defaults:
pretty_errors = true
pretty_print = true
max_output_lines = 50 # 0 disables
max_output_chars = 3000 # 0 disable
show_timing = false # show eval timing (default: false)
Tweak any of these for the current session with :config_<key>. Bool keys
toggle when called with no argument:
:config_pretty_print
:config_max_output_lines 200
:config_max_output_lines 0
# Show all options...
:config
Why a GHCi wrapper?
First and foremost, for personal use (and frivolous good fun ... to each his own). The precise goal was to have a smooth and aesthetic way to interact with Haskell programs.
It might also be of small use to happy hackers who still program.
How does it work?
:type expr first to capture the type, then the expression itself.: commands pass through. The one exception is :set prompt: ghcitty drives GHCi via a sentinel prompt, so it rejects prompt changes rather than deadlocking.Ctrl+C is forwarded to GHCi via the PTY so a long-running expression aborts instead of killing the REPL.How do the multiline heuristics work?
Basically "automatic" multiline uses a pretty simple and reliable heuristic...
=, do, where, etc, unbalanced brackets, etcBlank line + <RET> submits your expression:{/:} blockHow does completion work?
<TAB> opens a columnar menu using :complete repl with full line context, so :m + Data.Li<Tab> completes module names.:scratch, :config_*, :edit, :undo, :doc, :hoogle) appear in completions and ghost hints too.How does the hoogle integration work?
It tries the local hoogle CLI first, falls back to web API...
How do sessions work?
Every eval is appended to ~/.local/share/ghcitty/<session>.hs. --continue replays on startup.
37 commits
Rust
99.2%