diff --git a/extensions/git/src/commands.ts b/extensions/git/src/commands.ts index f13a85f3a0e..ee76d643332 100644 --- a/extensions/git/src/commands.ts +++ b/extensions/git/src/commands.ts @@ -794,7 +794,7 @@ export class CommandCenter { if (uri.scheme === 'git-resource') { const {resourceGroupId} = JSON.parse(uri.query) as { resourceGroupId: string, sourceUri: string }; - const [resourceGroup] = this.model.resources.filter(g => g.id === resourceGroupId); + const [resourceGroup] = this.model.resources.filter(g => g.contextKey === resourceGroupId); if (!resourceGroup) { return; diff --git a/extensions/git/src/model.ts b/extensions/git/src/model.ts index c192512c123..ed2e984daff 100644 --- a/extensions/git/src/model.ts +++ b/extensions/git/src/model.ts @@ -150,9 +150,9 @@ export class Resource implements SCMResource { export class ResourceGroup implements SCMResourceGroup { @memoize - get uri(): Uri { return Uri.parse(`git-resource-group:${this.id}`); } + get uri(): Uri { return Uri.parse(`git-resource-group:${this.contextKey}`); } - get id(): string { return this._id; } + get contextKey(): string { return this._id; } get label(): string { return this._label; } get resources(): Resource[] { return this._resources; } diff --git a/extensions/git/src/scmProvider.ts b/extensions/git/src/scmProvider.ts index c0672088771..2464724b031 100644 --- a/extensions/git/src/scmProvider.ts +++ b/extensions/git/src/scmProvider.ts @@ -14,7 +14,7 @@ export class GitSCMProvider implements SCMProvider { private disposables: Disposable[] = []; - get id(): string { return 'git'; } + get contextKey(): string { return 'git'; } get resources(): SCMResourceGroup[] { return this.model.resources; } get onDidChange(): Event { diff --git a/src/vs/vscode.proposed.d.ts b/src/vs/vscode.proposed.d.ts index 086ac731526..9ec2b992a07 100644 --- a/src/vs/vscode.proposed.d.ts +++ b/src/vs/vscode.proposed.d.ts @@ -656,17 +656,17 @@ declare module 'vscode' { */ readonly uri: Uri; - /** - * The identifier of the SCM resource group, which will be used to populate - * the value of the `scmResourceGroup` context key. - */ - readonly id: string; - /** * The UI label of the SCM resource group. */ readonly label: string; + /** + * The context key of the SCM resource group, which will be used to populate + * the value of the `scmResourceGroup` context key. + */ + readonly contextKey?: string; + /** * The collection of [SCM resources](#SCMResource) within the SCM resource group. */ @@ -679,17 +679,17 @@ declare module 'vscode' { */ export interface SCMProvider { - /** - * The identifier of the SCM provider, which will be used to populate - * the value of the `scmProvider` context key. - */ - readonly id: string; - /** * A human-readable label for the name of the SCM Provider. */ readonly label: string; + /** + * The context key of the SCM provider, which will be used to populate + * the value of the `scmProvider` context key. + */ + readonly contextKey?: string; + /** * The list of SCM resource groups. */ diff --git a/src/vs/workbench/api/node/extHost.protocol.ts b/src/vs/workbench/api/node/extHost.protocol.ts index dbb5bdf0dc8..d6ddc18254e 100644 --- a/src/vs/workbench/api/node/extHost.protocol.ts +++ b/src/vs/workbench/api/node/extHost.protocol.ts @@ -252,6 +252,7 @@ export abstract class MainProcessExtensionServiceShape { export interface SCMProviderFeatures { label: string; + contextKey?: string; supportsOpen: boolean; supportsOriginalResource: boolean; } @@ -265,15 +266,15 @@ export type SCMRawResource = [ export type SCMRawResourceGroup = [ string /*uri*/, - string /*id*/, + string | undefined /*context key*/, string /*label*/, SCMRawResource[] ]; export abstract class MainThreadSCMShape { - $register(id: string, features: SCMProviderFeatures): void { throw ni(); } - $unregister(id: string): void { throw ni(); } - $onChange(id: string, resources: SCMRawResourceGroup[], count: number | undefined, state: string | undefined): void { throw ni(); } + $register(handle: number, features: SCMProviderFeatures): void { throw ni(); } + $unregister(handle: number): void { throw ni(); } + $onChange(handle: number, resources: SCMRawResourceGroup[], count: number | undefined, state: string | undefined): void { throw ni(); } $setInputBoxValue(value: string): void { throw ni(); } } @@ -417,8 +418,8 @@ export abstract class ExtHostTerminalServiceShape { } export abstract class ExtHostSCMShape { - $open(id: string, uri: string): TPromise { throw ni(); } - $getOriginalResource(id: string, uri: URI): TPromise { throw ni(); } + $open(handle: number, uri: string): TPromise { throw ni(); } + $getOriginalResource(handle: number, uri: URI): TPromise { throw ni(); } $onInputBoxValueChange(value: string): TPromise { throw ni(); } $onInputBoxAcceptChanges(): TPromise { throw ni(); } } diff --git a/src/vs/workbench/api/node/extHostSCM.ts b/src/vs/workbench/api/node/extHostSCM.ts index 45dd58b3603..7ee64fab3c9 100644 --- a/src/vs/workbench/api/node/extHostSCM.ts +++ b/src/vs/workbench/api/node/extHostSCM.ts @@ -24,12 +24,6 @@ function getIconPath(decorations: vscode.SCMResourceThemableDecorations) { return undefined; } -export interface Cache { - [providerId: string]: { - [resourceUri: string]: vscode.SCMResource; - }; -} - class ExtHostSCMInputBox { private _value: string = ''; @@ -73,10 +67,15 @@ class ExtHostSCMInputBox { } } +type ProviderHandle = number; + export class ExtHostSCM { + private static _handlePool: number = 0; + private _proxy: MainThreadSCMShape; - private _providers: { [id: string]: vscode.SCMProvider; } = Object.create(null); + private _providers: Map = new Map(); + private _cache: Map> = new Map>(); private _onDidChangeActiveProvider = new Emitter(); get onDidChangeActiveProvider(): Event { return this._onDidChangeActiveProvider.event; } @@ -87,37 +86,32 @@ export class ExtHostSCM { private _inputBox: ExtHostSCMInputBox; get inputBox(): vscode.SCMInputBox { return this._inputBox; } - private cache: Cache = Object.create(null); - constructor(threadService: IThreadService) { this._proxy = threadService.get(MainContext.MainThreadSCM); this._inputBox = new ExtHostSCMInputBox(this._proxy); } registerSCMProvider(provider: vscode.SCMProvider): Disposable { - const providerId = provider.id; + const handle = ExtHostSCM._handlePool++; - if (this._providers[providerId]) { - throw new Error(`Provider ${providerId} already registered`); - } + this._providers.set(handle, provider); - // TODO@joao: should pluck all the things out of the provider - this._providers[providerId] = provider; - - this._proxy.$register(providerId, { + this._proxy.$register(handle, { label: provider.label, + contextKey: provider.contextKey, supportsOpen: !!provider.open, supportsOriginalResource: !!provider.getOriginalResource }); const onDidChange = debounceEvent(provider.onDidChange, (l, e) => e, 100); const onDidChangeListener = onDidChange(resourceGroups => { - this.cache[providerId] = Object.create(null); + const cache = new Map(); + this._cache.set(handle, cache); const rawResourceGroups = resourceGroups.map(g => { const rawResources = g.resources.map(r => { const uri = r.uri.toString(); - this.cache[providerId][uri] = r; + cache.set(uri, r); const sourceUri = r.sourceUri.toString(); const iconPath = getIconPath(r.decorations); @@ -138,27 +132,33 @@ export class ExtHostSCM { return [uri, sourceUri, icons, strikeThrough] as SCMRawResource; }); - return [g.uri.toString(), g.id, g.label, rawResources] as SCMRawResourceGroup; + return [g.uri.toString(), g.contextKey, g.label, rawResources] as SCMRawResourceGroup; }); - this._proxy.$onChange(providerId, rawResourceGroups, provider.count, provider.state); + this._proxy.$onChange(handle, rawResourceGroups, provider.count, provider.state); }); return new Disposable(() => { onDidChangeListener.dispose(); - delete this._providers[providerId]; - this._proxy.$unregister(providerId); + this._providers.delete(handle); + this._proxy.$unregister(handle); }); } - $open(providerId: string, uri: string): TPromise { - const provider = this._providers[providerId]; + $open(handle: number, uri: string): TPromise { + const provider = this._providers.get(handle); if (!provider) { return TPromise.as(null); } - const resource = this.cache[providerId][uri]; + const cache = this._cache.get(handle); + + if (!cache) { + return TPromise.as(null); + } + + const resource = cache.get(uri); if (!resource) { return TPromise.as(null); @@ -167,8 +167,8 @@ export class ExtHostSCM { return asWinJsPromise(token => provider.open(resource, token)); } - $getOriginalResource(id: string, uri: URI): TPromise { - const provider = this._providers[id]; + $getOriginalResource(handle: number, uri: URI): TPromise { + const provider = this._providers.get(handle); if (!provider) { return TPromise.as(null); diff --git a/src/vs/workbench/api/node/mainThreadSCM.ts b/src/vs/workbench/api/node/mainThreadSCM.ts index 6bf13fcdcd5..30feeea44bd 100644 --- a/src/vs/workbench/api/node/mainThreadSCM.ts +++ b/src/vs/workbench/api/node/mainThreadSCM.ts @@ -24,8 +24,9 @@ class MainThreadSCMProvider implements ISCMProvider { private disposables: IDisposable[] = []; - get id(): string { return this._id; } + get handle(): number { return this._handle; } get label(): string { return this.features.label; } + get contextKey(): string { return this.features.contextKey; } private _count: number | undefined = undefined; get count(): number | undefined { return this._count; } @@ -34,7 +35,7 @@ class MainThreadSCMProvider implements ISCMProvider { get state(): string | undefined { return this._state; } constructor( - private _id: string, + private _handle: number, private proxy: ExtHostSCMShape, private features: SCMProviderFeatures, @ISCMService scmService: ISCMService, @@ -49,7 +50,7 @@ class MainThreadSCMProvider implements ISCMProvider { return TPromise.as(null); } - return this.proxy.$open(this.id, resource.uri.toString()); + return this.proxy.$open(this.handle, resource.uri.toString()); } getOriginalResource(uri: URI): TPromise { @@ -57,7 +58,7 @@ class MainThreadSCMProvider implements ISCMProvider { return TPromise.as(null); } - return this.proxy.$getOriginalResource(this.id, uri); + return this.proxy.$getOriginalResource(this.handle, uri); } private onDidChangeProvider(provider: ISCMProvider): void { @@ -68,29 +69,29 @@ class MainThreadSCMProvider implements ISCMProvider { $onChange(rawResourceGroups: SCMRawResourceGroup[], count: number | undefined, state: string | undefined): void { this._resources = rawResourceGroups.map(rawGroup => { - const [uri, id, label, rawResources] = rawGroup; + const [uri, contextKey, label, rawResources] = rawGroup; + const resources: ISCMResource[] = []; + const group: ISCMResourceGroup = { uri: URI.parse(uri), contextKey, label, resources }; - const resources = rawResources.map(rawResource => { + rawResources.forEach(rawResource => { const [uri, sourceUri, icons, strikeThrough] = rawResource; - const icon = icons[0]; const iconDark = icons[1] || icon; - const decorations = { icon: icon && URI.parse(icon), iconDark: iconDark && URI.parse(iconDark), strikeThrough }; - return { - resourceGroupId: id, + resources.push({ + resourceGroup: group, uri: URI.parse(uri), sourceUri: URI.parse(sourceUri), decorations - }; + }); }); - return { uri: URI.parse(uri), id, label, resources }; + return group; }); this._count = count; @@ -107,7 +108,7 @@ class MainThreadSCMProvider implements ISCMProvider { export class MainThreadSCM extends MainThreadSCMShape { private proxy: ExtHostSCMShape; - private providers: { [id: string]: MainThreadSCMProvider; } = Object.create(null); + private providers: { [handle: number]: MainThreadSCMProvider; } = Object.create(null); private inputBoxListeners: IDisposable[] = []; constructor( @@ -122,23 +123,23 @@ export class MainThreadSCM extends MainThreadSCMShape { this.scmService.input.onDidAccept(this.proxy.$onInputBoxAcceptChanges, this.proxy, this.inputBoxListeners); } - $register(id: string, features: SCMProviderFeatures): void { - this.providers[id] = this.instantiationService.createInstance(MainThreadSCMProvider, id, this.proxy, features); + $register(handle: number, features: SCMProviderFeatures): void { + this.providers[handle] = this.instantiationService.createInstance(MainThreadSCMProvider, handle, this.proxy, features); } - $unregister(id: string): void { - const provider = this.providers[id]; + $unregister(handle: number): void { + const provider = this.providers[handle]; if (!provider) { return; } provider.dispose(); - delete this.providers[id]; + delete this.providers[handle]; } - $onChange(id: string, rawResourceGroups: SCMRawResourceGroup[], count: number | undefined, state: string | undefined): void { - const provider = this.providers[id]; + $onChange(handle: number, rawResourceGroups: SCMRawResourceGroup[], count: number | undefined, state: string | undefined): void { + const provider = this.providers[handle]; if (!provider) { return; 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 b8901432a1e..64e62f8cd3c 100644 --- a/src/vs/workbench/parts/scm/electron-browser/scm.contribution.ts +++ b/src/vs/workbench/parts/scm/electron-browser/scm.contribution.ts @@ -50,7 +50,6 @@ export class SwitchProvider extends Action { run(): TPromise { const picks = this.scmService.providers.map(provider => ({ - id: provider.id, label: provider.label, run: () => this.scmService.activeProvider = provider })); diff --git a/src/vs/workbench/parts/scm/electron-browser/scmMenus.ts b/src/vs/workbench/parts/scm/electron-browser/scmMenus.ts index 92bff17cc66..48ca06aaa64 100644 --- a/src/vs/workbench/parts/scm/electron-browser/scmMenus.ts +++ b/src/vs/workbench/parts/scm/electron-browser/scmMenus.ts @@ -13,13 +13,12 @@ import { IMenuService, MenuId } from 'vs/platform/actions/common/actions'; import { IAction } from 'vs/base/common/actions'; import { fillInActions } from 'vs/platform/actions/browser/menuItemActionItem'; import { ISCMService, ISCMProvider, ISCMResource, ISCMResourceGroup } from 'vs/workbench/services/scm/common/scm'; -import { getSCMResourceGroupId } from './scmUtil'; +import { getSCMResourceContextKey } from './scmUtil'; export class SCMMenus implements IDisposable { private disposables: IDisposable[] = []; - private activeProviderId: string | undefined; private titleDisposable: IDisposable = EmptyDisposable; private titleActions: IAction[] = []; private titleSecondaryActions: IAction[] = []; @@ -42,8 +41,6 @@ export class SCMMenus implements IDisposable { this.titleDisposable = EmptyDisposable; } - this.activeProviderId = activeProvider ? activeProvider.id : undefined; - if (!activeProvider) { return; } @@ -99,7 +96,7 @@ export class SCMMenus implements IDisposable { } const contextKeyService = this.contextKeyService.createScoped(); - contextKeyService.createKey('scmResourceGroup', getSCMResourceGroupId(resource)); + contextKeyService.createKey('scmResourceGroup', getSCMResourceContextKey(resource)); const menu = this.menuService.createMenu(menuId, contextKeyService); const primary = []; diff --git a/src/vs/workbench/parts/scm/electron-browser/scmUtil.ts b/src/vs/workbench/parts/scm/electron-browser/scmUtil.ts index 865685bc782..2032354475f 100644 --- a/src/vs/workbench/parts/scm/electron-browser/scmUtil.ts +++ b/src/vs/workbench/parts/scm/electron-browser/scmUtil.ts @@ -11,6 +11,6 @@ export function isSCMResource(element: ISCMResourceGroup | ISCMResource): elemen return !!(element as ISCMResource).sourceUri; } -export function getSCMResourceGroupId(resource: ISCMResourceGroup | ISCMResource): string { - return isSCMResource(resource) ? resource.resourceGroupId : resource.id; +export function getSCMResourceContextKey(resource: ISCMResourceGroup | ISCMResource): string { + return isSCMResource(resource) ? resource.resourceGroup.contextKey : resource.contextKey; } \ No newline at end of file diff --git a/src/vs/workbench/parts/scm/electron-browser/scmViewlet.ts b/src/vs/workbench/parts/scm/electron-browser/scmViewlet.ts index d3ee18ad6bb..cf053ed089a 100644 --- a/src/vs/workbench/parts/scm/electron-browser/scmViewlet.ts +++ b/src/vs/workbench/parts/scm/electron-browser/scmViewlet.ts @@ -43,14 +43,6 @@ import URI from 'vs/base/common/uri'; import { isSCMResource } from './scmUtil'; import { attachInputBoxStyler } from 'vs/platform/theme/common/styler'; -function getElementId(element: ISCMResourceGroup | ISCMResource) { - if (isSCMResource(element)) { - return `${element.resourceGroupId}:${element.sourceUri.toString()}`; - } else { - return `${element.id}`; - } -} - interface SearchInputEvent extends Event { target: HTMLInputElement; immediate?: boolean; @@ -196,7 +188,6 @@ export class SCMViewlet extends Viewlet { private listContainer: HTMLElement; private list: List; private menus: SCMMenus; - private activeProviderId: string | undefined; private providerChangeDisposable: IDisposable = EmptyDisposable; private disposables: IDisposable[] = []; @@ -223,7 +214,6 @@ export class SCMViewlet extends Viewlet { private setActiveProvider(activeProvider: ISCMProvider | undefined): void { this.providerChangeDisposable.dispose(); - this.activeProviderId = activeProvider ? activeProvider.id : undefined; if (activeProvider) { this.providerChangeDisposable = activeProvider.onDidChange(this.update, this); @@ -270,7 +260,7 @@ export class SCMViewlet extends Viewlet { ]; this.list = new List(this.listContainer, delegate, renderers, { - identityProvider: e => getElementId(e), + identityProvider: e => e.uri.toString(), keyboardSupport: false }); diff --git a/src/vs/workbench/services/scm/common/scm.ts b/src/vs/workbench/services/scm/common/scm.ts index ff30d9875b3..338489cce98 100644 --- a/src/vs/workbench/services/scm/common/scm.ts +++ b/src/vs/workbench/services/scm/common/scm.ts @@ -24,7 +24,7 @@ export interface ISCMResourceDecorations { } export interface ISCMResource { - readonly resourceGroupId: string; + readonly resourceGroup: ISCMResourceGroup; readonly uri: URI; readonly sourceUri: URI; readonly decorations: ISCMResourceDecorations; @@ -32,14 +32,14 @@ export interface ISCMResource { export interface ISCMResourceGroup { readonly uri: URI; - readonly id: string; readonly label: string; + readonly contextKey?: string; readonly resources: ISCMResource[]; } export interface ISCMProvider extends IDisposable { - readonly id: string; readonly label: string; + readonly contextKey?: string; readonly resources: ISCMResourceGroup[]; readonly onDidChange: Event; readonly count?: number; diff --git a/src/vs/workbench/services/scm/common/scmService.ts b/src/vs/workbench/services/scm/common/scmService.ts index b1c26021750..10ae0207d8e 100644 --- a/src/vs/workbench/services/scm/common/scmService.ts +++ b/src/vs/workbench/services/scm/common/scmService.ts @@ -59,7 +59,7 @@ export class SCMService implements ISCMService { } this._activeProvider = provider; - this.activeProviderContextKey.set(provider ? provider.id : void 0); + this.activeProviderContextKey.set(provider ? provider.contextKey : void 0); this.providerChangeDisposable.dispose(); this.providerChangeDisposable = provider.onDidChange(this.onDidChangeProviderState, this);