part of
c6
# ghcitty
**Fast, friendly GHCi**
**ghcitty** is a tiny Rust binary that wraps GHCi with a snappy, delightful frontend

(demo) Tab completion, ghost hints, smart multiline
## Features
- Syntax highlighting
- Structured errors with expected/actual diffs, auto-import hints, error code links
- Tab completion with inline types
- Fish-style ghost completions
- Pretty-printed `Show` output (records, lists, tuples)
- Hoogle integration
- Binding explorer
- Auto-detect stack/cabal projects
- Bracketed paste
- Auto-saved, resumable sessions
- JSON mode for tooling
- Auto-reload on file changes
- Vi mode
## Of note
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.
## Install
### Prerequisites
You just need a [GHC](https://www.haskell.org/ghcup/install/) and [Rust](https://rust-lang.org/tools/install/) installed
### Cargo
[](https://crates.io/crates/ghcitty)
```
cargo install ghcitty
```
And use with:
```
ghcitty
```
### From source
```
git clone https://github.com/mattlianje/ghcitty.git
cd ghcitty
cargo install --path .
```
### Nix
```
nix profile install github:mattlianje/ghcitty
```
### Cabal / Stack
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
```
## Usage
```
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
```
## Tour
#### Auto-multiline with navigation
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
`:hoogle` to search by name or type, `:doc` for Haddock docs.
#### Vi mode and $EDITOR
Vi keybindings. `Ctrl+G` opens `$EDITOR`, evals on save.
#### Auto-reload
Edit a loaded file and ghcitty picks up the changes automatically without `:r`
## Commands
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 + g Open $EDITOR, eval on save
:scratch Open the persistent Scratch.hs in $EDITOR, :load on save (no args)
:undo Undo last expressions
:config List runtime config
:config_ [value] Toggle a bool, or set a value (session-only)
```
## Config
`~/.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_`. 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
```
## FAQ
**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?**
- Commands are fenced with sentinel markers so ghcitty knows exactly where your output begins and ends.
- For eval, it sends `:type expr` first to capture the type, then the expression itself.
- Definitions skip the type query and look up the bound name after.
- All GHCi `:` 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...
- We enter multiline on trailing `=`, `do`, `where`, `etc`, unbalanced brackets, etc
- `Blank line` + `` submits your expression
- Bracketed paste is treated as if you used a `:{/:}` block
**How does completion work?**
- `` opens a columnar menu using `:complete repl` with full line context, so `:m + Data.Li` completes module names.
- For short candidate lists, the type of each match shows alongside it.
- Ghcitty's own slash commands (`:scratch`, `:config_*`, `:edit`, `:undo`, `:doc`, `:hoogle`) appear in completions and ghost hints too.
- Ghost completions show the top match dimmed after 2+ chars.
**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/.hs`. `--continue` replays on startup.