Skip to main content

Module hunks

Module hunks 

Source
Expand description

Per-file hunk scanner for the /diff overlay.

Extends super’s numstat-based snapshot with full unified-diff content needed to render the GitHub-style diff viewer. Runs up to three subprocess calls per scan:

  1. git diff <target> --name-status - file list with M/A/D/R classification.
  2. git diff <target> --no-ext-diff - full unified-diff body. The flag defeats user-configured difftastic / delta so the parser sees standard unified-diff format.
  3. git ls-files --others --exclude-standard - untracked files (only when target == "HEAD", capped at MAX_UNTRACKED_FILES entries, each read up to MAX_UNTRACKED_FILE_SIZE bytes).

Single-shot - never polled. The /diff overlay calls scan on open and renders the resulting Vec<FileHunks> for the duration of the view; refreshing mid-review would invalidate pending comments anchored to specific lines.

Always returns a ScanOutcome - files may be empty on a genuinely clean tree OR when one of the subprocess calls hit Failed / Oversize. The scanner_ok flag distinguishes the two so a downstream renderer can show “scan failed” rather than miscategorising the empty result as “no changes.”

Re-exports§

use std::path::Path; 🔒
use std::time::Duration; 🔒
use serde::Deserialize; 🔒
use serde::Deserialize; 🔒
use serde::Serialize; 🔒
use serde::Serialize; 🔒
use super::COMMAND_TIMEOUT; 🔒
use super::GitOutput; 🔒
use super::run_git_within; 🔒

Structs§

CommitMeta
One commit in the review stepper’s ordered list. sha is the full hash (used to scope the per-commit diff), short_sha the abbreviated form for display, subject the commit’s first line. body is the message beyond the subject, filled lazily by scan_commit_body when the stepper first lands on the commit (empty until then, and for a subject-only commit).
DiffLine
One rendered diff line. Carries its kind, raw text (no leading marker), and per-side line numbers so the renderer can show a gutter without recomputing positions.
FileHunks
One file’s worth of hunks, ordered as git diff emitted them.
Hunk
A single @@-delimited hunk inside one file’s diff. lines preserves the original unified-diff ordering with each line tagged as context, added, or removed - the renderer iterates them directly to draw the + / - / markers and per-side line numbers without re-classifying anything.
NameStatusEntry 🔒
One git diff --name-status line: the classification, the new path, and the old path a rename or copy names (absent for every other status). The old path survives here rather than in FileHunks so the content read can carry both sides of a rename while the overlay keeps the one it draws.
ScanOutcome
Outcome of a single scan invocation. files carries whatever was parsed; scanner_ok is false when at least one of the underlying subprocess calls hit Failed or Oversize - the file list may be partial or empty, and a downstream renderer should distinguish that case from a genuine clean tree so the user knows whether to retry vs. accept “no changes.”

Enums§

DiffFetch 🔒
One file-diff subprocess result before it’s folded into a FileScanOutcome: parsed hunks, the size cap, or a crash.
DiffLineKind
Per-line classification inside a hunk.
FileScanOutcome 🔒
Per-file fetch result. SubprocessFailed propagates back to scan so a single-file crash flips scanner_ok without poisoning the rest. oversize marks a file whose full-context fetch tripped the size cap and fell back to a bounded diff (or empty) - it renders but doesn’t expand, and crucially does NOT flip the scope-wide scanner_ok.
FileStatus
File-level change classification from git diff --name-status, plus a synthetic Untracked variant for files surfaced from git ls-files --others.

Constants§

EMPTY_TREE_SHA 🔒
Git’s canonical empty-tree object (SHA-1). Diffing a parentless root commit against it yields the commit’s full contents as additions - <sha>^ doesn’t resolve for a root, so this stands in for the non-existent parent.
FALLBACK_CONTEXT_LINES 🔒
Fallback context radius for a file whose pinned full-context fetch was still oversize - a bounded diff that renders normally (expansion is disabled for it). git’s own default is 3.
LOG_FIELD_SEP 🔒
Field separator for the git log format below - the ASCII unit separator, which never appears in a commit subject.
MAX_INFLIGHT_FETCHES 🔒
Max in-flight git diff -- <path> subprocesses during a scan. macOS’s default soft open-file limit is ~256 and every git child holds stdin/stdout/stderr pipes plus a handful of git internals (~6-10 FDs); firing all N at once on a 100+ file refactor branch trips EMFILE. 16 keeps total well under the FD ceiling while still giving a 16× speedup over a sequential loop.
MAX_UNTRACKED_FILES
Skip the untracked-file scan entirely when the working tree has more than this many untracked entries. A fresh-repo state with hundreds of untracked files would otherwise dump everything into the overlay. The Inspector GIT section is unaffected; only the /diff overlay’s untracked surface is suppressed (no U rows render in the rail when the cap is exceeded).
MAX_UNTRACKED_FILE_SIZE 🔒
Per-file size ceiling for untracked content surfaced in the diff body. Above this we keep the rail entry but skip reading bytes.
PINNED_CONTEXT_LINES 🔒
Unified-diff context radius the per-file fetch pins at open: large enough to cover realistic inter-hunk gaps (so expanding reveals hidden lines from the cached snapshot without a live re-fetch), but bounded so a big file with a small change doesn’t emit its whole content and trip the oversize cap. A gap wider than this reveals up to the cap.

Functions§

commit_ref_spec 🔒
Resolve the two-endpoint git diff range for one commit, or None when sha names no commit git can read.
contains_hunk_marker 🔒
True when section contains at least one @@ line - used by the per-file fetch path to distinguish “no body to parse” (binary / submodule, no log) from “parser couldn’t extract hunks despite headers being present” (WARN-worthy).
diff_ref_spec 🔒
Translate a caller-supplied diff target into the git ref-spec the underlying subprocess receives.
fetch_file_hunks 🔒
Fetch one file’s hunks for the overlay, pinning at PINNED_CONTEXT_LINES so the returned hunks carry enough context for in-memory expansion. The -- separator keeps a --foo path from being read as a flag.
parse_hunk_header 🔒
Parse @@ -OLD_START[,OLD_COUNT] +NEW_START[,NEW_COUNT] @@. Missing counts default to 1 per the unified-diff spec. Returns None on malformed headers (caller skips the hunk).
parse_hunks 🔒
Parse one file’s diff section into individual hunks. Hunks are @@-delimited; each line in a hunk body starts with one of - (removed), + (added), (context), or \ (newline annotation, dropped).
parse_name_status 🔒
Parse git diff --name-status output into a list of FileHunks stubs. Hunks are filled in by the per-file fetch pass.
parse_name_status_entries 🔒
Parse git diff --name-status output into entries.
parse_pair 🔒
run_file_diff 🔒
Fetch + parse one file’s diff at a given context radius. Binary / submodule entries and empty diffs return Ok(vec![]). Splits the oversize cap from a genuine subprocess crash so the caller can retry oversize at a smaller context instead of failing the whole scan.
scan
Top-level scanner entry. target is a plain ref / SHA / "HEAD" (not a ../... range - the helper diff_ref_spec picks the shape for us). "HEAD" runs a two-dot working-tree diff (uncommitted only); any other ref runs git diff <target>...HEAD, the three-dot form that surfaces what THIS branch contributed vs the merge-base with target. Three-dot matches the Inspector GIT panel’s branch-ahead scanner (which composes format!("{default}...HEAD") via the same helper), so the panel and overlay agree on what’s diffable even after a squash-merge where two-dot git diff main HEAD would be empty.
scan_commit
Scan a single commit’s own diff (<sha>^..<sha>, or against the empty tree for a parentless root commit) into per-file hunks. Never surfaces untracked files - a commit’s diff is closed over its own changes.
scan_commit_body
Fetch a commit’s message body - everything after the subject line, with the trailing newline trimmed. Empty for a subject-only commit. Kept out of scan_commits because a multi-line body would break its line-per-commit git log parse; the stepper fetches it lazily per commit alongside the hunks.
scan_commit_body_within
scan_commit_body with its command budget spelled; see the module’s scan_within.
scan_commit_within
scan_commit with its command budget spelled; see the module’s scan_within.
scan_commits
List the commits in <target>..HEAD, oldest first, for the diff overlay’s commit stepper. Empty when the range has no commits (dirty-tree-only review, /diff HEAD, or target unresolvable).
scan_commits_within
scan_commits with its command budget spelled; see the module’s scan_within.
scan_untracked 🔒
Read untracked files from git ls-files --others --exclude-standard and synthesise a FileHunks for each one (status Untracked, single all-added hunk). Caps total count at MAX_UNTRACKED_FILES - when the working tree has more untracked entries than that, returns an empty Vec so a fresh-repo state doesn’t dump hundreds of files into the overlay.
scan_with_ref_spec 🔒
Scan a pre-resolved diff range into per-file hunks. ref_spec is already the exact shape git receives - HEAD, main...HEAD, <sha>^..<sha>, an empty-tree range, etc. Never surfaces untracked files, so untracked_suppressed is always 0.
scan_within
scan with its command budget spelled: the shell gives each child this reader spawns the 10 s COMMAND_TIMEOUT, and a test gives them one of its own. The budget is a bound on the machine, not on the read: it is spent starting each child, so a loaded machine can hold a child’s first output past the shell’s 10 s and blank a file’s hunk section.
status_of 🔒
The status a --name-status code’s leading letter means, or None for a code git grew that forge does not know.