-
Notifications
You must be signed in to change notification settings - Fork 5
Add new command: openCollapsed #125
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
|
Thanks for the PR @jacekkopecky! I'll take a look at it asap |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull Request Overview
Adds a new diffviewer.openCollapsed command to open diffs with all files initially collapsed (treated as viewed), and refactors the webview/update logic to support collapsing without triggering focus/scroll side effects. Also optimizes viewed state persistence (removing empty state) and replaces click-driven collapse behavior with explicit DOM class manipulation to avoid unintended scrolling.
- New openCollapsed command and menu contribution
- Introduces collapseAll payload flag and logic to pre-collapse all diff files
- Replaces toggle.click() usage with manual DOM updates and adjusts viewed state saving
Reviewed Changes
Copilot reviewed 7 out of 7 changed files in this pull request and generated 5 comments.
Show a summary per file
| File | Description |
|---|---|
| src/webview/message/handler.ts | Implements collapseAll flow, custom file collapse logic, revised viewed state messaging, and UI helper adjustments |
| src/webview/message/api.ts | Updates UpdateWebviewPayload: removes diffContainer, adds collapseAll flag |
| src/webview/css/elements.ts | Adds selector for viewed toggle label to support manual collapse styling |
| src/webview/css/classes.ts | Adds enum with diff2html CSS class names used when emulating collapse behavior |
| src/extension/viewed-state.ts | Avoids persisting empty viewed state by storing undefined |
| src/extension/provider.ts | Registers openCollapsed command and propagates collapseAll flag to webview |
| package.json | Contributes new command and adds it to the explorer context menu |
Tip: Customize your code reviews with copilot-instructions.md. Create the file or learn how to get started.
| if (toggle.checked !== isChecked) { | ||
| toggle.click(); | ||
| } | ||
| this.updateDiff2HtmlFileCollapsed(toggle, viewed); |
Copilot
AI
Oct 3, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
When marking all files as viewed (viewed === true), CHANGED_SINCE_VIEWED is not removed from toggles, whereas the single-toggle path removes it in onViewedToggleChangedHandler. This leads to stale 'changed since viewed' indicators after 'mark all' operations. Remove the class when viewed is true, e.g. toggle.classList.remove(CHANGED_SINCE_VIEWED) inside the loop.
| this.updateDiff2HtmlFileCollapsed(toggle, viewed); | |
| this.updateDiff2HtmlFileCollapsed(toggle, viewed); | |
| if (viewed) { | |
| toggle.classList.remove(CHANGED_SINCE_VIEWED); | |
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
can be done unconditionally
| const diffHash = await this.getDiffHash(toggle); | ||
| if (diffHash !== oldSha1) { | ||
| this.updateDiff2HtmlFileCollapsed(toggle, false); | ||
| toggle.classList.add(CHANGED_SINCE_VIEWED); |
Copilot
AI
Oct 3, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For unchanged files (diffHash === oldSha1) the previous behavior (toggle.click()) would clear CHANGED_SINCE_VIEWED via onViewedToggleChangedHandler; now the class is never removed if it was previously present. Explicitly remove CHANGED_SINCE_VIEWED for the unchanged (still-collapsed) case to avoid stale indicators.
| toggle.classList.add(CHANGED_SINCE_VIEWED); | |
| toggle.classList.add(CHANGED_SINCE_VIEWED); | |
| } else { | |
| toggle.classList.remove(CHANGED_SINCE_VIEWED); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
unnecessary because this code is only called after a rerender so the class isn't there
|
|
||
| // first synchronously hide all viewed files so we don't render too much in case the file is huge and most is collapsed | ||
| // we'll do a second pass over hidden files, so we'll hold them in togglesToRevisit | ||
| const togglesToRevisit = []; |
Copilot
AI
Oct 3, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
[nitpick] togglesToRevisit is inferred as any[] (empty array literal) until first push; under strict/noImplicitAny this may degrade type safety. Add an explicit type: const togglesToRevisit: { toggle: HTMLInputElement; oldSha1: string }[] = [];.
| const togglesToRevisit = []; | |
| const togglesToRevisit: { toggle: HTMLInputElement; oldSha1: string }[] = []; |
src/webview/message/handler.ts
Outdated
| } | ||
| this.updateDiff2HtmlFileCollapsed(toggle, viewed); | ||
| // no await here so we synchronously return from this function, the sending will happen later as hashes get computed | ||
| this.sendFileViewedMessage(toggle, viewed); |
Copilot
AI
Oct 3, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
[nitpick] sendFileViewedMessage returns a Promise but the result is neither awaited nor intentionally ignored; if it rejects it could cause an unhandled rejection. Consider prefixing with void or adding a .catch(...) to document intentional fire-and-forget behavior: void this.sendFileViewedMessage(toggle, viewed);.
| this.sendFileViewedMessage(toggle, viewed); | |
| void this.sendFileViewedMessage(toggle, viewed); |
src/extension/provider.ts
Outdated
| vscode.commands.registerCommand("diffviewer.showLineByLine", () => setOutputFormatConfig("line-by-line")), | ||
| vscode.commands.registerCommand("diffviewer.showSideBySide", () => setOutputFormatConfig("side-by-side")), | ||
| vscode.commands.registerCommand("diffviewer.openCollapsed", async (file) => { | ||
| const collapsedUri = vscode.Uri.from({ ...file, query: "collapsed" }); |
Copilot
AI
Oct 3, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
[nitpick] Use the built-in URI.with API instead of spreading the URI object to preserve all internal fields safely: const collapsedUri = file.with({ query: 'collapsed' });.
| const collapsedUri = vscode.Uri.from({ ...file, query: "collapsed" }); | |
| const collapsedUri = file.with({ query: "collapsed" }); |
|
Thanks @caponetto ; I can look at the AI's suggestions tomorrow, it seems I really missed something but I'm not sure about how the AI suggests to fix it. |
|
@jacekkopecky Take these comments only as suggestions. Ignore them if they don't make sense. |
Of course. 😄
Happy to. |
The webView already uses SkeletonElementIds and we never use a different payload.diffContainer value anyway.
isVisible is a bit ambiguous - we're making the main body *not* visible and the loading messages visible. Then a consistent renaming for showEmpty().
This makes the workspace storage file a bit smaller.
When we use toggle.click(), that toggle gets focused, which causes the window to scroll to the last collapsed file when we switch to that tab. That's disruptive and this fixes it.
This command is in the context menu for diff files in the explorer. It opens the diff file with all parts collapsed (marked as viewed) to potentially make it easier to deal with very large diff files.
This omission was spotted by CoPilot
7f2e1f3 to
48893b7
Compare
Codecov Report✅ All modified and coverable lines are covered by tests.
🚀 New features to boost your workflow:
|
The previous test would still pass if the two commands used the opposite setOutputFormatConfig calls.
|
@caponetto I think everything is handled now. I hope I got the tests right, your way of mocking things is different from what I'm used to… |
The aim of this PR is mainly to address #124, but also includes fixes that could be added independent of tackling #124.
The new command looks like this:
The other changes included are:
@caponetto any comments are welcome; I think this is best reviewed commit-by-commit.