Open-Source Wikis

/

Helix

/

Packages

/

helix-vcs

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:

  1. 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.
  2. 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 using gix::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:

  1. Holds the base text (immutable for the document's lifetime, refreshed when the user runs :reload).
  2. Receives change notifications from the document (current Rope).
  3. Recomputes the hunk list against the base text on a debounce.
  4. Publishes the result via ArcSwap so 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 --> Swap

The 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_providers is a DiffProviderRegistry constructed at startup.
  • Document::diff_handle is created lazily on open; updated on apply.
  • The diff gutter is implemented in helix-view/src/gutter.rs reading from Document::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 DiffProvider in lib.rs, implement get_diff_base, get_current_head_name, and for_each_changed_file for it, and feature-gate the new module the same way git is.
  • Tweaking diff granularity: see diff.rs and the Hunks representation.
  • Changing how stale the diff can be: tune the debounce in the DiffHandle background task.

Built by Factory AutoWiki from public repository content. It is a generated preview for codebase exploration, not source-maintained documentation.

helix-vcs – Helix wiki | Factory