diff --git a/src/vs/workbench/api/electron-browser/mainThreadSCM.ts b/src/vs/workbench/api/electron-browser/mainThreadSCM.ts index d9119994320..5aba93ce447 100644 --- a/src/vs/workbench/api/electron-browser/mainThreadSCM.ts +++ b/src/vs/workbench/api/electron-browser/mainThreadSCM.ts @@ -9,8 +9,8 @@ import { TPromise } from 'vs/base/common/winjs.base'; import URI from 'vs/base/common/uri'; import Event, { Emitter } from 'vs/base/common/event'; import { assign } from 'vs/base/common/objects'; -import { IDisposable, dispose, combinedDisposable } from 'vs/base/common/lifecycle'; -import { ISCMService, ISCMProvider, ISCMResource, ISCMResourceGroup, ISCMResourceDecorations } from 'vs/workbench/services/scm/common/scm'; +import { IDisposable, dispose } from 'vs/base/common/lifecycle'; +import { ISCMService, ISCMRepository, ISCMProvider, ISCMResource, ISCMResourceGroup, ISCMResourceDecorations } from 'vs/workbench/services/scm/common/scm'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { ICommandService } from 'vs/platform/commands/common/commands'; import { ExtHostContext, MainThreadSCMShape, ExtHostSCMShape, SCMProviderFeatures, SCMRawResource, SCMGroupFeatures, MainContext, IExtHostContext } from '../node/extHost.protocol'; @@ -220,8 +220,8 @@ class MainThreadSCMProvider implements ISCMProvider { export class MainThreadSCM implements MainThreadSCMShape { private _proxy: ExtHostSCMShape; - private _sourceControls: { [handle: number]: MainThreadSCMProvider; } = Object.create(null); - private _sourceControlDisposables: { [handle: number]: IDisposable; } = Object.create(null); + private _repositories: { [handle: number]: ISCMRepository; } = Object.create(null); + private _inputDisposables: { [handle: number]: IDisposable; } = Object.create(null); private _disposables: IDisposable[] = []; constructor( @@ -234,101 +234,113 @@ export class MainThreadSCM implements MainThreadSCMShape { } dispose(): void { - Object.keys(this._sourceControls) - .forEach(id => this._sourceControls[id].dispose()); - this._sourceControls = Object.create(null); + Object.keys(this._repositories) + .forEach(id => this._repositories[id].dispose()); + this._repositories = Object.create(null); - Object.keys(this._sourceControlDisposables) - .forEach(id => this._sourceControlDisposables[id].dispose()); - this._sourceControlDisposables = Object.create(null); + Object.keys(this._inputDisposables) + .forEach(id => this._inputDisposables[id].dispose()); + this._inputDisposables = Object.create(null); this._disposables = dispose(this._disposables); } $registerSourceControl(handle: number, id: string, label: string): void { const provider = new MainThreadSCMProvider(this._proxy, handle, id, label, this.scmService, this.commandService); - this._sourceControls[handle] = provider; + const repository = this.scmService.registerSCMProvider(provider); + this._repositories[handle] = repository; - const providerDisposable = this.scmService.registerSCMProvider(provider); - const inputDisposable = this.scmService.input.onDidChange(value => this._proxy.$onInputBoxValueChange(handle, value)); - this._sourceControlDisposables[handle] = combinedDisposable([providerDisposable, inputDisposable]); + const inputDisposable = repository.input.onDidChange(value => this._proxy.$onInputBoxValueChange(handle, value)); + this._inputDisposables[handle] = inputDisposable; } $updateSourceControl(handle: number, features: SCMProviderFeatures): void { - const sourceControl = this._sourceControls[handle]; + const repository = this._repositories[handle]; - if (!sourceControl) { + if (!repository) { return; } - sourceControl.$updateSourceControl(features); + const provider = repository.provider as MainThreadSCMProvider; + provider.$updateSourceControl(features); } $unregisterSourceControl(handle: number): void { - const sourceControl = this._sourceControls[handle]; + const repository = this._repositories[handle]; - if (!sourceControl) { + if (!repository) { return; } - this._sourceControlDisposables[handle].dispose(); - delete this._sourceControlDisposables[handle]; + this._inputDisposables[handle].dispose(); + delete this._inputDisposables[handle]; - sourceControl.dispose(); - delete this._sourceControls[handle]; + repository.dispose(); + delete this._repositories[handle]; } $registerGroup(sourceControlHandle: number, groupHandle: number, id: string, label: string): void { - const provider = this._sourceControls[sourceControlHandle]; + const repository = this._repositories[sourceControlHandle]; - if (!provider) { + if (!repository) { return; } + const provider = repository.provider as MainThreadSCMProvider; provider.$registerGroup(groupHandle, id, label); } $updateGroup(sourceControlHandle: number, groupHandle: number, features: SCMGroupFeatures): void { - const provider = this._sourceControls[sourceControlHandle]; + const repository = this._repositories[sourceControlHandle]; - if (!provider) { + if (!repository) { return; } + const provider = repository.provider as MainThreadSCMProvider; provider.$updateGroup(groupHandle, features); } $updateGroupLabel(sourceControlHandle: number, groupHandle: number, label: string): void { - const provider = this._sourceControls[sourceControlHandle]; + const repository = this._repositories[sourceControlHandle]; - if (!provider) { + if (!repository) { return; } + const provider = repository.provider as MainThreadSCMProvider; provider.$updateGroupLabel(groupHandle, label); } $updateGroupResourceStates(sourceControlHandle: number, groupHandle: number, resources: SCMRawResource[]): void { - const provider = this._sourceControls[sourceControlHandle]; + const repository = this._repositories[sourceControlHandle]; - if (!provider) { + if (!repository) { return; } + const provider = repository.provider as MainThreadSCMProvider; provider.$updateGroupResourceStates(groupHandle, resources); } $unregisterGroup(sourceControlHandle: number, handle: number): void { - const provider = this._sourceControls[sourceControlHandle]; + const repository = this._repositories[sourceControlHandle]; - if (!provider) { + if (!repository) { return; } + const provider = repository.provider as MainThreadSCMProvider; provider.$unregisterGroup(handle); } - $setInputBoxValue(value: string): void { - this.scmService.input.value = value; + $setInputBoxValue(sourceControlHandle: number, value: string): void { + const repository = this._repositories[sourceControlHandle]; + + if (!repository) { + return; + } + + repository.input.value = value; } } diff --git a/src/vs/workbench/api/node/extHost.protocol.ts b/src/vs/workbench/api/node/extHost.protocol.ts index 31490f5317e..41b81d2d12e 100644 --- a/src/vs/workbench/api/node/extHost.protocol.ts +++ b/src/vs/workbench/api/node/extHost.protocol.ts @@ -336,7 +336,7 @@ export interface MainThreadSCMShape extends IDisposable { $updateGroupResourceStates(sourceControlHandle: number, groupHandle: number, resources: SCMRawResource[]): void; $unregisterGroup(sourceControlHandle: number, handle: number): void; - $setInputBoxValue(value: string): void; + $setInputBoxValue(sourceControlHandle: number, value: string): void; } export type DebugSessionUUID = string; diff --git a/src/vs/workbench/api/node/extHostSCM.ts b/src/vs/workbench/api/node/extHostSCM.ts index 16b1c4ef6da..327bb851030 100644 --- a/src/vs/workbench/api/node/extHostSCM.ts +++ b/src/vs/workbench/api/node/extHostSCM.ts @@ -33,7 +33,7 @@ export class ExtHostSCMInputBox { } set value(value: string) { - this._proxy.$setInputBoxValue(value); + this._proxy.$setInputBoxValue(this._sourceControlHandle, value); this.updateValue(value); } @@ -43,7 +43,7 @@ export class ExtHostSCMInputBox { return this._onDidChange.event; } - constructor(private _proxy: MainThreadSCMShape) { + constructor(private _proxy: MainThreadSCMShape, private _sourceControlHandle: number) { // noop } @@ -232,7 +232,7 @@ class ExtHostSourceControl implements vscode.SourceControl { private _id: string, private _label: string, ) { - this._inputBox = new ExtHostSCMInputBox(this._proxy); + this._inputBox = new ExtHostSCMInputBox(this._proxy, this._handle); this._proxy.$registerSourceControl(this._handle, _id, _label); } diff --git a/src/vs/workbench/parts/scm/electron-browser/dirtydiffDecorator.ts b/src/vs/workbench/parts/scm/electron-browser/dirtydiffDecorator.ts index 3aa3675295f..46d2f520c00 100644 --- a/src/vs/workbench/parts/scm/electron-browser/dirtydiffDecorator.ts +++ b/src/vs/workbench/parts/scm/electron-browser/dirtydiffDecorator.ts @@ -81,7 +81,7 @@ class DirtyDiffModelDecorator { this.toDispose = []; this.triggerDiff(); this.toDispose.push(model.onDidChangeContent(() => this.triggerDiff())); - this.toDispose.push(scmService.onDidChangeProvider(() => this.triggerDiff())); + this.toDispose.push(scmService.onDidChangeRepository(() => this.triggerDiff())); } private triggerDiff(): winjs.Promise { @@ -123,13 +123,13 @@ class DirtyDiffModelDecorator { return this._originalURIPromise; } - const provider = this.scmService.activeProvider; + const repository = this.scmService.activeRepository; - if (!provider) { + if (!repository) { return winjs.TPromise.as(null); } - this._originalURIPromise = provider.getOriginalResource(this.uri) + this._originalURIPromise = repository.provider.getOriginalResource(this.uri) .then(originalUri => { if (!originalUri) { return null; diff --git a/src/vs/workbench/parts/scm/electron-browser/scm.contribution.ts b/src/vs/workbench/parts/scm/electron-browser/scm.contribution.ts index cf3f2c4cac5..5c396f0269d 100644 --- a/src/vs/workbench/parts/scm/electron-browser/scm.contribution.ts +++ b/src/vs/workbench/parts/scm/electron-browser/scm.contribution.ts @@ -49,9 +49,9 @@ export class SwitchProvider extends Action { } run(): TPromise { - const picks: IPickOpenEntry[] = this.scmService.providers.map(provider => ({ - label: provider.label, - run: () => this.scmService.activeProvider = provider + const picks: IPickOpenEntry[] = this.scmService.repositories.map(repository => ({ + label: repository.provider.label, + run: () => this.scmService.activeRepository = repository })); picks.push({ label: localize('installAdditionalSCMProviders', "Install Additional SCM Providers..."), @@ -61,7 +61,7 @@ export class SwitchProvider extends Action { viewlet.search('category:"SCM Providers" @sort:installs'); viewlet.focus(); }); - return this.scmService.activeProvider; + return this.scmService.activeRepository; }, separator: { border: true } }); diff --git a/src/vs/workbench/parts/scm/electron-browser/scmActivity.ts b/src/vs/workbench/parts/scm/electron-browser/scmActivity.ts index 4abe15c32e6..265c38c2d52 100644 --- a/src/vs/workbench/parts/scm/electron-browser/scmActivity.ts +++ b/src/vs/workbench/parts/scm/electron-browser/scmActivity.ts @@ -8,7 +8,7 @@ import { localize } from 'vs/nls'; import { IDisposable, dispose, empty as EmptyDisposable, OneDisposable } from 'vs/base/common/lifecycle'; import { VIEWLET_ID } from 'vs/workbench/parts/scm/common/scm'; -import { ISCMService, ISCMProvider } from 'vs/workbench/services/scm/common/scm'; +import { ISCMService, ISCMRepository } from 'vs/workbench/services/scm/common/scm'; import { IActivityBarService, NumberBadge } from 'vs/workbench/services/activity/common/activityBarService'; import { IWorkbenchContribution } from 'vs/workbench/common/contributions'; @@ -24,8 +24,8 @@ export class StatusUpdater implements IWorkbenchContribution { @ISCMService private scmService: ISCMService, @IActivityBarService private activityBarService: IActivityBarService ) { - this.scmService.onDidChangeProvider(this.setActiveProvider, this, this.disposables); - this.setActiveProvider(this.scmService.activeProvider); + this.scmService.onDidChangeRepository(this.setActiveRepository, this, this.disposables); + this.setActiveRepository(this.scmService.activeRepository); this.disposables.push(this.badgeHandle); } @@ -33,21 +33,22 @@ export class StatusUpdater implements IWorkbenchContribution { return StatusUpdater.ID; } - private setActiveProvider(activeProvider: ISCMProvider | undefined): void { + private setActiveRepository(repository: ISCMRepository | undefined): void { this.providerChangeDisposable.dispose(); - this.providerChangeDisposable = activeProvider ? activeProvider.onDidChange(this.update, this) : EmptyDisposable; + this.providerChangeDisposable = repository ? repository.provider.onDidChange(this.update, this) : EmptyDisposable; this.update(); } private update(): void { - const provider = this.scmService.activeProvider; + const repository = this.scmService.activeRepository; + let count = 0; - if (provider) { - if (typeof provider.count === 'number') { - count = provider.count; + if (repository) { + if (typeof repository.provider.count === 'number') { + count = repository.provider.count; } else { - count = provider.resources.reduce((r, g) => r + g.resources.length, 0); + count = repository.provider.resources.reduce((r, g) => r + g.resources.length, 0); } } diff --git a/src/vs/workbench/parts/scm/electron-browser/scmViewlet.ts b/src/vs/workbench/parts/scm/electron-browser/scmViewlet.ts index 4859e9d6e64..c099453912e 100644 --- a/src/vs/workbench/parts/scm/electron-browser/scmViewlet.ts +++ b/src/vs/workbench/parts/scm/electron-browser/scmViewlet.ts @@ -21,7 +21,7 @@ import { IDelegate, IRenderer, IListContextMenuEvent } from 'vs/base/browser/ui/ import { VIEWLET_ID } from 'vs/workbench/parts/scm/common/scm'; import { FileLabel } from 'vs/workbench/browser/labels'; import { CountBadge } from 'vs/base/browser/ui/countBadge/countBadge'; -import { ISCMService, ISCMProvider, ISCMResourceGroup, ISCMResource } from 'vs/workbench/services/scm/common/scm'; +import { ISCMService, ISCMRepository, ISCMResourceGroup, ISCMResource } from 'vs/workbench/services/scm/common/scm'; import { IEditorGroupService } from 'vs/workbench/services/group/common/groupService'; import { IWorkbenchEditorService } from 'vs/workbench/services/editor/common/editorService'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; @@ -230,13 +230,13 @@ function resourceSorter(a: ISCMResource, b: ISCMResource): number { class SourceControlViewDescriptor implements IViewDescriptor { - get provider(): ISCMProvider { return this._provider; } - get id(): string { return this._provider.id; } - get name(): string { return this._provider.label; } + get repository(): ISCMRepository { return this._repository; } + get id(): string { return this._repository.provider.id; } + get name(): string { return this._repository.provider.label; } get ctor(): any { return null; } get location(): ViewLocation { return ViewLocation.SCM; } - constructor(private _provider: ISCMProvider) { + constructor(private _repository: ISCMRepository) { } } @@ -251,13 +251,12 @@ class SourceControlView extends CollapsibleView { private disposables: IDisposable[] = []; constructor( - private provider: ISCMProvider, + private repository: ISCMRepository, options: IViewletViewOptions, @IKeybindingService protected keybindingService: IKeybindingService, @IThemeService protected themeService: IThemeService, @IContextMenuService protected contextMenuService: IContextMenuService, @IContextViewService protected contextViewService: IContextViewService, - @ISCMService protected scmService: ISCMService, @IListService protected listService: IListService, @ICommandService protected commandService: ICommandService, @IMessageService protected messageService: IMessageService, @@ -267,7 +266,7 @@ class SourceControlView extends CollapsibleView { ) { super({ ...(options as IViewOptions), sizing: ViewSizing.Flexible }, keybindingService, contextMenuService); - this.menus = instantiationService.createInstance(SCMMenus, provider); + this.menus = instantiationService.createInstance(SCMMenus, repository.provider); this.menus.onDidChangeTitle(this.updateActions, this, this.disposables); } @@ -290,9 +289,9 @@ class SourceControlView extends CollapsibleView { this.disposables.push(attachInputBoxStyler(this.inputBox, this.themeService)); this.disposables.push(this.inputBox); - this.inputBox.value = this.scmService.input.value; - this.inputBox.onDidChange(value => this.scmService.input.value = value, null, this.disposables); - this.scmService.input.onDidChange(value => this.inputBox.value = value, null, this.disposables); + this.inputBox.value = this.repository.input.value; + this.inputBox.onDidChange(value => this.repository.input.value = value, null, this.disposables); + this.repository.input.onDidChange(value => this.inputBox.value = value, null, this.disposables); // this.disposables.push(this.inputBox.onDidHeightChange(() => this.layout())); chain(domEvent(this.inputBox.inputElement, 'keydown')) @@ -301,8 +300,8 @@ class SourceControlView extends CollapsibleView { .on(this.onDidAcceptInput, this, this.disposables); - if (this.provider.onDidChangeCommitTemplate) { - this.provider.onDidChangeCommitTemplate(this.updateInputBox, this, this.disposables); + if (this.repository.provider.onDidChangeCommitTemplate) { + this.repository.provider.onDidChangeCommitTemplate(this.updateInputBox, this, this.disposables); } this.updateInputBox(); @@ -340,7 +339,7 @@ class SourceControlView extends CollapsibleView { this.list.onContextMenu(this.onListContextMenu, this, this.disposables); this.disposables.push(this.list); - this.provider.onDidChange(this.updateList, this, this.disposables); + this.repository.provider.onDidChange(this.updateList, this, this.disposables); this.updateList(); } @@ -365,11 +364,11 @@ class SourceControlView extends CollapsibleView { } getActionsContext(): any { - return this.provider; + return this.repository.provider; } private updateList(): void { - const elements = this.provider.resources + const elements = this.repository.provider.resources .reduce<(ISCMResourceGroup | ISCMResource)[]>((r, g) => [...r, g, ...g.resources.sort(resourceSorter)], []); this.list.splice(0, this.list.length, elements); @@ -414,20 +413,20 @@ class SourceControlView extends CollapsibleView { } private updateInputBox(): void { - if (typeof this.provider.commitTemplate === 'undefined') { + if (typeof this.repository.provider.commitTemplate === 'undefined') { return; } - this.inputBox.value = this.provider.commitTemplate; + this.inputBox.value = this.repository.provider.commitTemplate; } private onDidAcceptInput(): void { - if (!this.provider.acceptInputCommand) { + if (!this.repository.provider.acceptInputCommand) { return; } - const id = this.provider.acceptInputCommand.id; - const args = this.provider.acceptInputCommand.arguments; + const id = this.repository.provider.acceptInputCommand.id; + const args = this.repository.provider.acceptInputCommand.arguments; this.commandService.executeCommand(id, ...args) .done(undefined, onUnexpectedError); @@ -484,13 +483,13 @@ export class SCMViewlet extends ComposedViewsViewlet { telemetryService, storageService, instantiationService, themeService, contextService, contextKeyService, contextMenuService, extensionService); } - private onDidAddProvider(provider: ISCMProvider): void { - const view = new SourceControlViewDescriptor(provider); + private onDidAddRepository(repository: ISCMRepository): void { + const view = new SourceControlViewDescriptor(repository); ViewsRegistry.registerViews([view]); } - private onDidRemoveProvider(provider: ISCMProvider): void { - ViewsRegistry.deregisterViews([provider.id], ViewLocation.SCM); + private onDidRemoveRepository(repository: ISCMRepository): void { + ViewsRegistry.deregisterViews([repository.provider.id], ViewLocation.SCM); } // private onDidProvidersChange(): void { @@ -521,9 +520,9 @@ export class SCMViewlet extends ComposedViewsViewlet { parent.addClass('scm-viewlet'); - this.scmService.onDidAddProvider(this.onDidAddProvider, this, this.disposables); - this.scmService.onDidRemoveProvider(this.onDidRemoveProvider, this, this.disposables); - this.scmService.providers.forEach(p => this.onDidAddProvider(p)); + this.scmService.onDidAddRepository(this.onDidAddRepository, this, this.disposables); + this.scmService.onDidRemoveRepository(this.onDidRemoveRepository, this, this.disposables); + this.scmService.repositories.forEach(p => this.onDidAddRepository(p)); // this.themeService.onThemeChange(this.update, this, this.disposables); // return TPromise.as(null); @@ -531,7 +530,7 @@ export class SCMViewlet extends ComposedViewsViewlet { protected createView(viewDescriptor: IViewDescriptor, options: IViewletViewOptions): IView { if (viewDescriptor instanceof SourceControlViewDescriptor) { - return this.instantiationService.createInstance(SourceControlView, viewDescriptor.provider, options); + return this.instantiationService.createInstance(SourceControlView, viewDescriptor.repository, options); } return this.instantiationService.createInstance(viewDescriptor.ctor, options); diff --git a/src/vs/workbench/services/scm/common/scm.ts b/src/vs/workbench/services/scm/common/scm.ts index 66cc07504cc..06fef1b791b 100644 --- a/src/vs/workbench/services/scm/common/scm.ts +++ b/src/vs/workbench/services/scm/common/scm.ts @@ -61,15 +61,20 @@ export interface ISCMInput { readonly onDidChange: Event; } +export interface ISCMRepository extends IDisposable { + readonly provider: ISCMProvider; + readonly input: ISCMInput; +} + export interface ISCMService { readonly _serviceBrand: any; - readonly onDidAddProvider: Event; - readonly onDidRemoveProvider: Event; - readonly onDidChangeProvider: Event; - readonly providers: ISCMProvider[]; - readonly input: ISCMInput; - activeProvider: ISCMProvider | undefined; + readonly onDidAddRepository: Event; + readonly onDidRemoveRepository: Event; + readonly onDidChangeRepository: Event; - registerSCMProvider(provider: ISCMProvider): IDisposable; + readonly repositories: ISCMRepository[]; + activeRepository: ISCMRepository | undefined; + + registerSCMProvider(provider: ISCMProvider): ISCMRepository; } \ No newline at end of file diff --git a/src/vs/workbench/services/scm/common/scmService.ts b/src/vs/workbench/services/scm/common/scmService.ts index 5313e3e0273..bb0dac7be2a 100644 --- a/src/vs/workbench/services/scm/common/scmService.ts +++ b/src/vs/workbench/services/scm/common/scmService.ts @@ -7,11 +7,10 @@ import { IDisposable, toDisposable, empty as EmptyDisposable, combinedDisposable } from 'vs/base/common/lifecycle'; import Event, { Emitter } from 'vs/base/common/event'; -import { memoize } from 'vs/base/common/decorators'; import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey'; import { IStatusbarService, StatusbarAlignment as MainThreadStatusBarAlignment } from 'vs/platform/statusbar/common/statusbar'; import { IStorageService, StorageScope } from 'vs/platform/storage/common/storage'; -import { ISCMService, ISCMProvider, ISCMInput, DefaultSCMProviderIdStorageKey } from './scm'; +import { ISCMService, ISCMProvider, ISCMInput, ISCMRepository, DefaultSCMProviderIdStorageKey } from './scm'; class SCMInput implements ISCMInput { @@ -30,6 +29,21 @@ class SCMInput implements ISCMInput { get onDidChange(): Event { return this._onDidChange.event; } } +class SCMRepository implements ISCMRepository { + + readonly input: ISCMInput = new SCMInput(); + + constructor( + public readonly provider: ISCMProvider, + private disposable: IDisposable + ) { } + + dispose(): void { + this.disposable.dispose(); + this.provider.dispose(); + } +} + export class SCMService implements ISCMService { _serviceBrand; @@ -37,32 +51,30 @@ export class SCMService implements ISCMService { private activeProviderDisposable: IDisposable = EmptyDisposable; private statusBarDisposable: IDisposable = EmptyDisposable; - private _activeProvider: ISCMProvider | undefined; + private _activeRepository: ISCMRepository | undefined; - get activeProvider(): ISCMProvider | undefined { - return this._activeProvider; + get activeRepository(): ISCMRepository | undefined { + return this._activeRepository; } - set activeProvider(provider: ISCMProvider | undefined) { - this.setActiveSCMProvider(provider); - this.storageService.store(DefaultSCMProviderIdStorageKey, provider.contextValue, StorageScope.WORKSPACE); + set activeRepository(repository: ISCMRepository | undefined) { + this.setActiveSCMProvider(repository); + this.storageService.store(DefaultSCMProviderIdStorageKey, repository.provider.contextValue, StorageScope.WORKSPACE); } private _providerIds = new Set(); - private _providers: ISCMProvider[] = []; - get providers(): ISCMProvider[] { return [...this._providers]; } + private _repositories: ISCMRepository[] = []; + get repositories(): ISCMRepository[] { return [...this._repositories]; } - private _onDidAddProvider = new Emitter(); - get onDidAddProvider(): Event { return this._onDidAddProvider.event; } + private _onDidAddProvider = new Emitter(); + get onDidAddRepository(): Event { return this._onDidAddProvider.event; } - private _onDidRemoveProvider = new Emitter(); - get onDidRemoveProvider(): Event { return this._onDidRemoveProvider.event; } + private _onDidRemoveProvider = new Emitter(); + get onDidRemoveRepository(): Event { return this._onDidRemoveProvider.event; } - private _onDidChangeProvider = new Emitter(); - get onDidChangeProvider(): Event { return this._onDidChangeProvider.event; } + private _onDidChangeProvider = new Emitter(); + get onDidChangeRepository(): Event { return this._onDidChangeProvider.event; } - @memoize - get input(): ISCMInput { return new SCMInput(); } constructor( @IContextKeyService contextKeyService: IContextKeyService, @@ -70,57 +82,62 @@ export class SCMService implements ISCMService { @IStatusbarService private statusbarService: IStatusbarService ) { } - private setActiveSCMProvider(provider: ISCMProvider): void { + private setActiveSCMProvider(repository: ISCMRepository): void { this.activeProviderDisposable.dispose(); - if (!provider) { + if (!repository) { throw new Error('invalid provider'); } - if (provider && this._providers.indexOf(provider) === -1) { + if (repository && this._repositories.indexOf(repository) === -1) { throw new Error('Provider not registered'); } - this._activeProvider = provider; + this._activeRepository = repository; + const provider = repository.provider; this.activeProviderDisposable = provider.onDidChange(() => this.onDidProviderChange(provider)); this.onDidProviderChange(provider); - this._onDidChangeProvider.fire(provider); + this._onDidChangeProvider.fire(repository); } - registerSCMProvider(provider: ISCMProvider): IDisposable { + registerSCMProvider(provider: ISCMProvider): ISCMRepository { if (this._providerIds.has(provider.id)) { throw new Error(`SCM Provider ${provider.id} already exists.`); } this._providerIds.add(provider.id); - this._providers.push(provider); - const defaultProviderId = this.storageService.get(DefaultSCMProviderIdStorageKey, StorageScope.WORKSPACE); - - if (this._providers.length === 1 || defaultProviderId === provider.contextValue) { - this.setActiveSCMProvider(provider); - } - - this._onDidAddProvider.fire(provider); - - return toDisposable(() => { - const index = this._providers.indexOf(provider); + const disposable = toDisposable(() => { + const index = this._repositories.indexOf(repository); if (index < 0) { return; } this._providerIds.delete(provider.id); - this._providers.splice(index, 1); + this._repositories.splice(index, 1); - if (this.activeProvider === provider) { - this.activeProvider = this._providers[0]; + if (this.activeRepository === repository) { + this.activeRepository = this._repositories[0]; } - this._onDidRemoveProvider.fire(provider); + this._onDidRemoveProvider.fire(repository); }); + + const repository = new SCMRepository(provider, disposable); + this._repositories.push(repository); + + const defaultProviderId = this.storageService.get(DefaultSCMProviderIdStorageKey, StorageScope.WORKSPACE); + + if (this._repositories.length === 1 || defaultProviderId === provider.contextValue) { + this.setActiveSCMProvider(repository); + } + + this._onDidAddProvider.fire(repository); + + return repository; } private onDidProviderChange(provider: ISCMProvider): void {