From ff4d2a4146be8ff81a9ab3665ba38a10eae2f8db Mon Sep 17 00:00:00 2001 From: Ladislau Szomoru <3372902+lszomoru@users.noreply.github.com> Date: Sun, 6 Feb 2022 15:58:43 +0100 Subject: [PATCH 1/2] Initial implementation --- extensions/git/package.json | 7 +++++ extensions/git/package.nls.json | 1 + extensions/git/src/repository.ts | 50 ++++++++++++++++++++++++++++---- extensions/git/tsconfig.json | 1 + 4 files changed, 54 insertions(+), 5 deletions(-) diff --git a/extensions/git/package.json b/extensions/git/package.json index 800563a808294..3efa9e8a1d3ca 100644 --- a/extensions/git/package.json +++ b/extensions/git/package.json @@ -15,6 +15,7 @@ "scmActionButton", "scmSelectedProvider", "scmValidation", + "tabs", "timeline" ], "categories": [ @@ -2113,6 +2114,12 @@ "default": true, "description": "%config.confirmNoVerifyCommit%" }, + "git.closeDiffOnOperation": { + "type": "boolean", + "scope": "resource", + "default": false, + "description": "%config.closeDiffOnOperation%" + }, "git.openDiffOnClick": { "type": "boolean", "scope": "resource", diff --git a/extensions/git/package.nls.json b/extensions/git/package.nls.json index 9fd574a721dc1..c3a9840b3561e 100644 --- a/extensions/git/package.nls.json +++ b/extensions/git/package.nls.json @@ -175,6 +175,7 @@ "config.confirmForcePush": "Controls whether to ask for confirmation before force-pushing.", "config.allowNoVerifyCommit": "Controls whether commits without running pre-commit and commit-msg hooks are allowed.", "config.confirmNoVerifyCommit": "Controls whether to ask for confirmation before committing without verification.", + "config.closeDiffOnOperation": "Controls whether the diff editor should be automatically closed when changes are committed, discarded, staged, or unstaged.", "config.openDiffOnClick": "Controls whether the diff editor should be opened when clicking a change. Otherwise the regular editor will be opened.", "config.supportCancellation": "Controls whether a notification comes up when running the Sync action, which allows the user to cancel the operation.", "config.branchSortOrder": "Controls the sort order for branches.", diff --git a/extensions/git/src/repository.ts b/extensions/git/src/repository.ts index d409a337ffabf..925ab79534c4d 100644 --- a/extensions/git/src/repository.ts +++ b/extensions/git/src/repository.ts @@ -5,7 +5,7 @@ import * as fs from 'fs'; import * as path from 'path'; -import { CancellationToken, Command, Disposable, Event, EventEmitter, Memento, OutputChannel, ProgressLocation, ProgressOptions, scm, SourceControl, SourceControlInputBox, SourceControlInputBoxValidation, SourceControlInputBoxValidationType, SourceControlResourceDecorations, SourceControlResourceGroup, SourceControlResourceState, ThemeColor, Uri, window, workspace, WorkspaceEdit, FileDecoration, commands } from 'vscode'; +import { CancellationToken, Command, Disposable, Event, EventEmitter, Memento, OutputChannel, ProgressLocation, ProgressOptions, scm, SourceControl, SourceControlInputBox, SourceControlInputBoxValidation, SourceControlInputBoxValidationType, SourceControlResourceDecorations, SourceControlResourceGroup, SourceControlResourceState, ThemeColor, Uri, window, workspace, WorkspaceEdit, FileDecoration, commands, Tab } from 'vscode'; import TelemetryReporter from '@vscode/extension-telemetry'; import * as nls from 'vscode-nls'; import { Branch, Change, ForcePushMode, GitErrorCodes, LogOptions, Ref, RefType, Remote, Status, CommitOptions, BranchQuery, FetchOptions } from './api/git'; @@ -14,7 +14,7 @@ import { debounce, memoize, throttle } from './decorators'; import { Commit, GitError, Repository as BaseRepository, Stash, Submodule, LogFileOptions } from './git'; import { StatusBarCommands } from './statusbar'; import { toGitUri } from './uri'; -import { anyEvent, combinedDisposable, debounceEvent, dispose, EmptyDisposable, eventToPromise, filterEvent, find, IDisposable, isDescendant, logTimestamp, onceEvent, relativePath } from './util'; +import { anyEvent, combinedDisposable, debounceEvent, dispose, EmptyDisposable, eventToPromise, filterEvent, find, IDisposable, isDescendant, logTimestamp, onceEvent, pathEquals, relativePath } from './util'; import { IFileWatcher, watch } from './watch'; import { Log, LogLevel } from './log'; import { IPushErrorHandlerRegistry } from './pushError'; @@ -1159,7 +1159,10 @@ export class Repository implements Disposable { } async add(resources: Uri[], opts?: { update?: boolean }): Promise { - await this.run(Operation.Add, () => this.repository.add(resources.map(r => r.fsPath), opts)); + await this.run(Operation.Add, async () => { + await this.repository.add(resources.map(r => r.fsPath), opts); + this.closeDiffEditors([], [...resources.map(r => r.fsPath)]); + }); } async rm(resources: Uri[]): Promise { @@ -1168,15 +1171,25 @@ export class Repository implements Disposable { async stage(resource: Uri, contents: string): Promise { const path = relativePath(this.repository.root, resource.fsPath).replace(/\\/g, '/'); - await this.run(Operation.Stage, () => this.repository.stage(path, contents)); + await this.run(Operation.Stage, async () => { + await this.repository.stage(path, contents); + this.closeDiffEditors([], [...resource.fsPath]); + }); this._onDidChangeOriginalResource.fire(resource); } async revert(resources: Uri[]): Promise { - await this.run(Operation.RevertFiles, () => this.repository.revert('HEAD', resources.map(r => r.fsPath))); + await this.run(Operation.RevertFiles, async () => { + await this.repository.revert('HEAD', resources.map(r => r.fsPath)); + this.closeDiffEditors(resources.map(r => r.fsPath), []); + }); } async commit(message: string | undefined, opts: CommitOptions = Object.create(null)): Promise { + const indexResources = [...this.indexGroup.resourceStates.map(r => r.resourceUri.fsPath)]; + const workingGroupResources = opts.all && opts.all !== 'tracked' ? + [...this.workingTreeGroup.resourceStates.map(r => r.resourceUri.fsPath)] : []; + if (this.rebaseCommit) { await this.run(Operation.RebaseContinue, async () => { if (opts.all) { @@ -1185,6 +1198,7 @@ export class Repository implements Disposable { } await this.repository.rebaseContinue(); + this.closeDiffEditors(indexResources, workingGroupResources); }); } else { await this.run(Operation.Commit, async () => { @@ -1201,6 +1215,7 @@ export class Repository implements Disposable { } await this.repository.commit(message, opts); + this.closeDiffEditors(indexResources, workingGroupResources); }); } } @@ -1244,9 +1259,34 @@ export class Repository implements Disposable { await this.repository.clean(toClean); await this.repository.checkout('', toCheckout); await this.repository.updateSubmodules(submodulesToUpdate); + + this.closeDiffEditors([], [...toClean, ...toCheckout]); }); } + private closeDiffEditors(indexResources: string[], workingTreeResources: string[]): void { + const config = workspace.getConfiguration('git', Uri.file(this.root)); + if (!config.get('closeDiffOnCommitOrDiscard', false)) { return; } + + const diffEditorTabsToClose: Tab[] = []; + + // Index + diffEditorTabsToClose.push(...window.tabs + .filter(t => + t.resource && t.resource.scheme === 'git' && t.viewId === 'diff' && + indexResources.some(r => pathEquals(r, t.resource!.fsPath)))); + + // Working Tree + diffEditorTabsToClose.push(...window.tabs + .filter(t => + t.resource && t.resource.scheme === 'file' && t.viewId === 'diff' && + workingTreeResources.some(r => pathEquals(r, t.resource!.fsPath)) && + t.additionalResourcesAndViewIds.find(r => r.resource!.scheme === 'git'))); + + // Close editors + diffEditorTabsToClose.forEach(t => t.close()); + } + async branch(name: string, _checkout: boolean, _ref?: string): Promise { await this.run(Operation.Branch, () => this.repository.branch(name, _checkout, _ref)); } diff --git a/extensions/git/tsconfig.json b/extensions/git/tsconfig.json index 99129079e48ca..13997275056b0 100644 --- a/extensions/git/tsconfig.json +++ b/extensions/git/tsconfig.json @@ -14,6 +14,7 @@ "../../src/vscode-dts/vscode.proposed.scmActionButton.d.ts", "../../src/vscode-dts/vscode.proposed.scmSelectedProvider.d.ts", "../../src/vscode-dts/vscode.proposed.scmValidation.d.ts", + "../../src/vscode-dts/vscode.proposed.tabs.d.ts", "../../src/vscode-dts/vscode.proposed.timeline.d.ts", "../types/lib.textEncoder.d.ts" ] From 6a83a2e85d6e32932499c4fe8bcf41fe0aa3c2dc Mon Sep 17 00:00:00 2001 From: Ladislau Szomoru <3372902+lszomoru@users.noreply.github.com> Date: Tue, 8 Feb 2022 14:24:27 +0100 Subject: [PATCH 2/2] Pushed some fixes based on testing --- extensions/git/src/repository.ts | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/extensions/git/src/repository.ts b/extensions/git/src/repository.ts index 925ab79534c4d..97b7847c56e93 100644 --- a/extensions/git/src/repository.ts +++ b/extensions/git/src/repository.ts @@ -1181,7 +1181,9 @@ export class Repository implements Disposable { async revert(resources: Uri[]): Promise { await this.run(Operation.RevertFiles, async () => { await this.repository.revert('HEAD', resources.map(r => r.fsPath)); - this.closeDiffEditors(resources.map(r => r.fsPath), []); + this.closeDiffEditors([...resources.length !== 0 ? + resources.map(r => r.fsPath) : + this.indexGroup.resourceStates.map(r => r.resourceUri.fsPath)], []); }); } @@ -1266,7 +1268,7 @@ export class Repository implements Disposable { private closeDiffEditors(indexResources: string[], workingTreeResources: string[]): void { const config = workspace.getConfiguration('git', Uri.file(this.root)); - if (!config.get('closeDiffOnCommitOrDiscard', false)) { return; } + if (!config.get('closeDiffOnOperation', false)) { return; } const diffEditorTabsToClose: Tab[] = [];