feat(diff): add a button to expand all hidden lines of a diff file - #38675
Open
lunny wants to merge 4 commits into
Open
feat(diff): add a button to expand all hidden lines of a diff file#38675lunny wants to merge 4 commits into
lunny wants to merge 4 commits into
Conversation
Contributor
There was a problem hiding this comment.
Pull request overview
Adds a per-diff-file “Expand all lines” toggle that expands every collapsed gap in that file (using one request per gap via direction=all) and collapses back by re-fetching the pristine ?file-only=true render, with backend safeguards and tests to avoid the earlier OOM/state issues.
Changes:
- Frontend: add a diff header button that expands/collapses all hidden lines in a file; reuse shared HTML-fetch parsing for “load diff” and collapse.
- Backend: support
direction=allby reusing the existing full-gap fill path and add a size guard (413) for large blobs; fix tail-section line counts so “expand down” renders for tail gaps. - Tests: unit/integration/e2e coverage for full-gap expansion (leading/middle/tail), size guard behavior, and expand/collapse/unfold UX.
Reviewed changes
Copilot reviewed 12 out of 12 changed files in this pull request and generated 2 comments.
Show a summary per file
| File | Description |
|---|---|
| web_src/js/svg.ts | Adds new icon imports/registrations used by the expand-all toggle. |
| web_src/js/features/repo-diff.ts | Implements expand/collapse-all behavior and registers the global click handler. |
| templates/repo/diff/box.tmpl | Adds the expand-all toggle button to each diff file header (conditionally). |
| services/gitdiff/gitdiff.go | Adds data-expand-all-url to gap elements; fixes tail-section line count propagation. |
| services/gitdiff/gitdiff_excerpt.go | Adjusts full-gap excerpt fill offset semantics for direction=all/single vs end-of-file gaps. |
| routers/web/repo/compare.go | Rejects direction=all expansions for blobs at/above MaxDisplayFileSize (413). |
| services/gitdiff/gitdiff_test.go | Adds regression coverage for tail-section direction and verifies expand-all URL emission rules. |
| services/gitdiff/gitdiff_excerpt_test.go | Adds unit tests for direction=all on leading/middle/end-of-file gaps. |
| tests/integration/compare_test.go | Integration coverage for direction=all requests and the 413 guard behavior. |
| tests/e2e/utils.ts | Adds an API helper to update a file (used by the new e2e test). |
| tests/e2e/diff-expand-all.test.ts | E2E test covering expand, collapse, and unfold-then-expand behavior. |
| options/locale/locale_en-US.json | Adds user-facing strings for expand/collapse-all tooltip/aria labels. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
bircni
requested changes
Jul 28, 2026
bircni
left a comment
Member
There was a problem hiding this comment.
Please follow the contribution guidelines and add a screenshot
prepareDiffRenderDetail computed the file line counts into local variables instead of the DiffRenderDetail fields that addTailSection reads, so the tail section was always built with zero indices and GetExpandDirection never reported a direction for it. As a result the "expand down to the end of the file" button was never rendered. Assisted-by: Codet
Each file header in a diff gets a button that fills in every hidden (unchanged) line of that file; clicking it again restores the file to its pristine rendering. Expanding reuses the existing blob_excerpt endpoint with a new "direction=all", which means "fill this whole gap in one response, without the usual 20-line chunking". That direction shares the code path "single" already used, so a file needs one request per gap (hunks + 1) rather than one request per chunk. The offset derivation in BuildBlobExcerptDiffSection now comes from the hunk sizes instead of the direction, which is equivalent for every request the UI emits and makes "how much to expand" orthogonal to the expand direction. "direction=all" is the only path that materialises an unbounded number of lines, so it refuses files at or above MaxDisplayFileSize. Collapsing re-fetches the file with the existing "file-only" URL instead of restoring a snapshot of the DOM, so it is correct even when the user had already expanded some gaps by hand. Assisted-by: Codet
The update API needs the current blob sha, but the GET fetching it was neither retried nor status-checked: a transient 5xx or a 404 surfaced as a confusing JSON parse error instead of the retry helper's message. Wrap it like apiCreatePR does, reading the sha only when the response is ok. Assisted-by: Codet
…n test OpenRepositoryLocal gained a cat-file batch context parameter in go-gitea#38684, which broke the build of this package's tests after rebasing onto main. Assisted-by: Codet
lunny
force-pushed
the
lunny/expand-full-file
branch
from
July 29, 2026 07:13
6aead8c to
bdea3a6
Compare
Member
Author
Updated |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Adds a button to each diff file header that expands all of that file's hidden (unchanged) lines in one click, and collapses them again on a second click.
This is a re-implementation of #36663, which was rejected for duplicating backend code, for OOM/DoS risk, and for fragile frontend state. The approach here is deliberately different.
Expanding: one request per gap, no new backend logic
A file's hidden lines live in "gaps" between hunks, so a file has
hunks + 1gaps — typically 1-10, not the 200 chunked requests the earlier attempt made for a 4000-line file.BuildBlobExcerptDiffSectionalready had a branch that fills an entire gap in one response; onlyup/downdo the 20-line chunking. Sodirection=allneeds no new logic, no new option field, and no batch endpoint — it just shares that existing branch withsingle.The one backend change this needs is that the
offsetin that branch is now derived from the hunk sizes (leftHunkSize <= 0 && rightHunkSize <= 0, i.e. "this gap runs to the end of the file") instead of fromdirection == "down". This is equivalent for every request the UI can emit —downis only ever offered for gaps with both hunk sizes 0, andup/singleonly for gaps with at least one hunk size above 0 — and it makes "how much to expand" orthogonal to "which direction the button points".Collapsing: re-render, don't snapshot
Collapsing re-fetches the file through the existing
?file-only=trueURL rather than restoring savedinnerHTML. That keeps it correct when the user had already expanded some gaps by hand, and there is no DOM snapshot to go stale. The "fetch a page, take its file body" logic is now a shared helper with the existing.diff-load-buttonpath.Memory safety
direction=allis the only path that can materialise an unbounded number of lines, so it rejects files at or aboveMaxDisplayFileSize. The excerpt itself still streams throughbufio.Scanner— there is noio.ReadAllof the blob anywhere.Included bug fix
The first commit fixes a pre-existing bug:
prepareDiffRenderDetailwrote the file line counts into local variables instead of theDiffRenderDetailfields thataddTailSectionreads, so the tail section was always built with zero indices andGetExpandDirectionnever reported a direction for it. The "expand down to the end of the file" button therefore never rendered for any diff. Without this, "expand all lines" could never reach a file's tail. It is a separate commit so it can be backported on its own.Notes
data-global-click/registerGlobalEventFunc, so it keeps working for files brought in by "load more files".styleandwhitespace, since neither is persisted for anonymous visitors.Tests
direction=allfor a leading gap, an interior gap, and an end-of-file gap, asserting exact line ranges, that no further expander row is emitted, and that highlighting still runs; plus a regression test for the tail-section fix that assertsGetExpandDirection() == "down"(verified red before the fix).data-expand-all-urlfor both the leading and the end-of-file gap, asserting the full line range through the file's last line inclusive and that no expander button is left behind; plus the 413 guard and that the guard does not affect chunked requests.Screenshots
Generated by Codet