Repository navigation
feat(files): hide whitespace-only changes (Advanced setting, on by default) - #934
Conversation
The Files panel diff reader already hid indentation and trailing-whitespace changes through Monaco's default (ignoreTrimWhitespace), with no way to see them and an empty-looking reader for whitespace-only files. A new Advanced setting, "Hide whitespace-only changes in diffs" (on by default), now drives that option explicitly for Changes and Commits diffs, and a localized notice replaces the empty reader when a file's only differences are hidden. The option is display-only: switching it never rereads a diff or changes any request, Monaco recomputes in place, and staging/commits keep using exact content. Like VS Code it ignores leading/trailing whitespace and line endings; whitespace inside a line still shows (narrower than git diff -w). File-list +/- counts still come from Git. Covered by diff-whitespace and behavior-registry unit tests and a git-history browser regression rendering the real Advanced section (default hides re-indentation, whitespace-only notice, turning it off shows the change without a reread and persists, Commits follow the setting); UI typecheck and the 19 git-history browser tests pass.
pascalandr
left a comment
There was a problem hiding this comment.
Independent gatekeeper pass 1 on ddba1ae: no P0/P1 (the notice never hid a real content change in any tested case); 1 P2 + 4 P3, merge held.
- P2
diff-whitespace.ts: line-ending-only differences (CRLF↔LF, frequent on Windows with raw worktree bytes vs Git LF) are treated as whitespace-only. Monaco never shows line endings in either mode, so the notice's advice to turn the setting off leads to a blank reader. Fix: exclude line-ending-only changes, or show a separate setting-independent note. Update the unit test and FILES_PANEL.md. - P3 A side that is a single empty line makes Monaco's legacy algorithm report a whole-file change regardless of the trim option, yet the helper says "whitespace-only".
- P3 The trailing-blank regex is quadratic on long inner space runs (80k spaces take ~8 s on the main thread). Fix: index scans with early exit.
- P3 A leading BOM plus trailing whitespace shows 0 changes in Monaco but no notice. Fix: strip one leading
. - P3 Unused exports
DIFF_WHITESPACE_MODES/DiffWhitespaceMode.
Verified: defaults for old configs, persistence, registry placement, the live toggle without a reread, the single viewer consumer, i18n and styling. UI typecheck; unit tests 3/3; git-history browser tests 19/19. Fixes and another pass follow.
Address the first independent review of the whitespace diff setting. classifyHiddenDiffChange() replaces the boolean helper. "whitespace" means only leading/trailing spaces or tabs differ, which Monaco hides only while the setting is on, so the existing notice shows only then. "invisible" means only line endings or a byte-order mark differ, which Monaco never draws in either mode; a separate localized note now explains it whatever the setting, instead of advising users to turn the setting off for a still-blank reader. null means Monaco draws a real change. Also: a side that is a single empty line returns null (Monaco's legacy diff shows a whole-file change there); one leading BOM is stripped before comparing; the quadratic trim regex is replaced by index scans with early exit (100k-space lines classify in under a millisecond instead of seconds); unused exports are removed. FILES_PANEL.md and AGENTS.md no longer claim the setting covers line endings. Covered by classifier unit tests (CRLF, lone CR, BOM, empty sides, re-indent with CRLF, performance) and a git-history browser regression for a CRLF-only file with the setting on and off; UI typecheck, 5 unit tests and 19 git-history browser tests pass.
pascalandr
left a comment
There was a problem hiding this comment.
Fixes for gatekeeper pass 1 pushed in 0545e07:
- P2:
classifyHiddenDiffChange()separates two cases:- "whitespace": shows the existing notice, only while the setting is on;
- "invisible": line endings or BOM only. Monaco never draws these, so a separate localized note always explains them.
- P3:
- A single-empty-line side now returns null.
- One leading BOM is stripped before comparing.
- The quadratic regex is replaced by index scans with early exit; a 100k-space line now takes 0.6 ms (was ~2.9 s).
- Unused exports are removed.
- Docs:
FILES_PANEL.mdandAGENTS.mdare corrected.
Validation: UI typecheck clean; unit tests 5/5 (classifier cases and performance); git-history browser tests 19/19, including a CRLF-only file with the setting on and off.
Independent pass 2 follows.
Reworks the Advanced setting into "Hide whitespace-only changes" (on by default). Its main effect is now on the Files panel Changes list: unstaged tracked text files whose only differences are whitespace or line endings are left out, so re-indentation or CRLF churn no longer crowds the list. The diff reader keeps trimming leading/trailing whitespace as before, and the whitespace notice is now a factual statement shown whether the setting is on or off (Monaco 0.52 never draws same-length trailing-whitespace swaps). Detection runs server-side with Git itself: when requested, the existing bounded status read adds one `git diff --numstat -z --ignore-all-space` query (no per-file processes) and flags unstaged entries whose normal numstat is non-zero but whose -w numstat is empty. Untracked, binary, added, deleted, renamed, mode-only and conflicted changes are never hidden; a failed detection hides nothing. Staged files always stay visible, so a commit never includes a change the list does not show. Selection, range staging, drag-and-drop and counts use only the visible list, so hidden files stay unstaged. Toggling the setting re-reads the list and discards in-flight reads made under the old option. Covered by server tests on a real repository (whitespace-only, CRLF-only, real, binary, untracked, staged, staged-then-reindented; option-keyed request sharing; failure hides nothing), UI unit tests (staged rows kept, range staging skips hidden files, live toggle, stale reads) and the git-history browser suite (19/19); server and UI typechecks pass.
pascalandr
left a comment
There was a problem hiding this comment.
Independent gatekeeper pass on a7c0676 (reworked list hiding): 1 P2 + 2 P3, merge held.
- P2
git-status.ts:243-247: an explicit0 0record in the-wnumstat is treated as whitespace-only. Git lists mode changes and unmerged files as0 0, so a chmod (update-index --chmod=+x+ whitespace edit) or a pending conflict resolution got hidden. Fix: flag only paths absent from the-woutput, skip unmerged entries, add server tests for both repros, and correct the docs. - P3 The
-wquery and the unstaged numstat run concurrently; a real write between them can briefly hide a change. Fix: run-wafter the numstat resolves. - P3 The docs don't mention that
-walso hides final-newline-only changes.
Verified OK: -z parsing (spaces, Unicode, tabs), path key alignment, binary/-diff, submodules, untracked, intent-to-add, partially staged files, commit/stage flows (hidden files are never committed), option-keyed sharing, fail-open, UI visible-list counts/selection/stale reads, i18n.
Tests: typechecks; server 6/6; UI unit 20/20; browser 19/19. Fixes and another pass follow.
Address the independent review of the whitespace-only list hiding. Git lists worktree mode changes and unmerged paths in the --ignore-all-space numstat as explicit `0 0` records, while it omits files whose only changes are whitespace or line endings. Treating `0 0` like an absent path hid a chmod or a pending conflict resolution whenever the rest of the edit was whitespace, so it could never be seen or staged. Only paths absent from the -w output are now flagged, and entries whose staged side is unmerged are never flagged regardless of record order. Older Git that prints `0 0` for every whitespace-only file therefore never hides anything. The -w query now starts only after the unstaged numstat resolves, so a write between the two reads can only make the hidden state follow newer content. Docs mention that -w also hides final-newline-only changes. Server tests on throwaway repositories cover a worktree mode change listed as `0 0` (visible), a staged chmod (staged row visible, re-indent hidden), an unmerged re-indented resolution (visible), a final-newline-only change (hidden) and the sequential query order; server 8/8, UI unit 32/32, git-history browser 19/19 and both typechecks pass.
pascalandr
left a comment
There was a problem hiding this comment.
Independent gatekeeper pass on 2e7c21c: ZERO FINDINGS.
Verified on throwaway repositories with Git 2.53.0.windows.2:
- Hidden (absent from the
-woutput): re-indents, CRLF-only, final-newline and inner-spacing changes. - Visible: real changes; worktree mode changes listed as
0 0; staged chmods (staged row visible); conflicts resolved as "ours" or "theirs" and re-indented. - Ordering: the
-wquery now runs only after the unstaged numstat resolves, and detection still fails open. - Docs match the observed Git behaviour; UI, i18n and in-diff notes are unchanged since the previous pass.
Validation: server and UI typechecks clean; server git-status 8/8; UI unit 20/20; browser git-history 19/19.
Proceeding with the requested admin merge.
What changes for the user
New setting in Settings → Advanced: Hide whitespace-only changes, on by default.
When such a file is opened with the setting off, a short note says that only whitespace, or only line endings, changed. A diff is never silently blank.
How it works
git diff --numstat -z --ignore-all-spacequery, with no per-file processes. An unstaged tracked text file is hidden when its normal diff is non-empty but its-wdiff is empty.-w, which also ignores spacing inside a line. The diff reader keeps Monaco's leading/trailing trim.Validation
git-history.test.ts19/19.Oversized files touched:
useGitChanges.ts(~554 lines),stores/preferences.tsx(~1,589 lines) andlib/settings/behavior-registry.ts(~589 lines).