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:
git diff <target> --name-status- file list with M/A/D/R classification.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.git ls-files --others --exclude-standard- untracked files (only whentarget == "HEAD", capped atMAX_UNTRACKED_FILESentries, each read up toMAX_UNTRACKED_FILE_SIZEbytes).
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§
- Commit
Meta - One commit in the review stepper’s ordered list.
shais the full hash (used to scope the per-commit diff),short_shathe abbreviated form for display,subjectthe commit’s first line.bodyis the message beyond the subject, filled lazily byscan_commit_bodywhen the stepper first lands on the commit (empty until then, and for a subject-only commit). - Diff
Line - 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.
- File
Hunks - One file’s worth of hunks, ordered as
git diffemitted them. - Hunk
- A single
@@-delimited hunk inside one file’s diff.linespreserves 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. - Name
Status 🔒Entry - One
git diff --name-statusline: 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 inFileHunksso the content read can carry both sides of a rename while the overlay keeps the one it draws. - Scan
Outcome - Outcome of a single scan invocation.
filescarries whatever was parsed;scanner_okisfalsewhen at least one of the underlying subprocess calls hitFailedorOversize- 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§
- Diff
Fetch 🔒 - One file-diff subprocess result before it’s folded into a
FileScanOutcome: parsed hunks, the size cap, or a crash. - Diff
Line Kind - Per-line classification inside a hunk.
- File
Scan 🔒Outcome - Per-file fetch result.
SubprocessFailedpropagates back toscanso a single-file crash flipsscanner_okwithout poisoning the rest.oversizemarks 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-widescanner_ok. - File
Status - File-level change classification from
git diff --name-status, plus a syntheticUntrackedvariant for files surfaced fromgit 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 logformat 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 tripsEMFILE. 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
/diffoverlay’s untracked surface is suppressed (noUrows 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 diffrange for one commit, orNonewhenshanames no commit git can read. - contains_
hunk_ 🔒marker - True when
sectioncontains 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
targetinto the git ref-spec the underlying subprocess receives. - fetch_
file_ 🔒hunks - Fetch one file’s hunks for the overlay, pinning at
PINNED_CONTEXT_LINESso the returned hunks carry enough context for in-memory expansion. The--separator keeps a--foopath 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. ReturnsNoneon 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-statusoutput into a list ofFileHunksstubs. Hunks are filled in by the per-file fetch pass. - parse_
name_ 🔒status_ entries - Parse
git diff --name-statusoutput 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.
targetis a plain ref / SHA /"HEAD"(not a../...range - the helperdiff_ref_specpicks the shape for us)."HEAD"runs a two-dot working-tree diff (uncommitted only); any other ref runsgit diff <target>...HEAD, the three-dot form that surfaces what THIS branch contributed vs the merge-base withtarget. Three-dot matches the Inspector GIT panel’s branch-ahead scanner (which composesformat!("{default}...HEAD")via the same helper), so the panel and overlay agree on what’s diffable even after a squash-merge where two-dotgit diff main HEADwould 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_commitsbecause a multi-line body would break its line-per-commitgit logparse; the stepper fetches it lazily per commit alongside the hunks. - scan_
commit_ body_ within scan_commit_bodywith its command budget spelled; see the module’sscan_within.- scan_
commit_ within scan_commitwith its command budget spelled; see the module’sscan_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, ortargetunresolvable). - scan_
commits_ within scan_commitswith its command budget spelled; see the module’sscan_within.- scan_
untracked 🔒 - Read untracked files from
git ls-files --others --exclude-standardand synthesise aFileHunksfor each one (statusUntracked, single all-added hunk). Caps total count atMAX_UNTRACKED_FILES- when the working tree has more untracked entries than that, returns an emptyVecso 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_specis already the exact shape git receives -HEAD,main...HEAD,<sha>^..<sha>, an empty-tree range, etc. Never surfaces untracked files, sountracked_suppressedis always 0. - scan_
within scanwith its command budget spelled: the shell gives each child this reader spawns the 10 sCOMMAND_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-statuscode’s leading letter means, orNonefor a code git grew that forge does not know.