helix-editor/helix
helix-vcs
Diff-provider abstraction. Powers the diff gutter signs and the git-related typable commands. ~1,300 lines of Rust. Git is the only backend today, but the interface is provider-shaped to allow other VCS systems later.
Purpose
helix-vcs answers two questions for any open file:
- What did the file look like at HEAD? — used to produce the diff hunks rendered in the gutter and accessed by
goto_next/prev_change. - What is the current branch / commit name? — used in the statusline.
Plus a third capability: enumerate changed files in the workspace, used by the changed-files picker.
Directory layout
helix-vcs/src
├── lib.rs # DiffProviderRegistry, DiffProvider enum, public API
├── status.rs # FileChange enum (Untracked/Modified/Conflict/Renamed/Deleted)
├── diff.rs # DiffHandle, Hunk; ties diff_input to the rope
├── diff/ # supporting modules (line-based diff implementation)
└── git/, git.rs # Git provider via gix (gitoxide)Key abstractions
| Type | File | Purpose |
|---|---|---|
DiffProviderRegistry |
lib.rs |
Holds a Vec<DiffProvider>. Each call iterates providers until one answers. |
DiffProvider |
lib.rs |
An enum with one variant per backend — currently only Git. |
DiffHandle |
diff.rs |
Per-document handle. Holds the base text (HEAD version) plus an ArcSwap<Hunks> updated in the background as the document changes. |
Hunk |
diff.rs |
One contiguous block of differences (before, after line ranges). |
FileChange |
status.rs |
Conflict, Modified, Untracked, Renamed, Deleted. |
Git backend
The git backend uses gix (the gitoxide crate) — a pure-Rust git implementation. Helix specifically pulls in gix's Repository, status (for the file changes iterator), and diff modules (see helix-vcs/src/git.rs).
Three operations:
get_diff_base(path)— find the file's blob at HEAD and return its bytes.get_current_head_name(path)— resolve the symbolic HEAD; either a branch or a short commit hash.for_each_changed_file(workdir, cb)— stream changed files usinggix::status::index_worktree.
The git cargo feature (default-on for helix-term) gates the entire backend so a no-VCS build is possible.
DiffHandle
A DiffHandle is created when a Document opens a file. It runs a small background task that:
- Holds the base text (immutable for the document's lifetime, refreshed when the user runs
:reload). - Receives change notifications from the document (current
Rope). - Recomputes the hunk list against the base text on a debounce.
- Publishes the result via
ArcSwapso the gutter renderer reads without locking.
graph LR
Doc[Document::apply] --> Notify[DiffHandle: notify_change]
Notify --> BG[Background task]
BG -- diff base vs current --> Hunks
Hunks --> Swap[ArcSwap publish]
Gutter[gutter::diff render] -- read --> SwapThe diff itself uses a hand-rolled line-diff in diff/. It returns a sorted vector of Hunks used by the gutter and by goto_next_change/goto_prev_change commands (helix-term/src/commands.rs).
Integration points
Editor::diff_providersis aDiffProviderRegistryconstructed at startup.Document::diff_handleis created lazily on open; updated on apply.- The diff gutter is implemented in
helix-view/src/gutter.rsreading fromDocument::diff_handle. - The statusline branch indicator pulls from
Document::version_control_head(helix-term/src/ui/statusline.rs).
Entry points for modification
- Adding a new VCS backend: add a variant to
DiffProviderinlib.rs, implementget_diff_base,get_current_head_name, andfor_each_changed_filefor it, and feature-gate the new module the same waygitis. - Tweaking diff granularity: see
diff.rsand theHunksrepresentation. - Changing how stale the diff can be: tune the debounce in the
DiffHandlebackground task.
Built by Factory AutoWiki from public repository content. It is a generated preview for codebase exploration, not source-maintained documentation.