Skip to content

Commit 7f2e1f3

Browse files
committed
Add diffviewer.openCollapsed command
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.
1 parent 419faee commit 7f2e1f3

File tree

4 files changed

+61
-16
lines changed

4 files changed

+61
-16
lines changed

package.json

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,10 @@
5050
"command": "diffviewer.showSideBySide",
5151
"title": "Show diff side by side",
5252
"icon": "$(files)"
53+
},
54+
{
55+
"command": "diffviewer.openCollapsed",
56+
"title": "Open diff collapsed (all viewed)"
5357
}
5458
],
5559
"customEditors": [
@@ -142,6 +146,13 @@
142146
}
143147
],
144148
"menus": {
149+
"explorer/context": [
150+
{
151+
"command": "diffviewer.openCollapsed",
152+
"group": "navigation@99",
153+
"when": "resourceLangId == 'diff'"
154+
}
155+
],
145156
"editor/title": [
146157
{
147158
"command": "diffviewer.showLineByLine",

src/extension/provider.ts

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,10 @@ export class DiffViewerProvider implements vscode.CustomTextEditorProvider {
4343
}),
4444
vscode.commands.registerCommand("diffviewer.showLineByLine", () => setOutputFormatConfig("line-by-line")),
4545
vscode.commands.registerCommand("diffviewer.showSideBySide", () => setOutputFormatConfig("side-by-side")),
46+
vscode.commands.registerCommand("diffviewer.openCollapsed", async (file) => {
47+
const collapsedUri = vscode.Uri.from({ ...file, query: "collapsed" });
48+
await vscode.commands.executeCommand("vscode.openWith", collapsedUri, "diffViewer");
49+
}),
4650
];
4751
}
4852

@@ -71,6 +75,8 @@ export class DiffViewerProvider implements vscode.CustomTextEditorProvider {
7175
docId: diffDocument.uri.fsPath,
7276
});
7377

78+
const collapseAll = new URLSearchParams(diffDocument.uri.query).has("collapsed");
79+
7480
const messageReceivedHandler = new MessageToExtensionHandlerImpl({
7581
diffDocument,
7682
viewedStateStore,
@@ -82,7 +88,7 @@ export class DiffViewerProvider implements vscode.CustomTextEditorProvider {
8288
const webviewContext: WebviewContext = { document: diffDocument, panel: webviewPanel, viewedStateStore };
8389

8490
this.registerEventHandlers({ webviewContext, messageHandler: messageReceivedHandler });
85-
this.updateWebview(webviewContext);
91+
this.updateWebview(webviewContext, collapseAll);
8692
}
8793

8894
private registerEventHandlers(args: { webviewContext: WebviewContext; messageHandler: MessageToExtensionHandler }) {
@@ -112,7 +118,7 @@ export class DiffViewerProvider implements vscode.CustomTextEditorProvider {
112118
args.webviewContext.panel.onDidDispose(() => disposables.dispose());
113119
}
114120

115-
private updateWebview(webviewContext: WebviewContext): void {
121+
private updateWebview(webviewContext: WebviewContext, collapseAll = false): void {
116122
this.postMessageToWebviewWrapper({
117123
webview: webviewContext.panel.webview,
118124
message: {
@@ -153,6 +159,7 @@ export class DiffViewerProvider implements vscode.CustomTextEditorProvider {
153159
config: config,
154160
diffFiles: diffFiles,
155161
viewedState: viewedState,
162+
collapseAll,
156163
},
157164
},
158165
});

src/webview/message/api.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ export interface UpdateWebviewPayload {
66
config: AppConfig;
77
diffFiles: DiffFile[];
88
viewedState: ViewedState;
9+
collapseAll: boolean;
910
}
1011

1112
export interface MessageToWebviewApi {

src/webview/message/handler.ts

Lines changed: 40 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -52,13 +52,25 @@ export class MessageToWebviewHandlerImpl implements MessageToWebviewHandler {
5252
const appTheme = this.currentConfig.diff2html.colorScheme === ColorSchemeType.DARK ? "dark" : "light";
5353
this.setupTheme(appTheme);
5454

55+
// hide the diff container for now so the full diff doesn't show
56+
if (payload.collapseAll) {
57+
diffContainer.style.display = "none";
58+
}
59+
5560
const diff2html = new Diff2HtmlUI(diffContainer, payload.diffFiles, this.currentConfig.diff2html);
5661
diff2html.draw();
5762

5863
this.registerViewedToggleHandlers(diffContainer);
5964
this.registerDiffContainerHandlers(diffContainer);
60-
await this.hideViewedFiles(diffContainer, payload.viewedState);
65+
if (payload.collapseAll) {
66+
this.setAllViewedStates(true);
67+
} else {
68+
await this.hideViewedFiles(diffContainer, payload.viewedState);
69+
}
6170
this.updateFooter();
71+
72+
// show the diff
73+
diffContainer.style.display = "block";
6274
});
6375
}
6476

@@ -97,7 +109,7 @@ export class MessageToWebviewHandlerImpl implements MessageToWebviewHandler {
97109
viewedToggle.classList.remove(CHANGED_SINCE_VIEWED);
98110
this.scrollDiffFileHeaderIntoView(viewedToggle);
99111
this.updateFooter();
100-
this.sendFileViewedMessage(viewedToggle);
112+
this.sendFileViewedMessage(viewedToggle, viewedToggle.checked);
101113
}
102114

103115
private onMarkAllViewedChangedHandler(event: Event): void {
@@ -107,12 +119,17 @@ export class MessageToWebviewHandlerImpl implements MessageToWebviewHandler {
107119
}
108120

109121
const isChecked = markAllViewedCheckbox.checked;
122+
this.setAllViewedStates(isChecked);
123+
this.updateFooter();
124+
}
125+
126+
private setAllViewedStates(viewed: boolean) {
110127
const allToggles = this.getViewedToggles();
111128

112129
for (const toggle of Array.from(allToggles)) {
113-
if (toggle.checked !== isChecked) {
114-
toggle.click();
115-
}
130+
this.updateDiff2HtmlFileCollapsed(toggle, viewed);
131+
// no await here so we synchronously return from this function, the sending will happen later as hashes get computed
132+
this.sendFileViewedMessage(toggle, viewed);
116133
}
117134
}
118135

@@ -271,18 +288,27 @@ export class MessageToWebviewHandlerImpl implements MessageToWebviewHandler {
271288
const viewedToggles = diffContainer.querySelectorAll<HTMLInputElement>(
272289
Diff2HtmlCssClassElements.Input__ViewedToggle,
273290
);
291+
292+
// first synchronously hide all viewed files so we don't render too much in case the file is huge and most is collapsed
293+
// we'll do a second pass over hidden files, so we'll hold them in togglesToRevisit
294+
const togglesToRevisit = [];
274295
for (const toggle of Array.from(viewedToggles)) {
275296
const fileName = this.getDiffElementFileName(toggle);
276297
if (fileName && viewedState[fileName]) {
277-
const diffHash = await this.getDiffHash(toggle);
278-
if (diffHash === viewedState[fileName]) {
279-
this.updateDiff2HtmlFileCollapsed(toggle, true);
280-
} else {
281-
toggle.classList.add(CHANGED_SINCE_VIEWED);
282-
}
298+
togglesToRevisit.push({ toggle, oldSha1: viewedState[fileName] });
299+
this.updateDiff2HtmlFileCollapsed(toggle, true);
283300
}
284301
}
285302

303+
for (const { toggle, oldSha1 } of togglesToRevisit) {
304+
const diffHash = await this.getDiffHash(toggle);
305+
if (diffHash !== oldSha1) {
306+
this.updateDiff2HtmlFileCollapsed(toggle, false);
307+
toggle.classList.add(CHANGED_SINCE_VIEWED);
308+
}
309+
}
310+
}
311+
286312
private updateDiff2HtmlFileCollapsed(toggleElement: HTMLInputElement, collapse: boolean) {
287313
// do the same thing that diff2html does to collapse or expand one file
288314
toggleElement.checked = collapse;
@@ -299,13 +325,13 @@ export class MessageToWebviewHandlerImpl implements MessageToWebviewHandler {
299325
return fileContent ? getSha1Hash(fileContent) : null;
300326
}
301327

302-
private async sendFileViewedMessage(toggleElement: HTMLInputElement): Promise<void> {
303-
const fileName = this.getDiffElementFileName(toggleElement);
328+
private async sendFileViewedMessage(diffElement: HTMLInputElement, viewed: boolean): Promise<void> {
329+
const fileName = this.getDiffElementFileName(diffElement);
304330
if (!fileName) {
305331
return;
306332
}
307333

308-
const viewedSha1 = toggleElement.checked ? await this.getDiffHash(toggleElement) : null;
334+
const viewedSha1 = viewed ? await this.getDiffHash(diffElement) : null;
309335

310336
this.postMessageToExtensionFn({
311337
kind: "toggleFileViewed",

0 commit comments

Comments
 (0)