diff --git a/extensions/css/client/src/colorDecorators.ts b/extensions/css/client/src/colorDecorators.ts index e7b0e0cb6800876ff62c704b50d2f4cab7a3be12..e68dad254ab0b96739422b3841eaf3c3b97721fd 100644 --- a/extensions/css/client/src/colorDecorators.ts +++ b/extensions/css/client/src/colorDecorators.ts @@ -5,132 +5,7 @@ 'use strict'; import * as parse from 'parse-color'; -import { window, workspace, DecorationOptions, DecorationRenderOptions, Disposable, Range, TextDocument, DocumentColorProvider, Color, ColorRange } from 'vscode'; - -const MAX_DECORATORS = 500; - -let decorationType: DecorationRenderOptions = { - before: { - contentText: ' ', - border: 'solid 0.1em #000', - margin: '0.1em 0.2em 0 0.2em', - width: '0.8em', - height: '0.8em' - }, - dark: { - before: { - border: 'solid 0.1em #eee' - } - } -}; - -export function activateColorDecorations(decoratorProvider: (uri: string) => Thenable, supportedLanguages: { [id: string]: boolean }, isDecoratorEnabled: (languageId: string) => boolean): Disposable { - - let disposables: Disposable[] = []; - - let colorsDecorationType = window.createTextEditorDecorationType(decorationType); - disposables.push(colorsDecorationType); - - let decoratorEnablement = {}; - for (let languageId in supportedLanguages) { - decoratorEnablement[languageId] = isDecoratorEnabled(languageId); - } - - let pendingUpdateRequests: { [key: string]: NodeJS.Timer; } = {}; - - window.onDidChangeVisibleTextEditors(editors => { - for (let editor of editors) { - triggerUpdateDecorations(editor.document); - } - }, null, disposables); - - workspace.onDidChangeTextDocument(event => triggerUpdateDecorations(event.document), null, disposables); - - // track open and close for document languageId changes - workspace.onDidCloseTextDocument(event => triggerUpdateDecorations(event, true)); - workspace.onDidOpenTextDocument(event => triggerUpdateDecorations(event)); - - workspace.onDidChangeConfiguration(_ => { - let hasChanges = false; - for (let languageId in supportedLanguages) { - let prev = decoratorEnablement[languageId]; - let curr = isDecoratorEnabled(languageId); - if (prev !== curr) { - decoratorEnablement[languageId] = curr; - hasChanges = true; - } - } - if (hasChanges) { - updateAllVisibleEditors(true); - } - }, null, disposables); - - updateAllVisibleEditors(false); - - function updateAllVisibleEditors(settingsChanges: boolean) { - window.visibleTextEditors.forEach(editor => { - if (editor.document) { - triggerUpdateDecorations(editor.document, settingsChanges); - } - }); - } - - function triggerUpdateDecorations(document: TextDocument, settingsChanges = false) { - let triggerUpdate = supportedLanguages[document.languageId] && (decoratorEnablement[document.languageId] || settingsChanges); - if (triggerUpdate) { - let documentUriStr = document.uri.toString(); - let timeout = pendingUpdateRequests[documentUriStr]; - if (typeof timeout !== 'undefined') { - clearTimeout(timeout); - } - pendingUpdateRequests[documentUriStr] = setTimeout(() => { - // check if the document is in use by an active editor - for (let editor of window.visibleTextEditors) { - if (editor.document && documentUriStr === editor.document.uri.toString()) { - if (decoratorEnablement[editor.document.languageId]) { - updateDecorationForEditor(documentUriStr, editor.document.version); - break; - } else { - editor.setDecorations(colorsDecorationType, []); - } - } - } - delete pendingUpdateRequests[documentUriStr]; - }, 500); - } - } - - function updateDecorationForEditor(contentUri: string, documentVersion: number) { - decoratorProvider(contentUri).then(ranges => { - for (let editor of window.visibleTextEditors) { - let document = editor.document; - - if (document && document.version === documentVersion && contentUri === document.uri.toString()) { - let decorations = ranges.slice(0, MAX_DECORATORS).map(range => { - let color = document.getText(range); - if (color[0] === '#' && (color.length === 5 || color.length === 9)) { - let c = Color.fromHex(color); - if (c) { - color = `rgba(${c.red}, ${c.green}, ${c.blue}, ${c.alpha})`; - } - } - return { - range: range, - renderOptions: { - before: { - backgroundColor: color - } - } - }; - }); - editor.setDecorations(colorsDecorationType, decorations); - } - } - }); - } - - return Disposable.from(...disposables); -} +import { Range, TextDocument, DocumentColorProvider, Color, ColorRange } from 'vscode'; const CSSColorFormats = { Hex: '#{red:X}{green:X}{blue:X}', @@ -145,10 +20,14 @@ const CSSColorFormats = { }; export class ColorProvider implements DocumentColorProvider { - - constructor(private decoratorProvider: (uri: string) => Thenable) { } + constructor(private decoratorProvider: (uri: string) => Thenable, private supportedLanguages: { [id: string]: boolean }, private isDecoratorEnabled: (languageId: string) => boolean) { } async provideDocumentColors(document: TextDocument): Promise { + let renderDecorator = false; + if (document && this.isDecoratorEnabled(document.languageId)) { + renderDecorator = true; + } + const ranges = await this.decoratorProvider(document.uri.toString()); const result = []; for (let range of ranges) { @@ -164,7 +43,7 @@ export class ColorProvider implements DocumentColorProvider { } } if (color) { - result.push(new ColorRange(range, color, [CSSColorFormats.Hex, CSSColorFormats.RGB, CSSColorFormats.HSL])); + result.push(new ColorRange(range, color, [CSSColorFormats.Hex, CSSColorFormats.RGB, CSSColorFormats.HSL], renderDecorator)); } } return result; diff --git a/extensions/css/client/src/cssMain.ts b/extensions/css/client/src/cssMain.ts index a13dabac0b944637219ffdae26903ab47bdf1de4..5ab8e9660ed0d8b450cca610d915731797bf9338 100644 --- a/extensions/css/client/src/cssMain.ts +++ b/extensions/css/client/src/cssMain.ts @@ -8,8 +8,8 @@ import * as path from 'path'; import { languages, window, commands, workspace, ExtensionContext } from 'vscode'; import { LanguageClient, LanguageClientOptions, ServerOptions, TransportKind, RequestType, Range, TextEdit } from 'vscode-languageclient'; -import { activateColorDecorations, ColorProvider } from './colorDecorators'; import { ConfigurationFeature } from 'vscode-languageclient/lib/proposed'; +import { ColorProvider } from './colorDecorators'; import * as nls from 'vscode-nls'; let localize = nls.loadMessageBundle(); @@ -60,8 +60,7 @@ export function activate(context: ExtensionContext) { return workspace.getConfiguration().get(languageId + '.colorDecorators.enable'); }; - context.subscriptions.push(languages.registerColorProvider(['css', 'scss', 'less'], new ColorProvider(colorRequestor))); - context.subscriptions.push(activateColorDecorations(colorRequestor, { css: true, scss: true, less: true }, isDecoratorEnabled)); + context.subscriptions.push(languages.registerColorProvider(['css', 'scss', 'less'], new ColorProvider(colorRequestor, { css: true, scss: true, less: true }, isDecoratorEnabled))); }); let indentationRules = { diff --git a/extensions/json/client/src/colorDecorators.ts b/extensions/json/client/src/colorDecorators.ts index 79b7f1578b448588f8e70031d9b4712ec5484ca6..f9e94069dc272732023ff4bd9bdbfd6a19d600a5 100644 --- a/extensions/json/client/src/colorDecorators.ts +++ b/extensions/json/client/src/colorDecorators.ts @@ -4,130 +4,7 @@ *--------------------------------------------------------------------------------------------*/ 'use strict'; -import { window, workspace, DecorationOptions, DecorationRenderOptions, Disposable, Range, TextDocument, DocumentColorProvider, Color, ColorRange } from 'vscode'; - -const MAX_DECORATORS = 500; - -let decorationType: DecorationRenderOptions = { - before: { - contentText: ' ', - border: 'solid 0.1em #000', - margin: '0.1em 0.2em 0 0.2em', - width: '0.8em', - height: '0.8em' - }, - dark: { - before: { - border: 'solid 0.1em #eee' - } - } -}; - -export function activateColorDecorations(decoratorProvider: (uri: string) => Thenable, supportedLanguages: { [id: string]: boolean }, isDecoratorEnabled: (languageId: string) => boolean): Disposable { - - let disposables: Disposable[] = []; - - let colorsDecorationType = window.createTextEditorDecorationType(decorationType); - disposables.push(colorsDecorationType); - - let decoratorEnablement = {}; - for (let languageId in supportedLanguages) { - decoratorEnablement[languageId] = isDecoratorEnabled(languageId); - } - - let pendingUpdateRequests: { [key: string]: NodeJS.Timer; } = {}; - - window.onDidChangeVisibleTextEditors(editors => { - for (let editor of editors) { - triggerUpdateDecorations(editor.document); - } - }, null, disposables); - - workspace.onDidChangeTextDocument(event => triggerUpdateDecorations(event.document), null, disposables); - - // track open and close for document languageId changes - workspace.onDidCloseTextDocument(event => triggerUpdateDecorations(event, true)); - workspace.onDidOpenTextDocument(event => triggerUpdateDecorations(event)); - - workspace.onDidChangeConfiguration(_ => { - let hasChanges = false; - for (let languageId in supportedLanguages) { - let prev = decoratorEnablement[languageId]; - let curr = isDecoratorEnabled(languageId); - if (prev !== curr) { - decoratorEnablement[languageId] = curr; - hasChanges = true; - } - } - if (hasChanges) { - updateAllVisibleEditors(true); - } - }, null, disposables); - - updateAllVisibleEditors(false); - - function updateAllVisibleEditors(settingsChanges: boolean) { - window.visibleTextEditors.forEach(editor => { - if (editor.document) { - triggerUpdateDecorations(editor.document, settingsChanges); - } - }); - } - - function triggerUpdateDecorations(document: TextDocument, settingsChanges = false) { - let triggerUpdate = supportedLanguages[document.languageId] && (decoratorEnablement[document.languageId] || settingsChanges); - if (triggerUpdate) { - let documentUriStr = document.uri.toString(); - let timeout = pendingUpdateRequests[documentUriStr]; - if (typeof timeout !== 'undefined') { - clearTimeout(timeout); - } - pendingUpdateRequests[documentUriStr] = setTimeout(() => { - // check if the document is in use by an active editor - for (let editor of window.visibleTextEditors) { - if (editor.document && documentUriStr === editor.document.uri.toString()) { - if (decoratorEnablement[editor.document.languageId]) { - updateDecorationForEditor(documentUriStr, editor.document.version); - break; - } else { - editor.setDecorations(colorsDecorationType, []); - } - } - } - delete pendingUpdateRequests[documentUriStr]; - }, 500); - } - } - - function updateDecorationForEditor(contentUri: string, documentVersion: number) { - decoratorProvider(contentUri).then(ranges => { - for (let editor of window.visibleTextEditors) { - let document = editor.document; - - if (document && document.version === documentVersion && contentUri === document.uri.toString()) { - let decorations = []; - for (let i = 0; i < ranges.length && decorations.length < MAX_DECORATORS; i++) { - let range = ranges[i]; - let c = parseColorFromRange(document, range); - if (c) { - decorations.push({ - range: range, - renderOptions: { - before: { - backgroundColor: `rgba(${c.red}, ${c.green}, ${c.blue}, ${c.alpha})` - } - } - }); - } - } - editor.setDecorations(colorsDecorationType, decorations); - } - } - }); - } - - return Disposable.from(...disposables); -} +import { Range, TextDocument, DocumentColorProvider, Color, ColorRange } from 'vscode'; const ColorFormat_HEX = { opaque: '"#{red:X}{green:X}{blue:X}"', @@ -135,17 +12,21 @@ const ColorFormat_HEX = { }; export class ColorProvider implements DocumentColorProvider { - - constructor(private decoratorProvider: (uri: string) => Thenable) { } + constructor(private decoratorProvider: (uri: string) => Thenable, private supportedLanguages: { [id: string]: boolean }, private isDecoratorEnabled: (languageId: string) => boolean) { } async provideDocumentColors(document: TextDocument): Promise { + let renderDecorator = false; + if (document && this.isDecoratorEnabled(document.languageId)) { + renderDecorator = true; + } + const ranges = await this.decoratorProvider(document.uri.toString()); const result = []; for (let range of ranges) { let color = parseColorFromRange(document, range); if (color) { let r = new Range(range.start.line, range.start.character, range.end.line, range.end.character); - result.push(new ColorRange(r, color, [ColorFormat_HEX])); + result.push(new ColorRange(r, color, [ColorFormat_HEX], renderDecorator)); } } return result; diff --git a/extensions/json/client/src/jsonMain.ts b/extensions/json/client/src/jsonMain.ts index 1deaed5c71adb81f88284ee6c317e2aef040db50..9e0fb43920516f3060799ba822ed75d541eec6c5 100644 --- a/extensions/json/client/src/jsonMain.ts +++ b/extensions/json/client/src/jsonMain.ts @@ -9,8 +9,8 @@ import * as path from 'path'; import { workspace, languages, ExtensionContext, extensions, Uri, Range } from 'vscode'; import { LanguageClient, LanguageClientOptions, RequestType, ServerOptions, TransportKind, NotificationType, DidChangeConfigurationNotification } from 'vscode-languageclient'; import TelemetryReporter from 'vscode-extension-telemetry'; -import { activateColorDecorations, ColorProvider } from './colorDecorators'; import { ConfigurationFeature } from 'vscode-languageclient/lib/proposed'; +import { ColorProvider } from "./colorDecorators"; import * as nls from 'vscode-nls'; let localize = nls.loadMessageBundle(); @@ -122,10 +122,8 @@ export function activate(context: ExtensionContext) { let isDecoratorEnabled = (languageId: string) => { return workspace.getConfiguration().get(languageId + '.colorDecorators.enable'); }; - disposable = activateColorDecorations(colorRequestor, { json: true }, isDecoratorEnabled); - context.subscriptions.push(disposable); - context.subscriptions.push(languages.registerColorProvider('json', new ColorProvider(colorRequestor))); + context.subscriptions.push(languages.registerColorProvider('json', new ColorProvider(colorRequestor, { json: true }, isDecoratorEnabled))); }); // Push the disposable to the context's subscriptions so that the diff --git a/src/vs/editor/common/modes.ts b/src/vs/editor/common/modes.ts index 4d7bebc731de77fe00028a3166d91300eaafad24..02af3f2c6af0a2679808e6d028bc1fc97648483a 100644 --- a/src/vs/editor/common/modes.ts +++ b/src/vs/editor/common/modes.ts @@ -709,6 +709,11 @@ export interface IColorRange { * The available formats for this specific color. */ formatters: IColorFormatter[]; + + /** + * Controls whether the color decorator is rendered. + */ + renderDecorator: boolean; } /** diff --git a/src/vs/editor/contrib/colorPicker/browser/colorController.ts b/src/vs/editor/contrib/colorPicker/browser/colorController.ts index 76291dffd18b5da841d69d59f337a8290fe1a669..256db6b5df7e71dd32907628d322a9367a4862cf 100644 --- a/src/vs/editor/contrib/colorPicker/browser/colorController.ts +++ b/src/vs/editor/contrib/colorPicker/browser/colorController.ts @@ -41,6 +41,9 @@ export class ColorController extends Disposable implements IEditorContribution { let decorations = []; for (let i = 0; i < colorInfos.length; i++) { + if (!colorInfos[i].renderDecorator) { + continue; + } const { red, green, blue, alpha } = colorInfos[i].color; const rgba = new RGBA(red * 255, green * 255, blue * 255, alpha * 255); let subKey = hash(rgba).toString(16); diff --git a/src/vs/editor/contrib/colorPicker/browser/colorDetector.ts b/src/vs/editor/contrib/colorPicker/browser/colorDetector.ts index 0d2a307ed8c28577d27e1b137c62d7a5aa6799ff..37f549337aacf62c1d69a9141eb0ec6f174f05d1 100644 --- a/src/vs/editor/contrib/colorPicker/browser/colorDetector.ts +++ b/src/vs/editor/contrib/colorPicker/browser/colorDetector.ts @@ -111,7 +111,8 @@ export class ColorDetector implements IEditorContribution { const colorRanges = colorInfos.map(c => ({ range: c.range, color: c.color, - formatters: c.formatters + formatters: c.formatters, + renderDecorator: c.renderDecorator })); this.decorationsIds = this.editor.deltaDecorations(this.decorationsIds, decorations); diff --git a/src/vs/vscode.proposed.d.ts b/src/vs/vscode.proposed.d.ts index ec5426e9edf73fff107bda6752e8e7cdcbd2a77a..edf188cbf75f2c47e03590c47d3e5b0c7da67534 100644 --- a/src/vs/vscode.proposed.d.ts +++ b/src/vs/vscode.proposed.d.ts @@ -179,15 +179,20 @@ declare module 'vscode' { */ availableFormats: ColorFormat[]; + /** + * Controls whether the color decorator is rendered. + */ + renderDecorator: boolean; + /** * Creates a new color range. * * @param range The range the color appears in. Must not be empty. * @param color The value of the color. * @param format The format in which this color is currently formatted. - * @param availableFormats The other formats this color range supports the color to be formatted in. + * @param renderDecorator Controls whether the color decorator is rendered. */ - constructor(range: Range, color: Color, availableFormats: ColorFormat[]); + constructor(range: Range, color: Color, availableFormats: ColorFormat[], renderDecorator: boolean); } /** diff --git a/src/vs/workbench/api/electron-browser/mainThreadLanguageFeatures.ts b/src/vs/workbench/api/electron-browser/mainThreadLanguageFeatures.ts index 39a641f557a85976edfa38edb1700e44a6e77bc6..d28eb322823b0beb045f4c91137802f4bcbca936 100644 --- a/src/vs/workbench/api/electron-browser/mainThreadLanguageFeatures.ts +++ b/src/vs/workbench/api/electron-browser/mainThreadLanguageFeatures.ts @@ -303,7 +303,8 @@ export class MainThreadLanguageFeatures implements MainThreadLanguageFeaturesSha return { color, formatters, - range: documentColor.range + range: documentColor.range, + renderDecorator: documentColor.renderDecorator }; }); }); diff --git a/src/vs/workbench/api/node/extHost.protocol.ts b/src/vs/workbench/api/node/extHost.protocol.ts index 69090dd32ce6a18c8b1534e514acf8cf886c1cba..dc68ebb8bedca08e886e82e19a887180894d041a 100644 --- a/src/vs/workbench/api/node/extHost.protocol.ts +++ b/src/vs/workbench/api/node/extHost.protocol.ts @@ -474,6 +474,7 @@ export interface IRawColorInfo { color: [number, number, number, number]; availableFormats: (number | [number, number])[]; range: IRange; + renderDecorator: boolean; } export type IRawColorFormatMap = [number, string][]; diff --git a/src/vs/workbench/api/node/extHostLanguageFeatures.ts b/src/vs/workbench/api/node/extHostLanguageFeatures.ts index 3e295379597e51c37420164a2cc5153d42f605c4..0c40410d01df18a13e8c66224bc5c8bf9802341f 100644 --- a/src/vs/workbench/api/node/extHostLanguageFeatures.ts +++ b/src/vs/workbench/api/node/extHostLanguageFeatures.ts @@ -734,7 +734,8 @@ class ColorProviderAdapter { return { color: [ci.color.red, ci.color.green, ci.color.blue, ci.color.alpha] as [number, number, number, number], availableFormats: availableFormats, - range: TypeConverters.fromRange(ci.range) + range: TypeConverters.fromRange(ci.range), + renderDecorator: ci.renderDecorator }; }); diff --git a/src/vs/workbench/api/node/extHostTypes.ts b/src/vs/workbench/api/node/extHostTypes.ts index 980d89b0c0e7977a6ff72c1242370bea66e7f244..e5f82229efb33154074373ff6e6e5637548a5802 100644 --- a/src/vs/workbench/api/node/extHostTypes.ts +++ b/src/vs/workbench/api/node/extHostTypes.ts @@ -1056,7 +1056,9 @@ export class ColorRange { availableFormats: IColorFormat[]; - constructor(range: Range, color: Color, availableFormats: IColorFormat[]) { + renderDecorator: boolean; + + constructor(range: Range, color: Color, availableFormats: IColorFormat[], renderDecorator: boolean) { if (color && !(color instanceof Color)) { throw illegalArgument('color'); } @@ -1069,6 +1071,7 @@ export class ColorRange { this.range = range; this.color = color; this.availableFormats = availableFormats; + this.renderDecorator = renderDecorator; } }