From 2ff5371883a9620260bdce23d01fbc6cb8395309 Mon Sep 17 00:00:00 2001 From: Joao Moreno Date: Wed, 30 Nov 2016 10:17:25 +0100 Subject: [PATCH] MainThreadSCMProvider --- src/vs/workbench/api/node/mainThreadSCM.ts | 76 +++++++++++++---- .../parts/git/browser/gitSCMProvider.ts | 2 +- .../parts/git/common/gitContentProvider.ts | 81 ------------------- .../parts/scm/browser/dirtydiffDecorator.ts | 8 +- .../workbench/parts/scm/browser/scmViewlet.ts | 3 +- src/vs/workbench/services/scm/common/scm.ts | 6 +- .../services/scm/common/scmService.ts | 41 +++++----- 7 files changed, 95 insertions(+), 122 deletions(-) delete mode 100644 src/vs/workbench/parts/git/common/gitContentProvider.ts diff --git a/src/vs/workbench/api/node/mainThreadSCM.ts b/src/vs/workbench/api/node/mainThreadSCM.ts index 3e8cfff9a30..c20d0ca582f 100644 --- a/src/vs/workbench/api/node/mainThreadSCM.ts +++ b/src/vs/workbench/api/node/mainThreadSCM.ts @@ -4,38 +4,77 @@ *--------------------------------------------------------------------------------------------*/ 'use strict'; -import { IDisposable, dispose, combinedDisposable } from 'vs/base/common/lifecycle'; +import { TPromise } from 'vs/base/common/winjs.base'; +import URI from 'vs/base/common/uri'; +import Event from 'vs/base/common/event'; +import { IDisposable, dispose } from 'vs/base/common/lifecycle'; import { IThreadService } from 'vs/workbench/services/thread/common/threadService'; -import { ISCMService } from 'vs/workbench/services/scm/common/scm'; +import { ISCMService, ISCMProvider, ISCMResourceGroup, ISCMResource } from 'vs/workbench/services/scm/common/scm'; +import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { ExtHostContext, MainThreadSCMShape, ExtHostSCMShape } from './extHost.protocol'; +interface Supports { + originalResource: boolean; +} + +class MainThreadSCMProvider implements ISCMProvider { + + get id(): string { return this._id; } + readonly onChange: Event; + readonly resourceGroups: ISCMResourceGroup[] = []; + private disposables: IDisposable[] = []; + + constructor( + private _id: string, + private proxy: ExtHostSCMShape, + private supports: Supports, + @ISCMService scmService: ISCMService + ) { + this.disposables.push(scmService.registerSCMProvider(this)); + } + + commit(message: string): TPromise { + return TPromise.wrapError('commit not implemented'); + } + + open(uri: ISCMResource): TPromise { + return TPromise.wrapError('open not implemented'); + } + + drag(from: ISCMResource, to: ISCMResource): TPromise { + return TPromise.wrapError('drag not implemented'); + } + + getOriginalResource(uri: URI): TPromise { + if (!this.supports.originalResource) { + return TPromise.as(null); + } + + return this.proxy.$getBaselineResource(this.id, uri); + } + + dispose(): void { + this.disposables = dispose(this.disposables); + } +} + export class MainThreadSCM extends MainThreadSCMShape { - private toDispose: IDisposable; private proxy: ExtHostSCMShape; private providers: { [id: string]: IDisposable; } = Object.create(null); constructor( @IThreadService threadService: IThreadService, - @ISCMService private scmService: ISCMService + @IInstantiationService private instantiationService: IInstantiationService ) { super(); - this.proxy = threadService.get(ExtHostContext.ExtHostSCM); } $register(id: string, registerOriginalResourceProvider: boolean): void { - const disposables = []; - - if (registerOriginalResourceProvider) { - const baselineProvider = this.scmService.registerBaselineResourceProvider({ - getBaselineResource: uri => this.proxy.$getBaselineResource(id, uri) - }); - - disposables.push(baselineProvider); - } - - this.providers[id] = combinedDisposable(disposables); + this.providers[id] = this.instantiationService.createInstance(MainThreadSCMProvider, id, this.proxy, { + originalResource: registerOriginalResourceProvider + }); } $unregister(id: string): void { @@ -50,6 +89,9 @@ export class MainThreadSCM extends MainThreadSCMShape { } dispose(): void { - this.toDispose = dispose(this.toDispose); + Object.keys(this.providers) + .forEach(id => this.providers[id].dispose()); + + this.providers = Object.create(null); } } diff --git a/src/vs/workbench/parts/git/browser/gitSCMProvider.ts b/src/vs/workbench/parts/git/browser/gitSCMProvider.ts index 056d2f4918f..a8771c8170b 100644 --- a/src/vs/workbench/parts/git/browser/gitSCMProvider.ts +++ b/src/vs/workbench/parts/git/browser/gitSCMProvider.ts @@ -64,6 +64,6 @@ export class GitSCMProvider extends SCMProvider { } getOriginalResource(uri: URI): TPromise { - return TPromise.wrapError('not implemented'); + return TPromise.wrapError('getOriginalResource not implemented'); } } \ No newline at end of file diff --git a/src/vs/workbench/parts/git/common/gitContentProvider.ts b/src/vs/workbench/parts/git/common/gitContentProvider.ts deleted file mode 100644 index c526d6ec578..00000000000 --- a/src/vs/workbench/parts/git/common/gitContentProvider.ts +++ /dev/null @@ -1,81 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ -'use strict'; - -import { IModelService } from 'vs/editor/common/services/modelService'; -import URI from 'vs/base/common/uri'; -import { dispose } from 'vs/base/common/lifecycle'; -import * as paths from 'vs/base/common/paths'; -import { Throttler } from 'vs/base/common/async'; -import { TPromise } from 'vs/base/common/winjs.base'; -import { IModel } from 'vs/editor/common/editorCommon'; -import { ITextModelResolverService, ITextModelContentProvider } from 'vs/editor/common/services/resolverService'; -import { IBaselineResourceProvider, ISCMService } from 'vs/workbench/services/scm/common/scm'; -import { IGitService, StatusType, ServiceEvents, ServiceOperations, ServiceState } from 'vs/workbench/parts/git/common/git'; -import { IWorkbenchContribution } from 'vs/workbench/common/contributions'; - -export class GitContentProvider implements IWorkbenchContribution, ITextModelContentProvider, IBaselineResourceProvider { - - constructor( - @ITextModelResolverService textModelResolverService: ITextModelResolverService, - @IModelService private modelService: IModelService, - @ISCMService private scmService: ISCMService, - @IGitService private gitService: IGitService - ) { - this.scmService.registerBaselineResourceProvider(this); - textModelResolverService.registerTextModelContentProvider('git-index', this); - } - - getBaselineResource(resource: URI): TPromise { - return TPromise.as(resource.with({ scheme: 'git-index' })); - } - - provideTextContent(uri: URI): TPromise { - const model = this.modelService.createModel('', null, uri); - const throttler = new Throttler(); - - const updateModel = () => { - const gitModel = this.gitService.getModel(); - const root = gitModel.getRepositoryRoot(); - - if (!root) { - return TPromise.as(null); - } - - const path = uri.fsPath; - const relativePath = paths.relative(root, path); - const treeish = gitModel.getStatus().find(relativePath, StatusType.INDEX) ? '~' : 'HEAD'; - - return this.gitService.buffer(path, treeish) - .then(contents => model.setValue(contents || '')); - }; - - const triggerModelUpdate = () => { - if (this.gitService.getState() !== ServiceState.OK) { - return; - } - - throttler.queue(updateModel); - }; - - const disposables = [ - this.gitService.addListener2(ServiceEvents.STATE_CHANGED, triggerModelUpdate), - this.gitService.addListener2(ServiceEvents.OPERATION_END, e => { - if (e.operation.id !== ServiceOperations.BACKGROUND_FETCH) { - triggerModelUpdate(); - } - }) - ]; - - model.onWillDispose(() => dispose(disposables)); - triggerModelUpdate(); - - return TPromise.as(model); - } - - getId(): string { - return 'git.contentprovider'; - } -} \ No newline at end of file diff --git a/src/vs/workbench/parts/scm/browser/dirtydiffDecorator.ts b/src/vs/workbench/parts/scm/browser/dirtydiffDecorator.ts index e59e7aa64d6..87f64551342 100644 --- a/src/vs/workbench/parts/scm/browser/dirtydiffDecorator.ts +++ b/src/vs/workbench/parts/scm/browser/dirtydiffDecorator.ts @@ -114,7 +114,13 @@ class DirtyDiffModelDecorator { return this._originalURIPromise; } - this._originalURIPromise = this.scmService.getBaselineResource(this.uri) + const provider = this.scmService.activeProvider; + + if (!provider) { + return winjs.TPromise.as(null); + } + + this._originalURIPromise = provider.getOriginalResource(this.uri) .then(originalUri => { if (!originalUri) { return null; diff --git a/src/vs/workbench/parts/scm/browser/scmViewlet.ts b/src/vs/workbench/parts/scm/browser/scmViewlet.ts index e76e93a022f..9b350cb6d2e 100644 --- a/src/vs/workbench/parts/scm/browser/scmViewlet.ts +++ b/src/vs/workbench/parts/scm/browser/scmViewlet.ts @@ -137,7 +137,8 @@ export class SCMViewlet extends Viewlet { super(VIEWLET_ID, telemetryService); // TODO@Joao - scmService.activeProvider = instantiationService.createInstance(GitSCMProvider); + const provider = instantiationService.createInstance(GitSCMProvider); + scmService.registerSCMProvider(provider); this.menus = this.instantiationService.createInstance(SCMMenus); this.disposables.push(this.menus); diff --git a/src/vs/workbench/services/scm/common/scm.ts b/src/vs/workbench/services/scm/common/scm.ts index 648c1dfa3b1..2382eaf1c44 100644 --- a/src/vs/workbench/services/scm/common/scm.ts +++ b/src/vs/workbench/services/scm/common/scm.ts @@ -42,8 +42,8 @@ export interface ISCMProvider extends IDisposable { export interface ISCMService { _serviceBrand: any; - activeProvider: ISCMProvider; + activeProvider: ISCMProvider | undefined; + onDidChangeProvider: Event; - getBaselineResource(resource: URI): TPromise; - registerBaselineResourceProvider(provider: IBaselineResourceProvider): IDisposable; + registerSCMProvider(provider: ISCMProvider): IDisposable; } \ 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 c2463ff370f..1f8d62785e8 100644 --- a/src/vs/workbench/services/scm/common/scmService.ts +++ b/src/vs/workbench/services/scm/common/scmService.ts @@ -5,19 +5,21 @@ 'use strict'; -import { TPromise } from 'vs/base/common/winjs.base'; -import URI from 'vs/base/common/uri'; import { IDisposable, toDisposable } from 'vs/base/common/lifecycle'; +import Event, { Emitter } from 'vs/base/common/event'; import { IContextKeyService, IContextKey } from 'vs/platform/contextkey/common/contextkey'; -import { ISCMService, IBaselineResourceProvider, ISCMProvider } from './scm'; +import { ISCMService, ISCMProvider } from './scm'; export class SCMService implements ISCMService { _serviceBrand; private activeProviderContextKey: IContextKey; - private providers: IBaselineResourceProvider[] = []; - private _activeProvider: ISCMProvider; + private providers: ISCMProvider[] = []; + private _activeProvider: ISCMProvider | undefined; + + private _onDidChangeProvider = new Emitter(); + get onDidChangeProvider(): Event { return this._onDidChangeProvider.event; } constructor( @IContextKeyService private contextKeyService: IContextKeyService @@ -25,28 +27,27 @@ export class SCMService implements ISCMService { this.activeProviderContextKey = contextKeyService.createKey('scm.provider', void 0); } - get activeProvider(): ISCMProvider { + get activeProvider(): ISCMProvider | undefined { return this._activeProvider; } set activeProvider(provider: ISCMProvider) { + if (provider && this.providers.indexOf(provider) === -1) { + throw new Error('Provider not registered'); + } + this._activeProvider = provider; - this.activeProviderContextKey.set(provider.id); + this.activeProviderContextKey.set(provider ? provider.id : void 0); + this._onDidChangeProvider.fire(provider); } - getBaselineResource(resource: URI): TPromise { - const promises = this.providers - .map(p => p.getBaselineResource(resource)); - - return TPromise.join(promises).then(originalResources => { - // TODO@Joao: just take the first - return originalResources.filter(uri => !!uri)[0]; - }); - } - - registerBaselineResourceProvider(provider: IBaselineResourceProvider): IDisposable { + registerSCMProvider(provider: ISCMProvider): IDisposable { this.providers = [provider, ...this.providers]; + if (this.providers.length === 1) { + this.activeProvider = provider; + } + return toDisposable(() => { const index = this.providers.indexOf(provider); @@ -55,6 +56,10 @@ export class SCMService implements ISCMService { } this.providers.splice(index, 1); + + if (this.activeProvider === provider) { + this.activeProvider = this.providers[0]; + } }); } } \ No newline at end of file