diff --git a/src/vs/workbench/api/browser/mainThreadSCM.ts b/src/vs/workbench/api/browser/mainThreadSCM.ts index 8f78a95e712..906e878941d 100644 --- a/src/vs/workbench/api/browser/mainThreadSCM.ts +++ b/src/vs/workbench/api/browser/mainThreadSCM.ts @@ -150,18 +150,22 @@ class MainThreadSCMProvider implements ISCMProvider { } } - $registerGroup(handle: number, id: string, label: string): void { - const group = new MainThreadSCMResourceGroup( - this.handle, - handle, - this, - {}, - label, - id - ); + $registerGroups(_groups: [number /*handle*/, string /*id*/, string /*label*/, SCMGroupFeatures][]): void { + const groups = _groups.map(([handle, id, label, features]) => { + const group = new MainThreadSCMResourceGroup( + this.handle, + handle, + this, + features, + label, + id + ); - this._groupsByHandle[handle] = group; - this.groups.splice(this.groups.elements.length, 0, [group]); + this._groupsByHandle[handle] = group; + return group; + }); + + this.groups.splice(this.groups.elements.length, 0, groups); } $updateGroup(handle: number, features: SCMGroupFeatures): void { @@ -326,7 +330,7 @@ export class MainThreadSCM implements MainThreadSCMShape { this._repositories.delete(handle); } - $registerGroup(sourceControlHandle: number, groupHandle: number, id: string, label: string): void { + $registerGroups(sourceControlHandle: number, groups: [number /*handle*/, string /*id*/, string /*label*/, SCMGroupFeatures][], splices: SCMRawResourceSplices[]): void { const repository = this._repositories.get(sourceControlHandle); if (!repository) { @@ -334,7 +338,8 @@ export class MainThreadSCM implements MainThreadSCMShape { } const provider = repository.provider as MainThreadSCMProvider; - provider.$registerGroup(groupHandle, id, label); + provider.$registerGroups(groups); + provider.$spliceGroupResourceStates(splices); } $updateGroup(sourceControlHandle: number, groupHandle: number, features: SCMGroupFeatures): void { diff --git a/src/vs/workbench/api/common/extHost.protocol.ts b/src/vs/workbench/api/common/extHost.protocol.ts index eb5d8ea8455..8d35f851476 100644 --- a/src/vs/workbench/api/common/extHost.protocol.ts +++ b/src/vs/workbench/api/common/extHost.protocol.ts @@ -837,7 +837,7 @@ export interface MainThreadSCMShape extends IDisposable { $updateSourceControl(handle: number, features: SCMProviderFeatures): void; $unregisterSourceControl(handle: number): void; - $registerGroup(sourceControlHandle: number, handle: number, id: string, label: string): void; + $registerGroups(sourceControlHandle: number, groups: [number /*handle*/, string /*id*/, string /*label*/, SCMGroupFeatures][], splices: SCMRawResourceSplices[]): void; $updateGroup(sourceControlHandle: number, handle: number, features: SCMGroupFeatures): void; $updateGroupLabel(sourceControlHandle: number, handle: number, label: string): void; $unregisterGroup(sourceControlHandle: number, handle: number): void; diff --git a/src/vs/workbench/api/common/extHostSCM.ts b/src/vs/workbench/api/common/extHostSCM.ts index 6464c9af686..399e264ea82 100644 --- a/src/vs/workbench/api/common/extHostSCM.ts +++ b/src/vs/workbench/api/common/extHostSCM.ts @@ -6,10 +6,10 @@ import { URI, UriComponents } from 'vs/base/common/uri'; import { Event, Emitter } from 'vs/base/common/event'; import { debounce } from 'vs/base/common/decorators'; -import { DisposableStore, MutableDisposable } from 'vs/base/common/lifecycle'; +import { DisposableStore, IDisposable, MutableDisposable } from 'vs/base/common/lifecycle'; import { asPromise } from 'vs/base/common/async'; import { ExtHostCommands } from 'vs/workbench/api/common/extHostCommands'; -import { MainContext, MainThreadSCMShape, SCMRawResource, SCMRawResourceSplice, SCMRawResourceSplices, IMainContext, ExtHostSCMShape, ICommandDto, MainThreadTelemetryShape } from './extHost.protocol'; +import { MainContext, MainThreadSCMShape, SCMRawResource, SCMRawResourceSplice, SCMRawResourceSplices, IMainContext, ExtHostSCMShape, ICommandDto, MainThreadTelemetryShape, SCMGroupFeatures } from './extHost.protocol'; import { sortedDiff, equals } from 'vs/base/common/arrays'; import { comparePaths } from 'vs/base/common/comparers'; import type * as vscode from 'vscode'; @@ -228,6 +228,9 @@ class ExtHostSourceControlResourceGroup implements vscode.SourceControlResourceG private readonly _onDidUpdateResourceStates = new Emitter(); readonly onDidUpdateResourceStates = this._onDidUpdateResourceStates.event; + + private _disposed = false; + get disposed(): boolean { return this._disposed; } private readonly _onDidDispose = new Emitter(); readonly onDidDispose = this._onDidDispose.event; @@ -246,7 +249,13 @@ class ExtHostSourceControlResourceGroup implements vscode.SourceControlResourceG get hideWhenEmpty(): boolean | undefined { return this._hideWhenEmpty; } set hideWhenEmpty(hideWhenEmpty: boolean | undefined) { this._hideWhenEmpty = hideWhenEmpty; - this._proxy.$updateGroup(this._sourceControlHandle, this.handle, { hideWhenEmpty }); + this._proxy.$updateGroup(this._sourceControlHandle, this.handle, this.features); + } + + get features(): SCMGroupFeatures { + return { + hideWhenEmpty: this.hideWhenEmpty + }; } get resourceStates(): vscode.SourceControlResourceState[] { return [...this._resourceStates]; } @@ -263,9 +272,7 @@ class ExtHostSourceControlResourceGroup implements vscode.SourceControlResourceG private _sourceControlHandle: number, private _id: string, private _label: string, - ) { - this._proxy.$registerGroup(_sourceControlHandle, this.handle, _id, _label); - } + ) { } getResourceState(handle: number): vscode.SourceControlResourceState | undefined { return this._resourceStatesMap.get(handle); @@ -340,7 +347,7 @@ class ExtHostSourceControlResourceGroup implements vscode.SourceControlResourceG } dispose(): void { - this._proxy.$unregisterGroup(this._sourceControlHandle, this.handle); + this._disposed = true; this._onDidDispose.fire(); } } @@ -465,26 +472,51 @@ class ExtHostSourceControl implements vscode.SourceControl { this._proxy.$registerSourceControl(this.handle, _id, _label, _rootUri); } + private createdResourceGroups = new Map(); private updatedResourceGroups = new Set(); createResourceGroup(id: string, label: string): ExtHostSourceControlResourceGroup { const group = new ExtHostSourceControlResourceGroup(this._proxy, this._commands, this.handle, id, label); - - const updateListener = group.onDidUpdateResourceStates(() => { - this.updatedResourceGroups.add(group); - this.eventuallyUpdateResourceStates(); - }); - - Event.once(group.onDidDispose)(() => { - this.updatedResourceGroups.delete(group); - updateListener.dispose(); - this._groups.delete(group.handle); - }); - - this._groups.set(group.handle, group); + const disposable = Event.once(group.onDidDispose)(() => this.createdResourceGroups.delete(group)); + this.createdResourceGroups.set(group, disposable); + this.eventuallyAddResourceGroups(); return group; } + @debounce(100) + eventuallyAddResourceGroups(): void { + const groups: [number /*handle*/, string /*id*/, string /*label*/, SCMGroupFeatures][] = []; + const splices: SCMRawResourceSplices[] = []; + + for (const [group, disposable] of this.createdResourceGroups) { + disposable.dispose(); + + const updateListener = group.onDidUpdateResourceStates(() => { + this.updatedResourceGroups.add(group); + this.eventuallyUpdateResourceStates(); + }); + + Event.once(group.onDidDispose)(() => { + this.updatedResourceGroups.delete(group); + updateListener.dispose(); + this._groups.delete(group.handle); + this._proxy.$unregisterGroup(this.handle, group.handle); + }); + + groups.push([group.handle, group.id, group.label, group.features]); + + const snapshot = group._takeResourceStateSnapshot(); + + if (snapshot.length > 0) { + splices.push([group.handle, snapshot]); + } + + this._groups.set(group.handle, group); + } + + this._proxy.$registerGroups(this.handle, groups, splices); + } + @debounce(100) eventuallyUpdateResourceStates(): void { const splices: SCMRawResourceSplices[] = [];