From 06b160e34ee28a7134d2287b19be01369ea1d56a Mon Sep 17 00:00:00 2001 From: Joao Moreno Date: Wed, 30 Nov 2016 11:24:41 +0100 Subject: [PATCH] MainThreadSCMProvider.$onChange --- src/vs/vscode.proposed.d.ts | 7 ++- src/vs/workbench/api/node/extHost.protocol.ts | 6 ++ src/vs/workbench/api/node/extHostSCM.ts | 42 +++++++++++--- src/vs/workbench/api/node/mainThreadSCM.ts | 55 ++++++++++++++----- .../services/scm/common/scmProvider.ts | 6 +- 5 files changed, 87 insertions(+), 29 deletions(-) diff --git a/src/vs/vscode.proposed.d.ts b/src/vs/vscode.proposed.d.ts index 10e4ec84da4..872bbc6018f 100644 --- a/src/vs/vscode.proposed.d.ts +++ b/src/vs/vscode.proposed.d.ts @@ -88,10 +88,12 @@ declare module 'vscode' { export interface SCMResource { uri: Uri; + resourceGroup: string; } export interface SCMResourceGroup { - resources: SCMResource[]; + id: string; + label: string; } export interface SCMProvider { @@ -99,7 +101,8 @@ declare module 'vscode' { clickCommand?: string; dragCommand?: string; resourceGroups: SCMResourceGroup[]; - onDidChangeResourceGroup: Event; + + onDidChange: Event; getOriginalResource?(uri: Uri, token: CancellationToken): ProviderResult; } diff --git a/src/vs/workbench/api/node/extHost.protocol.ts b/src/vs/workbench/api/node/extHost.protocol.ts index ce8f1621ba9..7251cc8e26e 100644 --- a/src/vs/workbench/api/node/extHost.protocol.ts +++ b/src/vs/workbench/api/node/extHost.protocol.ts @@ -232,12 +232,18 @@ export interface SCMProviderFeatures { commitCommand?: string; clickCommand?: string; dragCommand?: string; + resourceGroups: vscode.SCMResourceGroup[]; supportsOriginalResource: boolean; } +export interface SCMRawResource { + uri: string; +} + export abstract class MainThreadSCMShape { $register(id: string, features: SCMProviderFeatures): void { throw ni(); } $unregister(id: string): void { throw ni(); } + $onChange(id: string, resources: SCMRawResource[][]): void { throw ni(); } } // -- extension host diff --git a/src/vs/workbench/api/node/extHostSCM.ts b/src/vs/workbench/api/node/extHostSCM.ts index 31356b24640..473ee115993 100644 --- a/src/vs/workbench/api/node/extHostSCM.ts +++ b/src/vs/workbench/api/node/extHostSCM.ts @@ -6,29 +6,30 @@ import URI from 'vs/base/common/uri'; import { TPromise } from 'vs/base/common/winjs.base'; -import Event, { Emitter } from 'vs/base/common/event'; +import Event, { Emitter, debounceEvent } from 'vs/base/common/event'; +import { index } from 'vs/base/common/arrays'; import { asWinJsPromise } from 'vs/base/common/async'; import { IThreadService } from 'vs/workbench/services/thread/common/threadService'; -import { SCMProvider } from 'vscode'; import { Disposable } from 'vs/workbench/api/node/extHostTypes'; -import { MainContext, MainThreadSCMShape } from './extHost.protocol'; +import { MainContext, MainThreadSCMShape, SCMRawResource } from './extHost.protocol'; +import * as vscode from 'vscode'; export class ExtHostSCM { private _proxy: MainThreadSCMShape; - private _providers: { [id: string]: SCMProvider; } = Object.create(null); + private _providers: { [id: string]: vscode.SCMProvider; } = Object.create(null); - private _onDidChangeActiveProvider = new Emitter(); - get onDidChangeActiveProvider(): Event { return this._onDidChangeActiveProvider.event; } + private _onDidChangeActiveProvider = new Emitter(); + get onDidChangeActiveProvider(): Event { return this._onDidChangeActiveProvider.event; } - private _activeProvider: SCMProvider; - get activeProvider(): SCMProvider | undefined { return this._activeProvider; } + private _activeProvider: vscode.SCMProvider; + get activeProvider(): vscode.SCMProvider | undefined { return this._activeProvider; } constructor(threadService: IThreadService) { this._proxy = threadService.get(MainContext.MainThreadSCM); } - registerSCMProvider(id: string, provider: SCMProvider): Disposable { + registerSCMProvider(id: string, provider: vscode.SCMProvider): Disposable { if (this._providers[id]) { throw new Error(`Provider ${id} already registered`); } @@ -36,14 +37,37 @@ export class ExtHostSCM { // TODO@joao: should pluck all the things out of the provider this._providers[id] = provider; + const resourceGroupsIds = provider.resourceGroups.map(g => g.id); + this._proxy.$register(id, { commitCommand: provider.commitCommand, clickCommand: provider.clickCommand, dragCommand: provider.dragCommand, + resourceGroups: provider.resourceGroups, supportsOriginalResource: !!provider.getOriginalResource }); + const onDidChange = debounceEvent(provider.onDidChange, (l, e) => e, 200); + const onDidChangeListener = onDidChange(resources => { + const resourceGroupsById = index(resourceGroupsIds, id => id, () => [] as SCMRawResource[]); + + resources.forEach(resource => { + const resourceGroup = resourceGroupsById[resource.resourceGroup]; + + if (!resourceGroup) { + // TODO@Joao: ask Joh: should we warn? should we throw? + return; + } + + resourceGroup.push({ uri: resource.uri.toString() }); + }); + + const result = resourceGroupsIds.map(id => resourceGroupsById[id]); + this._proxy.$onChange(id, result); + }); + return new Disposable(() => { + onDidChangeListener.dispose(); delete this._providers[id]; this._proxy.$unregister(id); }); diff --git a/src/vs/workbench/api/node/mainThreadSCM.ts b/src/vs/workbench/api/node/mainThreadSCM.ts index 6237a0512f4..8deb73adc1c 100644 --- a/src/vs/workbench/api/node/mainThreadSCM.ts +++ b/src/vs/workbench/api/node/mainThreadSCM.ts @@ -6,32 +6,29 @@ import { TPromise } from 'vs/base/common/winjs.base'; import URI from 'vs/base/common/uri'; -import Event, { Emitter } from 'vs/base/common/event'; -import { IDisposable, dispose } from 'vs/base/common/lifecycle'; +import { dispose } from 'vs/base/common/lifecycle'; import { IThreadService } from 'vs/workbench/services/thread/common/threadService'; -import { ISCMService, ISCMProvider, ISCMResourceGroup, ISCMResource } from 'vs/workbench/services/scm/common/scm'; +import { ISCMService, ISCMProvider, ISCMResource } 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 } from './extHost.protocol'; +import { ExtHostContext, MainThreadSCMShape, ExtHostSCMShape, SCMProviderFeatures, SCMRawResource } from './extHost.protocol'; +import { SCMProvider } from 'vs/workbench/services/scm/common/scmProvider'; -class MainThreadSCMProvider implements ISCMProvider { - - get id(): string { return this._id; } - - private _onChange = new Emitter(); - get onChange(): Event { return this._onChange.event; } - - readonly resourceGroups: ISCMResourceGroup[] = []; - private disposables: IDisposable[] = []; +class MainThreadSCMProvider extends SCMProvider { constructor( - private _id: string, + id: string, private proxy: ExtHostSCMShape, private features: SCMProviderFeatures, @ISCMService scmService: ISCMService, @ICommandService private commandService: ICommandService ) { + super(id, 'Ext Host SCM Provider'); + scmService.onDidChangeProvider(this.onDidChangeProvider, this, this.disposables); this.disposables.push(scmService.registerSCMProvider(this)); + + features.resourceGroups + .forEach(resourceGroup => this.createResourceGroup(resourceGroup.id, resourceGroup.label)); } commit(message: string): TPromise { @@ -72,6 +69,24 @@ class MainThreadSCMProvider implements ISCMProvider { return this.proxy.$getOriginalResource(this.id, uri); } + private onDidChangeProvider(provider: ISCMProvider): void { + // if (provider === this) { + // return + // } + } + + $onChange(raw: SCMRawResource[][]): void { + if (raw.length !== this.resourceGroups.length) { + throw new Error('bad on change'); + } + + raw.forEach((group, index) => { + const resourceGroup = this.resourceGroups[index]; + const resources = group.map(raw => ({ uri: URI.parse(raw.uri) })); + resourceGroup.set(...resources); + }); + } + dispose(): void { this.disposables = dispose(this.disposables); } @@ -80,7 +95,7 @@ class MainThreadSCMProvider implements ISCMProvider { export class MainThreadSCM extends MainThreadSCMShape { private proxy: ExtHostSCMShape; - private providers: { [id: string]: IDisposable; } = Object.create(null); + private providers: { [id: string]: MainThreadSCMProvider; } = Object.create(null); constructor( @IThreadService threadService: IThreadService, @@ -105,6 +120,16 @@ export class MainThreadSCM extends MainThreadSCMShape { delete this.providers[id]; } + $onChange(id: string, resources: SCMRawResource[][]): void { + const provider = this.providers[id]; + + if (!provider) { + return; + } + + provider.$onChange(resources); + } + dispose(): void { Object.keys(this.providers) .forEach(id => this.providers[id].dispose()); diff --git a/src/vs/workbench/services/scm/common/scmProvider.ts b/src/vs/workbench/services/scm/common/scmProvider.ts index 7af6b052e50..353bd728b77 100644 --- a/src/vs/workbench/services/scm/common/scmProvider.ts +++ b/src/vs/workbench/services/scm/common/scmProvider.ts @@ -52,9 +52,9 @@ export abstract class SCMProvider implements ISCMProvider { private onResourceGroupsChange = new Emitter(); private _resourceGroups: ResourceGroup[] = []; - get resourceGroups(): ISCMResourceGroup[] { return this._resourceGroups; } + get resourceGroups(): ResourceGroup[] { return this._resourceGroups; } - private disposables: IDisposable[] = []; + protected disposables: IDisposable[] = []; get id(): string { return this._id; } get label(): string { return this._label; } @@ -63,7 +63,7 @@ export abstract class SCMProvider implements ISCMProvider { } - createResourceGroup(id: string, label: string): ISCMResourceGroup { + protected createResourceGroup(id: string, label: string): ISCMResourceGroup { const resourceGroup = new ResourceGroup(id, label); this._resourceGroups.push(resourceGroup); const onChangeListener = this._onChange.add(resourceGroup.onChange);