From 86cd46a44ee4c9cd5dd29e478634e238f4e0e7ff Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Thu, 26 Oct 2017 15:45:26 +0200 Subject: [PATCH] deco - allow to derive new decoration from existing decoration, add IDecorationData#source --- extensions/git/src/repository.ts | 2 +- src/vs/vscode.proposed.d.ts | 1 + .../electron-browser/mainThreadDecorations.ts | 9 ++- src/vs/workbench/api/node/extHost.api.impl.ts | 4 +- src/vs/workbench/api/node/extHost.protocol.ts | 2 +- .../workbench/api/node/extHostDecorations.ts | 2 +- .../decorations/browser/decorations.ts | 11 +-- .../decorations/browser/decorationsService.ts | 77 +++++++++---------- .../test/browser/decorationsService.test.ts | 3 - 9 files changed, 53 insertions(+), 58 deletions(-) diff --git a/extensions/git/src/repository.ts b/extensions/git/src/repository.ts index bb98461872f..d51303ab2b6 100644 --- a/extensions/git/src/repository.ts +++ b/extensions/git/src/repository.ts @@ -265,7 +265,7 @@ export class Resource implements SourceControlResourceState { const abbreviation = this.letter; const color = this.color; const priority = this.priority; - return { bubble: true, title, abbreviation, color, priority }; + return { bubble: true, source: 'git.resource', title, abbreviation, color, priority }; } constructor( diff --git a/src/vs/vscode.proposed.d.ts b/src/vs/vscode.proposed.d.ts index 5586bd1c124..6aa10608b03 100644 --- a/src/vs/vscode.proposed.d.ts +++ b/src/vs/vscode.proposed.d.ts @@ -178,6 +178,7 @@ declare module 'vscode' { bubble?: boolean; abbreviation?: string; color?: ThemeColor; + source?: string; } export interface DecorationProvider { diff --git a/src/vs/workbench/api/electron-browser/mainThreadDecorations.ts b/src/vs/workbench/api/electron-browser/mainThreadDecorations.ts index 7ac2b8c92ef..c999dcc5553 100644 --- a/src/vs/workbench/api/electron-browser/mainThreadDecorations.ts +++ b/src/vs/workbench/api/electron-browser/mainThreadDecorations.ts @@ -29,23 +29,24 @@ export class MainThreadDecorations implements MainThreadDecorationsShape { this._provider.clear(); } - $registerDecorationProvider(handle: number): void { + $registerDecorationProvider(handle: number, label: string): void { let emitter = new Emitter(); let registration = this._decorationsService.registerDecorationsProvider({ - label: 'extension-provider', + label, onDidChange: emitter.event, provideDecorations: (uri) => { return this._proxy.$providerDecorations(handle, uri).then(data => { if (!data) { return undefined; } - const [weight, bubble, title, letter, themeColor] = data; + const [weight, bubble, title, letter, themeColor, source] = data; return { weight: weight || 0, bubble: bubble || false, + color: themeColor && themeColor.id, title, letter, - color: themeColor && themeColor.id + source, }; }); } diff --git a/src/vs/workbench/api/node/extHost.api.impl.ts b/src/vs/workbench/api/node/extHost.api.impl.ts index 1d9c80b498f..e7f484ddd5f 100644 --- a/src/vs/workbench/api/node/extHost.api.impl.ts +++ b/src/vs/workbench/api/node/extHost.api.impl.ts @@ -378,8 +378,8 @@ export function createApiFactory( sampleFunction: proposedApiFunction(extension, () => { return extHostMessageService.showMessage(extension, Severity.Info, 'Hello Proposed Api!', {}, []); }), - registerDecorationProvider: proposedApiFunction(extension, (provider: vscode.DecorationProvider) => { - return extHostDecorations.registerDecorationProvider(provider, extension.id); + registerDecorationProvider: proposedApiFunction(extension, (provider: vscode.DecorationProvider, source) => { + return extHostDecorations.registerDecorationProvider(provider, source); }) }; diff --git a/src/vs/workbench/api/node/extHost.protocol.ts b/src/vs/workbench/api/node/extHost.protocol.ts index 2346b9d7ebb..dd812a65ad4 100644 --- a/src/vs/workbench/api/node/extHost.protocol.ts +++ b/src/vs/workbench/api/node/extHost.protocol.ts @@ -625,7 +625,7 @@ export interface ExtHostDebugServiceShape { } -export type DecorationData = [number, boolean, string, string, ThemeColor]; +export type DecorationData = [number, boolean, string, string, ThemeColor, string]; export interface ExtHostDecorationsShape { $providerDecorations(handle: number, uri: URI): TPromise; diff --git a/src/vs/workbench/api/node/extHostDecorations.ts b/src/vs/workbench/api/node/extHostDecorations.ts index e327dbe4995..b2f746e6dc4 100644 --- a/src/vs/workbench/api/node/extHostDecorations.ts +++ b/src/vs/workbench/api/node/extHostDecorations.ts @@ -41,7 +41,7 @@ export class ExtHostDecorations implements ExtHostDecorationsShape { $providerDecorations(handle: number, uri: URI): TPromise { const provider = this._provider.get(handle); return asWinJsPromise(token => provider.provideDecoration(uri, token)).then(data => { - return data && [data.priority, data.bubble, data.title, data.abbreviation, data.color]; + return data && [data.priority, data.bubble, data.title, data.abbreviation, data.color, data.source]; }); } } diff --git a/src/vs/workbench/services/decorations/browser/decorations.ts b/src/vs/workbench/services/decorations/browser/decorations.ts index 6356737cb2d..8334be55869 100644 --- a/src/vs/workbench/services/decorations/browser/decorations.ts +++ b/src/vs/workbench/services/decorations/browser/decorations.ts @@ -18,14 +18,15 @@ export interface IDecorationData { readonly letter?: string; readonly title?: string; readonly bubble?: boolean; + readonly source?: string; } export interface IDecoration { - readonly _decoBrand: undefined; - readonly weight?: number; - readonly title?: string; - readonly labelClassName?: string; - readonly badgeClassName?: string; + readonly title: string; + readonly labelClassName: string; + readonly badgeClassName: string; + readonly data: IDecorationData[]; + update(replace: { source?: string, data?: IDecorationData }): IDecoration; } export interface IDecorationsProvider { diff --git a/src/vs/workbench/services/decorations/browser/decorationsService.ts b/src/vs/workbench/services/decorations/browser/decorationsService.ts index 5f8fdace5c1..dcb84c316ad 100644 --- a/src/vs/workbench/services/decorations/browser/decorationsService.ts +++ b/src/vs/workbench/services/decorations/browser/decorationsService.ts @@ -75,33 +75,6 @@ class DecorationRule { } } -class ResourceDecoration implements IDecoration { - - static from(data: IDecorationData | IDecorationData[]): ResourceDecoration { - let result = new ResourceDecoration(data); - if (Array.isArray(data)) { - result.weight = data[0].weight; - result.title = data.map(d => d.title).join(', '); - } else { - result.weight = data.weight; - result.title = data.title; - } - return result; - } - - _decoBrand: undefined; - _data: IDecorationData | IDecorationData[]; - - weight?: number; - title?: string; - labelClassName?: string; - badgeClassName?: string; - - private constructor(data: IDecorationData | IDecorationData[]) { - this._data = data; - } -} - class DecorationStyles { private readonly _disposables: IDisposable[]; @@ -121,10 +94,13 @@ class DecorationStyles { this._styleElement.parentElement.removeChild(this._styleElement); } - asDecoration(data: IDecorationData | IDecorationData[]): ResourceDecoration { + asDecoration(data: IDecorationData[], onlyChildren: boolean): IDecoration { + + // sort by weight + data.sort((a, b) => b.weight - a.weight); + let key = DecorationRule.keyOf(data); let rule = this._decorationRules.get(key); - let result = ResourceDecoration.from(data); if (!rule) { // new css rule @@ -133,9 +109,35 @@ class DecorationStyles { rule.appendCSSRules(this._styleElement, this._themeService.getTheme()); } - result.labelClassName = rule.labelClassName; - result.badgeClassName = rule.badgeClassName; - return result; + return { + data, + labelClassName: rule.labelClassName, + badgeClassName: !onlyChildren ? rule.badgeClassName : '', + title: !onlyChildren ? data.filter(d => Boolean(d.title)).map(d => d.title).join(', ') : '', + update: replace => { + let newData = data.slice(); + if (!replace.source) { + // add -> just append + newData.push(replace.data); + + } else { + // remove/replace -> require a walk + for (let i = 0; i < newData.length; i++) { + if (newData[i].source === replace.source) { + if (!replace.data) { + // remove + newData.splice(i, 1); + i--; + } else { + // replace + newData[i] = replace.data; + } + } + } + } + return this.asDecoration(newData, onlyChildren); + } + }; } private _onThemeChange(): void { @@ -373,15 +375,8 @@ export class FileDecorationsService implements IDecorationsService { if (data.length === 0) { return undefined; - } else if (onlyChildren) { - let result = this._decorationStyles.asDecoration(data.sort((a, b) => b.weight - a.weight)[0]); - result.badgeClassName = ''; - result.title = ''; - return result; - } else if (data.length === 1) { - return this._decorationStyles.asDecoration(data[0]); - } else { - return this._decorationStyles.asDecoration(data.sort((a, b) => b.weight - a.weight)); } + + return this._decorationStyles.asDecoration(data, onlyChildren); } } diff --git a/src/vs/workbench/services/decorations/test/browser/decorationsService.test.ts b/src/vs/workbench/services/decorations/test/browser/decorationsService.test.ts index 9ea7fd9c29b..ccbdc666109 100644 --- a/src/vs/workbench/services/decorations/test/browser/decorationsService.test.ts +++ b/src/vs/workbench/services/decorations/test/browser/decorationsService.test.ts @@ -120,7 +120,6 @@ suite('DecorationsService', function () { let deco = service.getDecoration(childUri, false); assert.equal(deco.title, '.txt'); - assert.equal(deco.weight, 17); deco = service.getDecoration(childUri.with({ path: 'some/path/' }), true); assert.equal(deco, undefined); @@ -139,10 +138,8 @@ suite('DecorationsService', function () { deco = service.getDecoration(childUri, false); assert.equal(deco.title, '.txt.bubble'); - assert.equal(deco.weight, 71); deco = service.getDecoration(childUri.with({ path: 'some/path/' }), true); assert.equal(deco.title, ''); - assert.equal(deco.weight, 71); }); }); -- GitLab