# srev — source reviewer
A terminal TUI viewer specialized for *reading* code without opening an editor.
It keeps the controls simple so you can focus on reviewing diffs and browsing full files. No editing features.
---
## Features
- **Working tree vs HEAD diff** on demand with `d` — review uncommitted changes
- **Toggle diff ⇄ full code** with `d`, preserving the corresponding line position
- **Vim-like cursor** for reading code; **jump to definition** under cursor with `gd`
- **Visual mode** (`v`/`V`) to select a range, then `y` to copy to clipboard
- **Outline pane** (bottom-left) lists symbols in the open file for quick navigation
- **In-file search** (`/` → `Enter`, `n`/`N` for next/previous match)
- **Fuzzy file search** (`Ctrl-P`, powered by nucleo — fzf equivalent)
- **Project-wide content search** (`Ctrl-F`, case-insensitive substring) — jump to a matching line
- **Inline fuzzy filtering** with `/` in tree, outline, and overlay panels
- **`Ctrl-R` reload** — re-reads the open file, git state, tree, and index while keeping cursor position
- **Syntax highlighting** for 70+ languages via inkjet / tree-sitter — **Markdown also highlights code inside fenced blocks** per language
- **Diff review navigation** — jump between hunks with `n`/`N`, between changed files with `]`/`[`. Diffs default to **side-by-side** (new/deleted files fall back to single column automatically); toggle with `s`
- File tree shows change status (`M`=modified / `A`=added / `D`=deleted / `?`=untracked) respecting `.gitignore`
- **Editor-style change gutter in code view** — added (green) / modified (blue) / deletion-above (red) vs HEAD
- Single binary. Builds on Linux / macOS / Windows
---
## Installation
You need a Rust toolchain (`cargo`) and a **C compiler** (required to build
libgit2 and tree-sitter grammars). The first build takes a few minutes and the
binary is about 80 MB because grammar files are bundled.
### From crates.io (recommended)
```sh
cargo install srev
```
### From GitHub (latest development version)
```sh
cargo install --git https://github.com/ore-public/srev
```
Either way the binary is installed to `~/.cargo/bin/srev` (run it as `srev` if
that directory is on your `$PATH`).
### Build from source (for development)
```sh
git clone https://github.com/ore-public/srev
cd srev
cargo build --release # output: target/release/srev
cargo test # run unit tests
```
---
## Usage
### Launching
```sh
srev [PATH] # defaults to the current directory if PATH is omitted
```
- Starts in **code mode** (file tree browsing). Press `d` to switch to diff (working tree vs HEAD).
### Layout
```
┌──────────────┬──────────────────────────────┐
│ File tree │ │
│ (code mode) │ Content │
│ Changed │ (code or diff) │
│ files │ │
│ (diff mode) │ │
├──────────────┤ │
│ Outline │ │
│ (Symbols) │ │
└──────────────┴──────────────────────────────┘
Status / help bar
```
- **Top-left**: file tree (code mode) or changed-file list (diff mode)
- **Bottom-left**: symbol list for the open file (Outline / Symbols)
- **Right**: content pane — code or unified diff
- **Bottom bar**: status and key hints
Press `d` to toggle between code and diff, keeping the current line in view.
### Key Bindings
#### Global
| `q` | Quit |
| `Tab` | Cycle focus (tree → outline → content) |
| `d` | Toggle diff ⇄ code (line position preserved) |
| `Ctrl-P` | Open fuzzy file search overlay |
| `Ctrl-F` | Project-wide content search (substring); `Enter` jumps to the matching line |
| `Ctrl-R` | Reload (file, git state, tree, index — cursor kept) |
| `]` / `[` | Open next / previous file (code mode = all files by path; diff mode = changed files) |
#### Tree (code mode) / Changed-file list (diff mode)
| `j` / `k`, `↓` / `↑` | Move up/down |
| `Enter` / `l` | Open file / expand directory |
| `h` | Collapse directory (tree only) |
| `/` | Inline fuzzy filter |
#### Outline (bottom-left)
| `j` / `k` | Select symbol |
| `Enter` / `l` | Jump to definition line |
| `/` | Filter symbols |
#### Content pane — code mode (vim-like)
| `h` / `j` / `k` / `l` | Move cursor |
| `w` / `b` | Word forward/back (within line) |
| `0` / `$` | Line start / end |
| `gg` / `G` | File start / end |
| `Ctrl-d` / `Ctrl-u` | Half-page scroll |
| `gd` | Jump to definition of word under cursor |
| `v` / `V` | Start visual mode (character / line) |
| `y` | Copy selection to clipboard |
| `Y` | Copy location to clipboard (no selection = `path:line:col`; single-line = `path:line`; multi-line = `path:start-end`) |
| `Esc` | Cancel selection |
| `/` → type → `Enter` | In-file search |
| `n` / `N` | Next / previous match |
> The `g` prefix for `gg` and `gd` is fixed and cannot be remapped in the config file.
#### Content pane — diff mode
| `j` / `k` | Scroll |
| `gg` / `G` | Jump to start / end |
| `PageDown` / `PageUp` | Page scroll |
| `n` / `N` | Jump to next / previous hunk (change block) |
| `s` | Toggle side-by-side ⇄ unified (default is side-by-side; new/deleted files show as single column) |
#### Overlay / filter / search input
| `Esc` | Cancel / close |
| `Enter` | Confirm |
| `Backspace` | Edit input |
| `↑` / `↓` or `Ctrl-p` / `Ctrl-n` | Move through candidates |
> `Ctrl-p` / `Ctrl-n` for candidate navigation is active **only while a filter or overlay is open**.
> In normal mode, `Ctrl-P` opens the fuzzy file search overlay.
---
## Configuration
### Remapping Keys
Config file: `~/.config/srev/config.toml`
(Override the path with the `SREV_CONFIG` environment variable.)
Add entries under `[keys]` as `"key" = "action"`.
```toml
[keys]
"ctrl-r" = "reload"
"x" = "toggle_diff" # bind to a different key
"d" = "none" # disable the default d binding
```
### Key Notation
| Single character | `"a"`, `"/"`, `"$"` |
| Ctrl modifier | `"ctrl-p"`, `"ctrl-r"` |
| Uppercase | `"Y"`, `"G"`, `"N"` |
| Named keys | `tab`, `enter`, `esc`, `space`, `up`, `down`, `left`, `right`, `home`, `end`, `pageup`, `pagedown`, `backspace`, `del` |
### Action Names
| `quit` | Quit |
| `focus_next` | Cycle focus |
| `down` | Move down |
| `up` | Move up |
| `left` | Move left / collapse directory |
| `right` | Move right / open |
| `activate` | Open / confirm |
| `top` | Jump to top (like `gg`) |
| `bottom` | Jump to bottom (like `G`) |
| `half_page_down` | Half-page scroll down |
| `half_page_up` | Half-page scroll up |
| `word_forward` | Word forward |
| `word_back` | Word back |
| `line_start` | Line start |
| `line_end` | Line end |
| `toggle_diff` | Toggle diff ⇄ code |
| `goto_def` | Jump to definition |
| `find` | Start in-file search |
| `search_next` | Next match |
| `search_prev` | Previous match |
| `visual_char` | Character visual mode |
| `visual_line` | Line visual mode |
| `yank` | Copy selection |
| `yank_location` | Copy location (line / line range when selecting) |
| `fuzzy_find` | Open file search overlay |
| `reload` | Reload |
| `cancel` | Cancel selection / close |
| `next_file` | Open next file (code = all files; diff = changed files) |
| `prev_file` | Open previous file (code = all files; diff = changed files) |
| `toggle_split` | Toggle unified ⇄ side-by-side diff |
| `grep` | Project-wide content search |
Use `"none"` to disable a key binding.
The `g` prefix for `gg` / `gd` cannot be remapped.
---
## Supported Languages
### Syntax Highlighting
**70+ languages** via inkjet (tree-sitter based).
**Markdown** is supported via tree-sitter's block + inline grammars, and code
inside fenced blocks (```rust, etc.) is highlighted per language when supported.
### Code Jump (`gd`) and Outline
Supported for **Rust, Python, JavaScript, Go, Ruby, C** only.
---
## Tech Stack
| TUI / terminal abstraction | `ratatui` + `crossterm` |
| Syntax highlighting | `inkjet` (tree-sitter based, 70+ languages) |
| Fuzzy matching | `nucleo-matcher` |
| File traversal (gitignore-aware) | `ignore` |
| Git diff / status | `git2` (vendored libgit2) |
| Symbol index / definition jump | `tree-sitter-tags` |
| Clipboard | `arboard` |
| Keymap config | `toml` |
---
## Known Limitations
- **No horizontal scroll** — long lines can be traversed with the cursor, but the view does not pan horizontally.
- **Side-by-side view** gives each pane about half the screen width, so long lines clip sooner. Toggling with `s` re-shows a nearby position rather than an exact match.
- **`gd` index builds in the background** — it starts on launch, so on large projects an early `gd` may briefly show "indexing…" (jumps are instant once ready).
- **Wide characters and tabs** — cursor and selection highlight positions may be slightly off on lines containing full-width characters or tab characters.
- **In-file search highlights whole lines** — the exact match position within the line is not highlighted.
- **Clipboard via arboard is for local use** — when connecting over SSH, clipboard content may not reach the remote terminal (consider OSC52 for SSH use cases).
---
## License
This project is dual-licensed under **MIT OR Apache-2.0**.
See [`LICENSE-MIT`](LICENSE-MIT) and [`LICENSE-APACHE`](LICENSE-APACHE) for details.
Third-party component licenses are listed in [`THIRD-PARTY-NOTICES.md`](THIRD-PARTY-NOTICES.md).
Notable entries:
- **libgit2** (vendored static link via the git2 crate): GPLv2 + linking exception
- **nucleo-matcher**: MPL-2.0