diff --git a/extensions/css/client/src/colorDecorators.ts b/extensions/css/client/src/colorDecorators.ts index e6374c3ec17..fa26523341a 100644 --- a/extensions/css/client/src/colorDecorators.ts +++ b/extensions/css/client/src/colorDecorators.ts @@ -4,7 +4,8 @@ *--------------------------------------------------------------------------------------------*/ 'use strict'; -import { window, workspace, DecorationOptions, DecorationRenderOptions, Disposable, Range, TextDocument } from 'vscode'; +import * as parse from 'parse-color'; +import { window, workspace, DecorationOptions, DecorationRenderOptions, Disposable, Range, TextDocument, DocumentColorProvider, Color, ColorFormat, ColorInfo } from 'vscode'; const MAX_DECORATORS = 500; @@ -107,6 +108,12 @@ export function activateColorDecorations(decoratorProvider: (uri: string) => The 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: { @@ -124,3 +131,53 @@ export function activateColorDecorations(decoratorProvider: (uri: string) => The return Disposable.from(...disposables); } + +const CSSColorFormats = { + Hex: '#{red:X}{green:X}{blue:X}', + RGB: { + opaque: 'rgb({red}, {green}, {blue})', + transparent: 'rgba({red}, {green}, {blue}, {alpha:2f[0-1]})' + }, + HSL: { + opaque: 'hsl({hue:d[0-360]}, {saturation:d[0-100]}%, {luminosity:d[0-100]}%)', + transparent: 'hsla({hue:d[0-360]}, {saturation:d[0-100]}%, {luminosity:d[0-100]}%, {alpha:2f[0-1]})' + } +}; + +function detectFormat(value: string): ColorFormat { + if (/^rgb/i.test(value)) { + return CSSColorFormats.RGB; + } else if (/^hsl/i.test(value)) { + return CSSColorFormats.HSL; + } else { + return CSSColorFormats.Hex; + } +} + +export class ColorProvider implements DocumentColorProvider { + + constructor(private decoratorProvider: (uri: string) => Thenable) { } + + async provideDocumentColors(document: TextDocument): Promise { + const ranges = await this.decoratorProvider(document.uri.toString()); + const result = []; + for (let range of ranges) { + let color; + const value = document.getText(range); + if (value[0] === '#') { + color = Color.fromHex(value); + } else { + const parsedColor = parse(value); + if (parsedColor && parsedColor.rgba) { + const [red, green, blue, alpha] = parsedColor.rgba; + color = new Color(red, green, blue, alpha); + } + } + if (color) { + const format = detectFormat(value); + result.push(new ColorInfo(range, color, format, [CSSColorFormats.Hex, CSSColorFormats.RGB, CSSColorFormats.HSL])); + } + } + return result; + } +} \ No newline at end of file diff --git a/extensions/css/client/src/cssMain.ts b/extensions/css/client/src/cssMain.ts index 389156ecc40..1080628cad4 100644 --- a/extensions/css/client/src/cssMain.ts +++ b/extensions/css/client/src/cssMain.ts @@ -5,11 +5,10 @@ 'use strict'; import * as path from 'path'; -import * as parse from 'parse-color'; -import { languages, window, commands, workspace, ExtensionContext, DocumentColorProvider, Color, ColorFormat, CancellationToken, TextDocument, ColorInfo } from 'vscode'; +import { languages, window, commands, workspace, ExtensionContext } from 'vscode'; import { LanguageClient, LanguageClientOptions, ServerOptions, TransportKind, RequestType, Range, TextEdit } from 'vscode-languageclient'; -import { activateColorDecorations } from './colorDecorators'; +import { activateColorDecorations, ColorProvider } from './colorDecorators'; import * as nls from 'vscode-nls'; let localize = nls.loadMessageBundle(); @@ -18,53 +17,6 @@ namespace ColorSymbolRequest { export const type: RequestType = new RequestType('css/colorSymbols'); } -const CSSColorFormats = { - Hex: '#{red:X}{green:X}{blue:X}', - RGB: { - opaque: 'rgb({red}, {green}, {blue})', - transparent: 'rgba({red}, {green}, {blue}, {alpha:2f[0-1]})' - }, - HSL: { - opaque: 'hsl({hue:d[0-360]}, {saturation:d[0-100]}%, {luminosity:d[0-100]}%)', - transparent: 'hsla({hue:d[0-360]}, {saturation:d[0-100]}%, {luminosity:d[0-100]}%, {alpha:2f[0-1]})' - } -}; - -function detectFormat(value: string): ColorFormat { - if (/^rgb/i.test(value)) { - return CSSColorFormats.RGB; - } else if (/^hsl/i.test(value)) { - return CSSColorFormats.HSL; - } else { - return CSSColorFormats.Hex; - } -} - -class ColorProvider implements DocumentColorProvider { - - constructor(private client: LanguageClient) { } - - async provideDocumentColors(document: TextDocument, token: CancellationToken): Promise { - const ranges = await this.client.sendRequest(ColorSymbolRequest.type, document.uri.toString()); - - return ranges.reduce((result, r) => { - const range = this.client.protocol2CodeConverter.asRange(r); - const value = document.getText(range); - const parsedColor = parse(value); - - if (!parsedColor || !parsedColor.rgba) { - return result; - } - - const [red, green, blue, alpha] = parsedColor.rgba; - const color = new Color(red, green, blue, alpha); - const format = detectFormat(value); - - return [...result, new ColorInfo(range, color, format, [CSSColorFormats.Hex, CSSColorFormats.RGB, CSSColorFormats.HSL])]; - }, []); - } -} - // this method is called when vs code is activated export function activate(context: ExtensionContext) { @@ -106,11 +58,8 @@ export function activate(context: ExtensionContext) { return workspace.getConfiguration().get(languageId + '.colorDecorators.enable'); }; - const colorProvider = new ColorProvider(client); - context.subscriptions.push(languages.registerColorProvider(['css', 'scss', 'less'], colorProvider)); - - disposable = activateColorDecorations(colorRequestor, { css: true, scss: true, less: true }, isDecoratorEnabled); - context.subscriptions.push(disposable); + context.subscriptions.push(languages.registerColorProvider(['css', 'scss', 'less'], new ColorProvider(colorRequestor))); + context.subscriptions.push(activateColorDecorations(colorRequestor, { css: true, scss: true, less: true }, isDecoratorEnabled)); }); let indentationRules = { diff --git a/extensions/css/server/npm-shrinkwrap.json b/extensions/css/server/npm-shrinkwrap.json index 39dc45e142b..21329db6203 100644 --- a/extensions/css/server/npm-shrinkwrap.json +++ b/extensions/css/server/npm-shrinkwrap.json @@ -3,9 +3,9 @@ "version": "1.0.0", "dependencies": { "vscode-css-languageservice": { - "version": "2.1.1", + "version": "2.1.2", "from": "vscode-css-languageservice@next", - "resolved": "https://registry.npmjs.org/vscode-css-languageservice/-/vscode-css-languageservice-2.1.1.tgz" + "resolved": "https://registry.npmjs.org/vscode-css-languageservice/-/vscode-css-languageservice-2.1.2.tgz" }, "vscode-jsonrpc": { "version": "3.2.0", diff --git a/extensions/css/server/package.json b/extensions/css/server/package.json index cc4ba952244..c7b93d1573f 100644 --- a/extensions/css/server/package.json +++ b/extensions/css/server/package.json @@ -8,7 +8,7 @@ "node": "*" }, "dependencies": { - "vscode-css-languageservice": "^2.1.1", + "vscode-css-languageservice": "^2.1.2", "vscode-languageserver": "^3.2.0" }, "devDependencies": {