feat(desktop): expand a whole file from its header, and show a file that only moved as its lines
Merged
DA
1d ago+471+471+012345678901234567890123456789-11-11-01234567890123456789
Summary
Part of the stage-cli features the developer chose: expand or collapse a whole file, as stage-cli's file header does (file-diff-list.tsx:522, lib/file-expansion-context.tsx, lib/full-file-preview.ts). Built on #3762's readTexts and stacked on the header actions PR.
- Expand full file / Collapse to changes.
- A compact header button (
UnfoldVertical/FoldVertical, with a pressed state and a tooltip) draws the whole file, every unchanged line among its changes, until it's pressed again. - It's offered only on files #3762 lets expand: changed in place or moved with changes, a patch drawn, not a secret path.
- It's also offered on files that only moved. It's never offered on images drawn as pictures.
- A compact header button (
- How the file gets drawn. Pierre 1.5.2's
CodeViewonly has a list-wideexpandUnchanged. So instead of drivingexpandHunkacross a file's hunks, the item'sfileDiffis replaced withparseDiffFromFile(before, after, { context: MAX }): one hunk holding every line.- It's cached per texts object, so redrawing a file for its notes keeps the same diff.
- Collapse re-parses the patch fresh, which returns the file to its changes, gaps closed.
- It survives virtualization by construction: the item's diff is the whole file, so scrolling away and back draws it the same. I checked this in the harness: lines 1… are still drawn after scrolling 30,000 px away and back.
- Reading the file. It goes through the same door as the gaps (
FileTexts.read): oneTASKS_FILEread atheadSha,blobSha-checked, kept for the answer's life.- Nothing is read until the button is pressed, and a file whose gaps were already opened isn't read again.
- A refused read leaves the file as it is and shows the refusal line, as a gap's refusal does.
- A pure rename (no hunks) still says "renamed without changes" at first. Once expanded, it shows its whole text as unchanged lines (
textsOftreats the text before as the text after).- stage-cli shows these up front, because its CLI sends both sides of every file.
- Here that would be one GitHub read per renamed file on every open, so it's behind the same button.
- The note itself offers it too: "File renamed without changes to its contents. · Show file", a link-toned
TextButtonthat runs the same toggle.
- Threads stay anchored, since annotations are keyed by side and line. Commenting stays limited to lines GitHub accepts (
commentLinesis unchanged).
Screenshots
PR #2908's build.mjs in the harness (Chromium).
| light | dark | |
|---|---|---|
| the button's hint | ![]() | ![]() |
| expanded, lines from 1 | ![]() | ![]() |
| a pure rename's Show file (PR #2855) | ![]() | ![]() |
Evidence
tsc --noEmitfor panel and desktop: clean../scripts/oxlint.sh: 0 errors.pnpm knip: clean../scripts/repository-checks.sh: passed.vitest run --project panel --project desktop: 231 files, 2366 tests passed, run with this change in the tree.- New test in
agent-changes-tab.test.ts:- An added file is offered nothing; a file that only moved starts as its notice.
- Expanding hands the bundle
wholetexts. For the moved file, pressed through its note's Show file, before equals after and it's no longer a lead. - Collapse to changes drops
whole. - Re-expanding reads nothing new: two files, two reads.
Invariants
- Checks green locally, as listed above.
- JSON Schema goldens unchanged.
- Behaviour tested.
- No new
as. - No raw async primitives.
- Test count +1.
- Deps unchanged.
Made with Luke
Review fixes (Devin)
- A pure rename shown whole drew nothing: two identical texts diff to no hunk.
diff-view/whole-diff.tsnow lays such a file out as one context hunk. A file with no lines keeps its notice. - Threads on a file drawn whole are placed against every line of its texts, not just the patch's rows. This covers a pure rename and threads outside the hunks of an expanded file.
- A stale whole read (from before a refresh) is dropped instead of overwriting files expanded since.





