diff --git a/extensions/git/package.json b/extensions/git/package.json index 17e8de43d3841..e9e667dcc337b 100644 --- a/extensions/git/package.json +++ b/extensions/git/package.json @@ -88,7 +88,7 @@ "command": "git.reopenClosedRepositories", "title": "%command.reopenClosedRepositories%", "category": "Git", - "enablement": "!operationInProgress && git.ClosedRepositoryCount != 0" + "enablement": "!operationInProgress && git.closedRepositoryCount != 0" }, { "command": "git.close", diff --git a/extensions/git/src/model.ts b/extensions/git/src/model.ts index 48f3a5c43e60b..3315b3eee5881 100644 --- a/extensions/git/src/model.ts +++ b/extensions/git/src/model.ts @@ -19,7 +19,6 @@ import { ApiRepository } from './api/api1'; import { IRemoteSourcePublisherRegistry } from './remotePublisher'; import { IPostCommitCommandsProviderRegistry } from './postCommitCommands'; import { IBranchProtectionProviderRegistry } from './branchProtection'; -import { ObservableSet } from './observable'; class RepositoryPick implements QuickPickItem { @memoize get label(): string { @@ -93,6 +92,42 @@ interface OpenRepository extends Disposable { repository: Repository; } +class ClosedRepositoriesManager { + + private _repositories: Set; + get repositories(): string[] { + return [...this._repositories.values()]; + } + + constructor(private readonly workspaceState: Memento) { + this._repositories = new Set(workspaceState.get('closedRepositories', [])); + this.onDidChangeRepositories(); + } + + addRepository(repository: string): void { + this._repositories.add(repository); + this.onDidChangeRepositories(); + } + + deleteRepository(repository: string): boolean { + const result = this._repositories.delete(repository); + if (result) { + this.onDidChangeRepositories(); + } + + return result; + } + + isRepositoryClosed(repository: string): boolean { + return this._repositories.has(repository); + } + + private onDidChangeRepositories(): void { + this.workspaceState.update('closedRepositories', [...this._repositories.values()]); + commands.executeCommand('setContext', 'git.closedRepositoryCount', this._repositories.size); + } +} + export class Model implements IBranchProtectionProviderRegistry, IRemoteSourcePublisherRegistry, IPostCommitCommandsProviderRegistry, IPushErrorHandlerRegistry { private _onDidOpenRepository = new EventEmitter(); @@ -170,9 +205,9 @@ export class Model implements IBranchProtectionProviderRegistry, IRemoteSourcePu return this._parentRepositories; } - private _closedRepositories: ObservableSet; + private _closedRepositoriesManager: ClosedRepositoriesManager; get closedRepositories(): string[] { - return [...this._closedRepositories.values()]; + return [...this._closedRepositoriesManager.repositories]; } /** @@ -187,10 +222,9 @@ export class Model implements IBranchProtectionProviderRegistry, IRemoteSourcePu private disposables: Disposable[] = []; - constructor(readonly git: Git, private readonly askpass: Askpass, private globalState: Memento, private workspaceState: Memento, private logger: LogOutputChannel, private telemetryReporter: TelemetryReporter) { - this._closedRepositories = new ObservableSet(workspaceState.get('closedRepositories', [])); - this._closedRepositories.onDidChange(this.onDidChangeClosedRepositories, this, this.disposables); - this.onDidChangeClosedRepositories(); + constructor(readonly git: Git, private readonly askpass: Askpass, private globalState: Memento, readonly workspaceState: Memento, private logger: LogOutputChannel, private telemetryReporter: TelemetryReporter) { + // Repositories managers + this._closedRepositoriesManager = new ClosedRepositoriesManager(workspaceState); workspace.onDidChangeWorkspaceFolders(this.onDidChangeWorkspaceFolders, this, this.disposables); window.onDidChangeVisibleTextEditors(this.onDidChangeVisibleTextEditors, this, this.disposables); @@ -379,11 +413,6 @@ export class Model implements IBranchProtectionProviderRegistry, IRemoteSourcePu openRepositoriesToDispose.forEach(r => r.dispose()); } - private onDidChangeClosedRepositories(): void { - this.workspaceState.update('closedRepositories', [...this._closedRepositories.values()]); - commands.executeCommand('setContext', 'git.closedRepositoryCount', this._closedRepositories.size); - } - private async onDidChangeVisibleTextEditors(editors: readonly TextEditor[]): Promise { if (!workspace.isTrusted) { this.logger.trace('[svte] Workspace is not trusted.'); @@ -496,7 +525,7 @@ export class Model implements IBranchProtectionProviderRegistry, IRemoteSourcePu } // Handle repositories that were closed by the user - if (!openIfClosed && this._closedRepositories.has(repositoryRoot)) { + if (!openIfClosed && this._closedRepositoriesManager.isRepositoryClosed(repositoryRoot)) { this.logger.trace(`Repository for path ${repositoryRoot} is closed`); return; } @@ -506,7 +535,7 @@ export class Model implements IBranchProtectionProviderRegistry, IRemoteSourcePu const repository = new Repository(this.git.open(repositoryRoot, dotGit, this.logger), this, this, this, this, this.globalState, this.logger, this.telemetryReporter); this.open(repository); - this._closedRepositories.delete(repository.root); + this._closedRepositoriesManager.deleteRepository(repository.root); // Do not await this, we want SCM // to know about the repo asap @@ -658,7 +687,7 @@ export class Model implements IBranchProtectionProviderRegistry, IRemoteSourcePu } this.logger.info(`Close repository: ${repository.root}`); - this._closedRepositories.add(openRepository.repository.root.toString()); + this._closedRepositoriesManager.addRepository(openRepository.repository.root); openRepository.dispose(); } diff --git a/extensions/git/src/observable.ts b/extensions/git/src/observable.ts deleted file mode 100644 index b32fbf156dd3f..0000000000000 --- a/extensions/git/src/observable.ts +++ /dev/null @@ -1,70 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ - -import { EventEmitter } from 'vscode'; - -export class ObservableSet implements Set { - - readonly [Symbol.toStringTag]: string = 'ObservableSet'; - - private _set: Set; - private _onDidChange = new EventEmitter(); - readonly onDidChange = this._onDidChange.event; - - constructor(values?: readonly T[] | null) { - this._set = new Set(values); - } - - get size(): number { - return this._set.size; - } - - add(value: T): this { - this._set.add(value); - this._onDidChange.fire(); - - return this; - } - - clear(): void { - if (this._set.size > 0) { - this._set.clear(); - this._onDidChange.fire(); - } - } - - delete(value: T): boolean { - const result = this._set.delete(value); - if (result) { - this._onDidChange.fire(); - } - - return result; - } - - forEach(callbackfn: (value: T, value2: T, set: Set) => void, thisArg?: any): void { - this._set.forEach((_value, key) => callbackfn.call(thisArg, key, key, this)); - } - - has(value: T): boolean { - return this._set.has(value); - } - - entries(): IterableIterator<[T, T]> { - return this._set.entries(); - } - - keys(): IterableIterator { - return this._set.keys(); - } - - values(): IterableIterator { - return this._set.keys(); - } - - [Symbol.iterator](): IterableIterator { - return this.keys(); - } -}