# CodeDiff
Fast, robust, syntax aware code diffing.
# Installation
```
cargo install codediff
```
This builds from source, so you'll need a C compiler on `PATH` alongside a Rust toolchain
(edition 2024, so rustc 1.85+) - the bundled SQLite and the tree-sitter grammars are all compiled
from C during the build. The first `cargo install` will take a couple of minutes because of this
plus the `lto = "fat"` release profile.
The git-history analysis tools in `src/bin/` (not installed by `cargo install`, only relevant if
you're building from a checkout) sit behind an off-by-default `stats` feature, since they pull in
git2 and its own OpenSSL/libssh2 build dependencies that the diffing tool itself doesn't need. Build
them with `cargo build --features stats`.
# Guiding principles
## Robust
CodeDiff must be able to process 100% of all commits in the full test dataset.
The full test dataset contains the git commit history, as available on the main branch, for about
7400 open source git repositories. The list of repositories was extracted from the Gentoo Linux
distribution and is available in `research/list_of_repositories.csv`.
A smaller list of 100 repositories, the "small" dataset, is available in the same directory for
faster iterations when debugging.
## Fast
CodeDiff must produce a diff in under 400ms for 99.99% of all commits in the full test dataset.
In code, I accept less readable, more complex code if it is faster.
Benchmarks are used to make sure performance doesn't regress.
# Using the TUI
`cargo run` opens a terminal UI with two panels, "Before" and "After". Terminals 220 columns or
wider show both panels side by side; narrower terminals show one panel at a time. Passing two file
paths, `cargo run -- BEFORE AFTER`, opens straight into their diff instead of an empty viewer.
* `Tab` — switch the active panel.
* `o` — open a file selector for the active panel. Once both panels have a file, the diff between
them is computed and drawn automatically (green = inserted, red = deleted, dark green = updated,
yellow = moved).
* `c` — open the theme picker.
* Arrow keys or `h`/`j`/`k`/`l` — move the cursor, one line or column at a time, same as a text
editor. The range under the cursor, and the matching range on the other panel, are highlighted
in blue.
* `Page Up`/`Page Down`/`Home`/`End` — scroll.
* `q` or `Esc` — quit (`Esc` cancels an open dialog instead, while one is open).
# License
Copyright (C) 2026 Marko Ivankovic
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published
by the Free Software Foundation.
See the LICENSE file for the full text of the License.
## Can't use AGPL software?
Contact me for options.
# For Developers, human or otherwise
This part of the README is mostly used to tell the AI how to work in this code. Still, useful for
humans too.
## Technology
The project is completely written in Rust.
User configuration (e.g. the active theme) is stored on disk via `confy`. SQLite is used
separately, by the dataset-analysis tools in `src/bin/`, to store the stats they collect.
The UI is a Terminal UI written using the excellent Ratatui and Crossterm libraries.
### UI design patterns
The UI uses the [Component architecture](https://ratatui.rs/concepts/application-patterns/component-architecture/).
Each component encapsulates its own state, event handlers, and rendering logic.
## Code quality
Code must always be formatted using the automated standard Rust formatter.
No Rust check errors are allowed. Rust check should be run frequently.
## Testing
Automated tests should be run frequently during coding.
Diff quality and diff speed are measured separately (see "Quality" and "Speed" below) and should
be checked on demand, definitely before any release.
### Automated tests
Each file in src/ should end with the test module for that file, as is typical in Rust. These tests
should test both happy-path and corner cases, and should use src/test/helper.rs to get handmade
high quality test data.
**Per-file unit tests must run in under 1 second.**
src/test/ additionally holds slower, fixture-driven tests (e.g. src/test/optimal_solutions/, which
checks real diffs against human-verified ground truth). **These must run in under 5 seconds.**
Semi-automated tests that run on the small and full dataset take some time to run and should be run
when appropriate, definitely before any release.
### How should tests handle dependencies?
*No mocks*. Mocks prevent testing through the interface and are brittle.
Ideally, the real implementation is used.
When necessary, e.g. for filesystem or database access, fake in-memory implementations should be used.
### Quality
`cargo run --release --bin benchmark_optimal_solutions` diffs every fixture in
src/test/data/diffs/ that has a human-verified ground truth mapping, and reports how many nodes
each one gets wrong. Use this to check whether a change made diffs better or worse.
### Speed
Automated benchmarks, using the Rust criterion library, measure the wall clock time of the main
diffing algorithm on all handmade test cases from src/test/helper.rs. Run these frequently to
catch performance regressions.
## Code structure
Rust's project structure must be followed.
Some directories don't exist yet but should be created if the need arises.
```
<root of the repository>
|- /src <- The implementation
|- main.rs <- Entry point: parses CLI args and starts the TUI
|- code.rs <- The struct and methods related to reading and parsing one unit of code
|- code/ <- Sensible implementation units related to code.rs
|- diff.rs <- Everything related to actually diffing two or more units of code
|- diff/ <- Sensible implementation units related to diff.rs
|- stats.rs <- Tools used to process large datasets to guide the design
|- stats/ <- Sensible implementation units related to stats.rs
|- tui.rs <- Declares the TUI's submodules and sets up logging
|- tui/ <- The TUI itself: app.rs (controller), ui.rs (terminal rendering),
| components/, widgets/
| |- SPECS.md <- TUI specs
|- test/ <- Shared test helpers, plus slower fixture-driven tests (see "Testing")
|- bin/ <- Standalone developer tools (benchmarking, dataset sampling, etc.)
|- /benches <- Benchmarks
|- /research <- Datasets and analysis scripts used to guide design decisions
|- README.md <- This file. Only very high level information goes here
|- AGENTS.md <- AI-only instructions
|- REVIEW.md <- Comments about the codebase that need to be improved upon
|- TODO.md <- List of small to mid size TODO items that need to be fixed in the future
```
The SPECS.md and README.md files can exist in any subdirectory, and they always serve the same
purpose:
* README.md - High level summary. Must be readable to humans.
* SPECS.md - Semi-structured collection of specifications and a decision log of every decision that
was taken during implementation.
TODO.md and REVIEW.md are normally root-only. A subsystem can have its own TODO.md for issues
specific to it (e.g. src/diff/TODO.md) - but REVIEW.md stays root-only.