From f52299aee02f31c23dddf7d19cd6038583a360d1 Mon Sep 17 00:00:00 2001 From: rebornix Date: Wed, 16 Aug 2017 17:05:12 -0700 Subject: [PATCH] Add a new option to control whether to render inline color box or not. --- extensions/css/client/src/colorDecorators.ts | 137 +----------------- extensions/css/client/src/cssMain.ts | 5 +- extensions/json/client/src/colorDecorators.ts | 135 +---------------- extensions/json/client/src/jsonMain.ts | 6 +- src/vs/editor/common/modes.ts | 5 + .../colorPicker/browser/colorController.ts | 3 + .../colorPicker/browser/colorDetector.ts | 3 +- src/vs/vscode.proposed.d.ts | 9 +- .../mainThreadLanguageFeatures.ts | 3 +- src/vs/workbench/api/node/extHost.protocol.ts | 1 + .../api/node/extHostLanguageFeatures.ts | 3 +- src/vs/workbench/api/node/extHostTypes.ts | 5 +- 12 files changed, 46 insertions(+), 269 deletions(-) diff --git a/extensions/css/client/src/colorDecorators.ts b/extensions/css/client/src/colorDecorators.ts index e7b0e0cb680..e68dad254ab 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 a13dabac0b9..5ab8e9660ed 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 79b7f1578b4..f9e94069dc2 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 1deaed5c71a..9e0fb439205 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 4d7bebc731d..02af3f2c6af 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 76291dffd18..256db6b5df7 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 0d2a307ed8c..37f549337aa 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 ec5426e9edf..edf188cbf75 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 39a641f557a..d28eb322823 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 69090dd32ce..dc68ebb8bed 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 3e295379597..0c40410d01d 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 980d89b0c0e..e5f82229efb 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; } } -- GitLab