Add full-file expansion in diffs - #36663
Conversation
Add a per-file toggle button that expands all collapsed sections at once and can revert to the original collapsed state. The expand mechanism uses direct JS fetch instead of htmx, replacing the hx-get/hx-target attributes on code expander buttons with data-url. Individual expand buttons are also handled via JS delegated click handlers. The expand-all uses direction=full to make the backend expand entire gaps in a single response instead of chunk-by-chunk, significantly reducing the number of network round-trips for large files. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> Signed-off-by: silverwind <me@silverwind.io>
…ve null guards Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
|
Small margin-left added to copy button to provide some separation with the text, this is consistent with GitHub. Screenshot in PR description is updated. |
For a file with 4000 lines (locale_en-US.json), each request expands 20 lines, then you sends 200 request to server in short time? |
|
Yeah the current mechanism is inefficient. I guess we could do more backend changes to make it send all at once. |
When expanding all collapsed sections in a diff, the frontend now collects per-gap parameters from all expander buttons, joins them with commas, and makes a single GET request. The backend detects batch mode (comma in last_left), renders each section to HTML, and returns a JSON string array. Single-section expands are unchanged. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Adressed in e643492. |
|
Horrible AI code, duplicate every line in backend. |
|
Odd, I can make it deduplicate more, had already asked it to minimize the diff. |
|
Reworking this now. Plan is to replace the htmx-based fetch for single frequents with a json api that can return both single and all fragments as an array of html fragments. The full-file fetch will be a single fetch for all fragements in 1 call to the backend. |
…e2e tests Backend: - ExcerptBlob returns JSON for both single and batch expand - Add excerptBlobExpandAll with MaxDisplayFileSize guard and 100-section cap - Use FormStrings for repeated query params instead of comma-separated - BuildBlobExcerptDiffSectionsFull: shared diffVarMutable pointers for single-pass highlighting across all sections - Keep ExcerptBlob nearly identical to main (4-line early return added) Frontend: - Replace HTMX with unified JS fetch using data-global-click delegation - Remove htmx.process calls and sleep(500) hack - fetchBlobExcerpt: single expand with is-loading guard - onDiffExpandAll: batch expand via single request, collapse via saved innerHTML, auto-flip button when all gaps manually expanded - State saved before is-loading class to avoid poisoning restored state Tests: - Add e2e tests: direct expand-all, collapse, single expand, partial manual + batch, manual full expansion auto-flip - Remove old integration tests replaced by e2e coverage - Update pull_commit_test for JSON response format Co-Authored-By: Claude (Opus 4.6) <noreply@anthropic.com>
|
Rewrite done:
|
Co-Authored-By: Claude (Opus 4.6) <noreply@anthropic.com>
Co-Authored-By: Claude (Opus 4.6) <noreply@anthropic.com>
Co-Authored-By: Claude (Opus 4.6) <noreply@anthropic.com>
|
One more minor enhancement added: All expand buttons now set |
wxiaoguang
left a comment
There was a problem hiding this comment.
Horrible AI slop and duplicate code.
Need to rewrite most of them (if I would have some time, but I can't promise)
|
I backfed all your vague feedback into it when producing this. Next time give specific feedback what you want and we might get something you like. |
|
Duplicate code, fragile logic, etc. I don't want to spend more time on teaching AI on this topic, which would cost multiple times of time than I do it by myself (to be clear: I also use AI, and will be assisted by AI). Indeed there are also workarounds: just click the "View File", and/or "Blame" the file. "Full-file expansion in diff" seems to be a rare use case during code review (in most cases, people don't really need to read the unchanged parts) Since it is just a nice-to-have feature, it doesn't block any real world user and no requirement issue from end users, so either someone can make it overall right, or when I have some free time and get interest to clean up the AI slop. |
|
Give clear actionable sentence or 2 how you want the design to look. That would have taken you less time than writing that last comment and would be actually helpful. "Unclean code" without actionable feedback is not a valid reason for a rejection imho when the code demonstrably works, and has 100% test coverage. The repo is full of unclean code because of years of careless rubberstamping, why should my PRs be treated differently now? |
TheFox0x7
left a comment
There was a problem hiding this comment.
Take it with a grain of salt as I have no experience with this part of codebase:
- ExcerptBlob and excerptBlobExpandAll are basically the same function.
- IMO io.Reader should be passed down to the function instead read in the expandAll one. You get more consistent apis that way.
I'm also not sure if it wouldn't be easier to ask git for this content directly by telling git to expand context for the diff but I did not have an occasion to dig into gitea's compare systems.
Also I can't use this on files that have their diff hidden by default, despite being able to request that diff.
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 15 out of 15 changed files in this pull request and generated 2 comments.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| // Determine line range: 1-indexed inclusive | ||
| startLine := opts.LastRight + 1 | ||
| endLine := opts.RightIndex - 1 // between-hunk: stop before next hunk | ||
| if opts.LeftHunkSize == 0 && opts.RightHunkSize == 0 { | ||
| endLine = len(allLines) // EOF: expand to end of file | ||
| } | ||
|
|
||
| leftStart := opts.LastLeft + 1 | ||
| var diffLines []*DiffLine | ||
| for lineNum := startLine; lineNum <= endLine; lineNum++ { | ||
| lineIdx := lineNum - 1 // 0-indexed | ||
| if lineIdx >= len(allLines) { | ||
| break |
| btn.classList.add('is-loading', 'loading-icon-2px'); | ||
| try { | ||
| const response = await GET(btn.getAttribute('data-url')!); | ||
| if (!response.ok) return; | ||
|
|
||
| tr.insertAdjacentHTML('afterend', await response.json()); | ||
| tr.remove(); | ||
|
|

New button in diff file headers to expand all collapsed sections in one click.
Changes
Backend:
ExcerptBlobreturns JSON for both single and batch expandexcerptBlobExpandAll: single batch request reads blob once, highlights once via shareddiffVarMutablepointersMaxDisplayFileSizeguard and 100-section cap to prevent OOMparseBatchExcerptOptionsusesFormStringsfor repeated query paramsFrontend:
data-global-clickdelegationfetchBlobExcerpt: single-section expand withis-loadingguardonDiffExpandAll: batch expand via single request, collapse via saved innerHTMLTests:
This PR was written with the help of Claude Opus 4.6