From 86df35e80fa41858977ffa43b1c51ab8f4934dbd Mon Sep 17 00:00:00 2001 From: Martin Aeschlimann Date: Tue, 14 Mar 2017 10:43:09 +0100 Subject: [PATCH] [themes] api polish, split editor colors --- .../editor/common/view/editorColorRegistry.ts | 109 +++++++ .../editor/contrib/find/browser/findWidget.ts | 16 + .../wordHighlighter/common/wordHighlighter.ts | 55 ++++ src/vs/platform/theme/common/colorRegistry.ts | 179 +++++++++++ src/vs/platform/theme/common/themeService.ts | 74 ++++- .../platform/theme/common/themingRegistry.ts | 120 -------- .../parts/search/browser/searchViewlet.ts | 15 +- .../themes/common/colorThemeSchema.ts | 4 +- .../themes/electron-browser/colorThemeData.ts | 35 +-- .../electron-browser/stylesContributions.ts | 278 +++--------------- .../themes/electron-browser/themeService.ts | 31 +- 11 files changed, 507 insertions(+), 409 deletions(-) create mode 100644 src/vs/editor/common/view/editorColorRegistry.ts create mode 100644 src/vs/platform/theme/common/colorRegistry.ts delete mode 100644 src/vs/platform/theme/common/themingRegistry.ts diff --git a/src/vs/editor/common/view/editorColorRegistry.ts b/src/vs/editor/common/view/editorColorRegistry.ts new file mode 100644 index 00000000000..e669e0d4558 --- /dev/null +++ b/src/vs/editor/common/view/editorColorRegistry.ts @@ -0,0 +1,109 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +/** + * Definition of the editor colors + */ + +import nls = require('vs/nls'); +import * as colorRegistry from 'vs/platform/theme/common/colorRegistry'; +import { Registry } from 'vs/platform/platform'; +import { ITheme, ICssStyleCollector, Extensions as ThemingExtensions, IThemingRegistry } from 'vs/platform/theme/common/themeService'; +import { Color } from 'vs/base/common/color'; + + +let colorReg = Registry.as(colorRegistry.Extensions.ColorContribution); +let themingReg = Registry.as(ThemingExtensions.ThemingContribution); +themingReg.onThemeChange(applyEditorStyles); + +function registerColor(id: string, defaults: colorRegistry.ColorDefaults, description: string): colorRegistry.ColorIdentifier { + return colorReg.registerColor(id, defaults, description); +} + +export const editorHoverHighlight = registerColor('editorHoverHighlight', { light: '#ADD6FF26', dark: '#264f7840', hc: '#ADD6FF26' }, nls.localize('hoverHighlight', 'Background color of the editor hover')); +export const editorActiveLinkForeground = registerColor('editorActiveLinkForeground', { dark: '#4E94CE', light: Color.black, hc: Color.cyan }, nls.localize('activeLinkForeground', 'Color of active links')); +export const editorLinkForeground = registerColor('editorLinkForeground', { dark: null, light: null, hc: null }, nls.localize('linkForeground', 'Color of links')); +export const referencesFindMatchHighlight = registerColor('referencesFindMatchHighlight', { dark: '#ea5c004d', light: '#ea5c004d', hc: null }, nls.localize('referencesFindMatchHighlight', 'References view match highlight color')); +export const referencesReferenceHighlight = registerColor('referencesReferenceHighlight', { dark: '#ff8f0099', light: '#f5d802de', hc: null }, nls.localize('referencesReferenceHighlight', 'References range highlight color')); +export const editorLineHighlight = registerColor('editorLineHighlight', { dark: null, light: null, hc: null }, nls.localize('lineHighlight', 'Editor line highlight color')); +export const editorRangeHighlight = registerColor('editorRangeHighlight', { dark: '#ffffff0b', light: '#fdff0033', hc: null }, nls.localize('rangeHighlight', 'Background color of range highlighted, like by Quick open and Find features')); +export const editorCursor = registerColor('editorCursor', { dark: '#AEAFAD', light: Color.black, hc: Color.white }, nls.localize('caret', 'Editor cursor color')); +export const editorInvisibles = registerColor('editorInvisibles', { dark: '#e3e4e229', light: '#33333333', hc: '#e3e4e229' }, nls.localize('invisibles', 'Editor invisibles color')); +export const editorGuide = registerColor('editorGuide', { dark: '#404040', light: Color.lightgrey, hc: Color.white }, nls.localize('guide', 'Editor guide color')); + +// TBD: split up and place each rule in the owning part +function applyEditorStyles(theme: ITheme, collector: ICssStyleCollector) { + + let background = theme.getColor(colorRegistry.editorBackground); + if (background) { + addBackgroundColorRule(theme, '.monaco-editor-background', background, collector); + addBackgroundColorRule(theme, '.glyph-margin', background, collector); + collector.addRule(`.${theme.selector} .monaco-workbench .monaco-editor-background { background-color: ${background}; }`); + } + + addBackgroundColorRule(theme, '.hoverHighlight', theme.getColor(editorHoverHighlight), collector); + + let activeLinkForeground = theme.getColor(editorActiveLinkForeground); + if (activeLinkForeground) { + collector.addRule(`.monaco-editor.${theme.selector} .detected-link-active { color: ${activeLinkForeground} !important; }`); + collector.addRule(`.monaco-editor.${theme.selector} .goto-definition-link { color: ${activeLinkForeground} !important; }`); + } + let linkForeground = theme.getColor(editorLinkForeground); + if (linkForeground) { + collector.addRule(`.monaco-editor.${theme.selector} .detected-link { color: ${linkForeground} !important; }`); + } + + let selection = theme.getColor(colorRegistry.editorSelection); + if (selection) { + addBackgroundColorRule(theme, '.focused .selected-text', selection, collector); + } + + let inactiveSelection = theme.getColor(colorRegistry.editorInactiveSelection, false); + if (inactiveSelection) { + addBackgroundColorRule(theme, '.selected-text', inactiveSelection, collector); + } else if (selection) { + addBackgroundColorRule(theme, '.selected-text', selection.transparent(0.5), collector); + } + + + addBackgroundColorRule(theme, '.reference-zone-widget .ref-tree .referenceMatch', theme.getColor(referencesFindMatchHighlight), collector); + addBackgroundColorRule(theme, '.reference-zone-widget .preview .reference-decoration', theme.getColor(referencesReferenceHighlight), collector); + + let lineHighlight = theme.getColor(editorLineHighlight); + if (lineHighlight) { + collector.addRule(`.monaco-editor.${theme.selector} .view-overlays .current-line { background-color: ${lineHighlight}; border: none; }`); + collector.addRule(`.monaco-editor.${theme.selector} .margin-view-overlays .current-line-margin { background-color: ${lineHighlight}; border: none; }`); + } else { + // to do editor line border + } + addBackgroundColorRule(theme, '.rangeHighlight', theme.getColor(editorRangeHighlight), collector); + + let caret = theme.getColor(editorCursor); + if (caret) { + let oppositeCaret = caret.opposite(); + collector.addRule(`.monaco-editor.${theme.selector} .cursor { background-color: ${caret}; border-color: ${caret}; color: ${oppositeCaret}; }`); + } + + let invisibles = theme.getColor(editorInvisibles); + if (invisibles) { + collector.addRule(`.vs-whitespace { color: ${invisibles} !important; }`); + } + + let color = theme.getColor(editorGuide); + if (!color) { + color = theme.getColor(editorInvisibles); + } + if (color !== null) { + collector.addRule(`.monaco-editor.${theme.selector} .lines-content .cigr { background: ${color}; }`); + } +} + +function addBackgroundColorRule(theme: ITheme, selector: string, color: Color, collector: ICssStyleCollector): void { + if (color) { + collector.addRule(`.monaco-editor.${theme.selector} ${selector} { background-color: ${color}; }`); + } +} + + diff --git a/src/vs/editor/contrib/find/browser/findWidget.ts b/src/vs/editor/contrib/find/browser/findWidget.ts index cab88530944..7eea9113239 100644 --- a/src/vs/editor/contrib/find/browser/findWidget.ts +++ b/src/vs/editor/contrib/find/browser/findWidget.ts @@ -25,6 +25,10 @@ import { Range } from 'vs/editor/common/core/range'; import { IContextKeyService, IContextKey } from 'vs/platform/contextkey/common/contextkey'; import { CONTEXT_FIND_INPUT_FOCUSSED } from 'vs/editor/contrib/find/common/findController'; +import * as colorRegistry from 'vs/platform/theme/common/colorRegistry'; +import { ITheme, ICssStyleCollector, registerThemingParticipant } from 'vs/platform/theme/common/themeService'; +import { Color } from 'vs/base/common/color'; + export interface IFindController { replace(): void; replaceAll(): void; @@ -768,3 +772,15 @@ class SimpleButton extends Widget { dom.toggleClass(this._domNode, className, shouldHaveIt); } } + +registerThemingParticipant((theme: ITheme, collector: ICssStyleCollector) => { + addBackgroundColorRule(theme, '.findMatch', theme.getColor(colorRegistry.editorFindMatchHighlight), collector); + addBackgroundColorRule(theme, '.currentFindMatch', theme.getColor(colorRegistry.editorCurrentFindMatchHighlight), collector); + addBackgroundColorRule(theme, '.findScope', theme.getColor(colorRegistry.editorFindRangeHighlight), collector); +}); + +function addBackgroundColorRule(theme: ITheme, selector: string, color: Color, collector: ICssStyleCollector): void { + if (color) { + collector.addRule(`.monaco-editor.${theme.selector} ${selector} { background-color: ${color}; }`); + } +} \ No newline at end of file diff --git a/src/vs/editor/contrib/wordHighlighter/common/wordHighlighter.ts b/src/vs/editor/contrib/wordHighlighter/common/wordHighlighter.ts index 78edca72e37..505e85d5a62 100644 --- a/src/vs/editor/contrib/wordHighlighter/common/wordHighlighter.ts +++ b/src/vs/editor/contrib/wordHighlighter/common/wordHighlighter.ts @@ -4,6 +4,8 @@ *--------------------------------------------------------------------------------------------*/ 'use strict'; +import nls = require('vs/nls'); + import { sequence, asWinJsPromise } from 'vs/base/common/async'; import { onUnexpectedExternalError } from 'vs/base/common/errors'; import { TPromise } from 'vs/base/common/winjs.base'; @@ -14,6 +16,14 @@ import { DocumentHighlight, DocumentHighlightKind, DocumentHighlightProviderRegi import { IDisposable, dispose } from 'vs/base/common/lifecycle'; import { Position } from 'vs/editor/common/core/position'; +import * as colorRegistry from 'vs/platform/theme/common/colorRegistry'; +import { ITheme, ICssStyleCollector, registerThemingParticipant } from 'vs/platform/theme/common/themeService'; +import { Color } from 'vs/base/common/color'; + +export const editorWordHighlight = colorRegistry.registerColor('editorWordHighlight', { dark: '#575757B8', light: '#57575740', hc: null }, nls.localize('wordHighlight', 'Background color of a symbol during read-access, like reading a variable')); +export const editorWordHighlightString = colorRegistry.registerColor('editorWordHighlightStrong', { dark: '#004972B8', light: '#0e639c40', hc: null }, nls.localize('wordHighlightStrong', 'Background color of a symbol during write-access, like writing to a variable')); + + export function getOccurrencesAtPosition(model: editorCommon.IReadOnlyModel, position: Position): TPromise { const orderedByScore = DocumentHighlightProviderRegistry.ordered(model); @@ -307,3 +317,48 @@ class WordHighlighterContribution implements editorCommon.IEditorContribution { this.wordHighligher.dispose(); } } + +registerThemingParticipant((theme: ITheme, collector: ICssStyleCollector) => { + let selectionHighlightColor = getSelectionHighlightColor(theme); + if (selectionHighlightColor) { + addBackgroundColorRule(theme, '.focused .selectionHighlight', selectionHighlightColor, collector); + addBackgroundColorRule(theme, '.selectionHighlight', selectionHighlightColor.transparent(0.5), collector); + } + + addBackgroundColorRule(theme, '.wordHighlight', theme.getColor(editorWordHighlight), collector); + addBackgroundColorRule(theme, '.wordHighlightStrong', theme.getColor(editorWordHighlightString), collector); + +}); + +function getSelectionHighlightColor(theme: ITheme) { + let selectionHighlight = theme.getColor(colorRegistry.editorSelectionHighlightColor); + if (selectionHighlight) { + return selectionHighlight; + } + + let selection = theme.getColor(colorRegistry.editorSelection); + let background = theme.getColor(colorRegistry.editorBackground); + + if (selection && background) { + return deriveLessProminentColor(selection, background); + } + + return null; +} + +function addBackgroundColorRule(theme: ITheme, selector: string, color: Color, collector: ICssStyleCollector): void { + if (color) { + collector.addRule(`.monaco-editor.${theme.selector} ${selector} { background-color: ${color}; }`); + } +} + +function deriveLessProminentColor(from: Color, backgroundColor: Color): Color { + let contrast = from.getContrast(backgroundColor); + if (contrast < 1.7 || contrast > 4.5) { + return null; + } + if (from.isDarkerThan(backgroundColor)) { + return Color.getLighterColor(from, backgroundColor, 0.4); + } + return Color.getDarkerColor(from, backgroundColor, 0.4); +} \ No newline at end of file diff --git a/src/vs/platform/theme/common/colorRegistry.ts b/src/vs/platform/theme/common/colorRegistry.ts new file mode 100644 index 00000000000..86ef0a2b3c1 --- /dev/null +++ b/src/vs/platform/theme/common/colorRegistry.ts @@ -0,0 +1,179 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +'use strict'; + +import platform = require('vs/platform/platform'); +import { IJSONSchema } from 'vs/base/common/jsonSchema'; +import { Color } from 'vs/base/common/color'; +import { ITheme } from 'vs/platform/theme/common/themeService'; + +import nls = require('vs/nls'); + +// ------ API types + +export type ColorIdentifier = string; + +export interface ColorContribution { + readonly id: ColorIdentifier; + readonly description: string; + readonly defaults: ColorDefaults; +} + + +export interface ColorFunction { + (theme: ITheme): Color; +} + +export interface ColorDefaults { + light: ColorValue; + dark: ColorValue; + hc: ColorValue; +} + +/** + * A Color Value is either a color literal, a refence to other color or a derived color + */ +export type ColorValue = Color | string | ColorIdentifier | ColorFunction; + +// color registry +export const Extensions = { + ColorContribution: 'base.contributions.colors' +}; + +export interface IColorRegistry { + + /** + * Register a color to the registry. + * @param id The color id as used in theme descrition files + * @param defaults The default values + * @description the description + */ + registerColor(id: string, defaults: ColorDefaults, description: string): ColorIdentifier; + + /** + * Get all color contributions + */ + getColors(): ColorContribution[]; + + /** + * Gets the default color of the given id + */ + resolveDefaultColor(id: ColorIdentifier, theme: ITheme): Color; + + /** + * JSON schema of all colors + */ + getColorSchema(): IJSONSchema; + +} + +class ColorRegistry implements IColorRegistry { + private colorsById: { [key: string]: ColorContribution }; + private colorSchema: IJSONSchema = { type: 'object', description: nls.localize('schema.colors', 'Colors used in the workbench.'), properties: {} }; + + constructor() { + this.colorsById = {}; + } + + public registerColor(id: string, defaults: ColorDefaults, description: string): ColorIdentifier { + let colorContribution = { id, description, defaults }; + this.colorsById[id] = colorContribution; + this.colorSchema.properties[id] = { type: 'string', description }; + return id; + } + + public getColors(): ColorContribution[] { + return Object.keys(this.colorsById).map(id => this.colorsById[id]); + } + + public resolveDefaultColor(id: ColorIdentifier, theme: ITheme): Color { + let colorDesc = this.colorsById[id]; + if (colorDesc) { + let colorValue = colorDesc.defaults[theme.type]; + return resolveColorValue(colorValue, theme); + } + return null; + } + + public getColorSchema(): IJSONSchema { + return this.colorSchema; + } + +} + +const colorRegistry = new ColorRegistry(); +platform.Registry.add(Extensions.ColorContribution, colorRegistry); + +export function registerColor(id: string, defaults: ColorDefaults, description: string): ColorIdentifier { + return colorRegistry.registerColor(id, defaults, description); +} + + +// ----- base colors + +/** + * Editor background color. + * Because of bug https://monacotools.visualstudio.com/DefaultCollection/Monaco/_workitems/edit/13254 + * we are *not* using the color white (or #ffffff, rgba(255,255,255)) but something very close to white. + */ +export const editorBackground = registerColor('editorBackground', { light: '#fffffe', dark: '#1E1E1E', hc: Color.black }, nls.localize('editorBackground', 'Editor background color')); + +/** + * Editor foreground color. + */ +export const editorForeground = registerColor('editorForeground', { light: '#333333', dark: '#BBBBBB', hc: Color.white }, nls.localize('editorForeground', 'Editor default foreground color')); + +/** + * Editor selection colors. + */ +export const editorSelection = registerColor('editorSelection', { light: '#ADD6FF', dark: '#264F78', hc: '#f3f518' }, nls.localize('editorSelection', 'Color of the editor selection')); +export const editorInactiveSelection = registerColor('editorInactiveSelection', { light: '#E5EBF1', dark: '#3A3D41', hc: null }, nls.localize('editorInactiveSelection', 'Color of the inactive editor selection')); +export const editorSelectionHighlightColor = registerColor('editorSelectionHighlightColor', { light: Color.white, dark: '#1E1E1E', hc: Color.black }, nls.localize('editorsSelectionHighlightColor', 'Background color of regions highlighted while selecting')); + +/** + * Editor find match colors. + */ +export const editorFindMatchHighlight = registerColor('editorFindMatchHighlight', { light: '#EA5C0055', dark: '#EA5C0055', hc: null }, nls.localize('findMatchHighlight', 'Background color of regions matching the search')); +export const editorCurrentFindMatchHighlight = registerColor('editorCurrentFindMatchHighlight', { light: '#A8AC94', dark: '#515C6A', hc: null }, nls.localize('currentFindMatchHighlight', 'Background color of the current region matching the search')); +export const editorFindRangeHighlight = registerColor('editorFindRangeHighlight', { dark: '#3a3d4166', light: '#b4b4b44d', hc: null }, nls.localize('findRangeHighlight', 'Background color of regions selected for search')); + + +// ----- color functions + +export function darken(colorValue: ColorValue, factor: number): ColorFunction { + return (theme) => { + let color = resolveColorValue(colorValue, theme); + if (color) { + return color.darken(factor); + } + return null; + }; +} + +// ----- implementation + +/** + * @param colorValue Resolve a color value in the context of a theme + */ +function resolveColorValue(colorValue: ColorValue, theme: ITheme): Color { + if (colorValue === null) { + return null; + } else if (typeof colorValue === 'string') { + if (colorValue[0] === '#') { + return Color.fromHex(colorValue); + } + return theme.getColor(colorValue); + } else if (colorValue instanceof Color) { + return colorValue; + } else if (typeof colorValue === 'function') { + return colorValue(theme); + } + return null; +} + + + + + diff --git a/src/vs/platform/theme/common/themeService.ts b/src/vs/platform/theme/common/themeService.ts index 859eadbde11..1749ccc2acb 100644 --- a/src/vs/platform/theme/common/themeService.ts +++ b/src/vs/platform/theme/common/themeService.ts @@ -6,37 +6,91 @@ import { createDecorator } from 'vs/platform/instantiation/common/instantiation'; import { Color } from 'vs/base/common/color'; -import Event from 'vs/base/common/event'; import { IDisposable } from 'vs/base/common/lifecycle'; +import platform = require('vs/platform/platform'); +import { ColorIdentifier } from 'vs/platform/theme/common/colorRegistry'; export let IThemeService = createDecorator('themeService'); +// base themes +export type ThemeType = 'light' | 'dark' | 'hc'; + + export interface ITheme { readonly selector: string; readonly label: string; - getColor(color: string): Color; + readonly type: ThemeType; + + /** + * Resolves the color of the given color identifer. If the theme does not + * sepcify the color, the default color is returned unless useDefault is set to false. + * @param color the id of the color + * @param useDefault specifies if the default color should be used. If not set, the default is used. + */ + getColor(color: ColorIdentifier, useDefault?: boolean): Color; +} - isLightTheme(): boolean; - isDarkTheme(): boolean; +export interface ICssStyleCollector { + addRule(rule: string): void; } export interface IThemingParticipant { - (theme: ITheme, result: string[]): void; + (theme: ITheme, collector: ICssStyleCollector): void; } export interface IThemeService { _serviceBrand: any; - getTheme(): ITheme; - onDidThemeChange: Event; + getTheme(): ITheme; /** - * Register a theming participant to the registry. + * Register a theming participant that is invoked on every theme change. */ - registerThemingParticipant(participant: IThemingParticipant): IDisposable; + onThemeChange(participant: IThemingParticipant): IDisposable; + +} + +// static theming participant +export const Extensions = { + ThemingContribution: 'base.contributions.theming' +}; + +export interface IThemingRegistry { /** - * Get all theming participants + * Register a theming participant that is invoked on every theme change. */ + onThemeChange(participant: IThemingParticipant): IDisposable; + getThemingParticipants(): IThemingParticipant[]; +} + +class ThemingRegistry implements IThemingRegistry { + private themingParticipants: IThemingParticipant[] = []; + + constructor() { + this.themingParticipants = []; + } + + public onThemeChange(participant: IThemingParticipant): IDisposable { + this.themingParticipants.push(participant); + + return { + dispose: () => { + const idx = this.themingParticipants.indexOf(participant); + this.themingParticipants.splice(idx, 1); + } + }; + } + + public getThemingParticipants(): IThemingParticipant[] { + return this.themingParticipants; + } +} + +let themingRegistry = new ThemingRegistry(); +platform.Registry.add(Extensions.ThemingContribution, themingRegistry); + +export function registerThemingParticipant(participant: IThemingParticipant): IDisposable { + return themingRegistry.onThemeChange(participant); } \ No newline at end of file diff --git a/src/vs/platform/theme/common/themingRegistry.ts b/src/vs/platform/theme/common/themingRegistry.ts deleted file mode 100644 index 9edb2f9ffb8..00000000000 --- a/src/vs/platform/theme/common/themingRegistry.ts +++ /dev/null @@ -1,120 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ -'use strict'; - -import platform = require('vs/platform/platform'); -import { IJSONSchema } from 'vs/base/common/jsonSchema'; -import { Color } from 'vs/base/common/color'; -import { ITheme } from 'vs/platform/theme/common/themeService'; - -import nls = require('vs/nls'); - -export const Extensions = { - ThemingContribution: 'base.contributions.theming' -}; - -export interface IColorContribution { - readonly id: string; - readonly description: string; - readonly defaults: ColorDefaults; -} - -export interface DerivedColor { - (theme: ITheme): Color; -} - -export interface ColorDefaults { - light: ColorValue; - dark: ColorValue; - hc: ColorValue; -} - -// either a hex color literal (#RRGGBB or #RRBBGGAA) or a refence to other color or a derived color -export type ColorValue = string | IColorContribution | DerivedColor; - - -export interface IThemingRegistry { - - /** - * Register a color to the registry. - */ - registerColor(id: string, description: string, defaults?: ColorDefaults): IColorContribution; - - /** - * Get all color contributions - */ - getColors(): IColorContribution[]; - - /** - * Gets the color of the given id - */ - getColor(id: string): IColorContribution; - - /** - * JSON schema of all colors - */ - getColorSchema(): IJSONSchema; - -} - -export function darken(colorValue: ColorValue, factor: number): DerivedColor { - return (theme) => { - let color = resolveColorValue(colorValue, theme); - if (color) { - return color.darken(factor); - } - return null; - }; -} - - -class ThemingRegistry implements IThemingRegistry { - private colorsById: { [key: string]: IColorContribution }; - private colorSchema: IJSONSchema = { type: 'object', description: nls.localize('schema.colors', 'Colors used in the workbench.'), properties: {} }; - - constructor() { - this.colorsById = {}; - } - - public registerColor(id: string, description: string, defaults: ColorDefaults): IColorContribution { - let colorContribution: IColorContribution = { id, description, defaults }; - this.colorsById[id] = colorContribution; - this.colorSchema.properties[id] = { type: 'string', description }; - return colorContribution; - } - - public getColors(): IColorContribution[] { - return Object.keys(this.colorsById).map(id => this.colorsById[id]); - } - - public getColor(id: string): IColorContribution { - return this.colorsById[id]; - } - - public getColorSchema(): IJSONSchema { - return this.colorSchema; - } - -} - -/** - * @param colorValue Resolve a color value in the context of a theme - */ -export function resolveColorValue(colorValue: ColorValue, theme: ITheme): Color { - if (colorValue === null) { - return null; - } else if (typeof colorValue === 'string') { - return Color.fromHex(colorValue); - } else if (typeof colorValue === 'object' && colorValue.id) { - return theme.getColor(colorValue.id); - } else if (typeof colorValue === 'function') { - return colorValue(theme); - } - return null; -} - - -const themingRegistry = new ThemingRegistry(); -platform.Registry.add(Extensions.ThemingContribution, themingRegistry); \ No newline at end of file diff --git a/src/vs/workbench/parts/search/browser/searchViewlet.ts b/src/vs/workbench/parts/search/browser/searchViewlet.ts index ff16885f859..8ee5cc7ec90 100644 --- a/src/vs/workbench/parts/search/browser/searchViewlet.ts +++ b/src/vs/workbench/parts/search/browser/searchViewlet.ts @@ -58,6 +58,8 @@ import { IUntitledEditorService } from 'vs/workbench/services/untitled/common/un import { OpenFolderAction, OpenFileFolderAction } from 'vs/workbench/browser/actions/fileActions'; import * as Constants from 'vs/workbench/parts/search/common/constants'; import { IListService } from 'vs/platform/list/browser/listService'; +import { IThemeService, ITheme, ICssStyleCollector } from 'vs/platform/theme/common/themeService'; +import * as colorRegistry from 'vs/platform/theme/common/colorRegistry'; export class SearchViewlet extends Viewlet { @@ -112,7 +114,8 @@ export class SearchViewlet extends Viewlet { @IReplaceService private replaceService: IReplaceService, @IUntitledEditorService private untitledEditorService: IUntitledEditorService, @IPreferencesService private preferencesService: IPreferencesService, - @IListService private listService: IListService + @IListService private listService: IListService, + @IThemeService private themeService: IThemeService ) { super(Constants.VIEWLET_ID, telemetryService); @@ -128,6 +131,8 @@ export class SearchViewlet extends Viewlet { this.toUnbind.push(this.untitledEditorService.onDidChangeDirty(e => this.onUntitledDidChangeDirty(e))); this.toUnbind.push(this.configurationService.onDidUpdateConfiguration(e => this.onConfigurationUpdated(e.config))); + this.toUnbind.push(this.themeService.onThemeChange(this.applyTheme.bind(this))); + this.selectCurrentMatchEmitter = new Emitter(); debounceEvent(this.selectCurrentMatchEmitter.event, (l, e) => e, 100, /*leading=*/true) (() => this.selectCurrentMatch()); @@ -139,6 +144,14 @@ export class SearchViewlet extends Viewlet { this.updateGlobalPatternExclusions(configuration); } + private applyTheme(theme: ITheme, collector: ICssStyleCollector) { + let matchHighlightColor = theme.getColor(colorRegistry.editorFindMatchHighlight); + if (matchHighlightColor) { + collector.addRule(`.search-viewlet .findInFileMatch { background-color: ${matchHighlightColor}; }`); + collector.addRule(`.search-viewlet .highlight { background-color: ${matchHighlightColor}; }`); + } + } + public create(parent: Builder): TPromise { super.create(parent); diff --git a/src/vs/workbench/services/themes/common/colorThemeSchema.ts b/src/vs/workbench/services/themes/common/colorThemeSchema.ts index bace23782c2..2bb29d4197e 100644 --- a/src/vs/workbench/services/themes/common/colorThemeSchema.ts +++ b/src/vs/workbench/services/themes/common/colorThemeSchema.ts @@ -8,9 +8,9 @@ import { Registry } from 'vs/platform/platform'; import { Extensions as JSONExtensions, IJSONContributionRegistry } from 'vs/platform/jsonschemas/common/jsonContributionRegistry'; import { IJSONSchema } from 'vs/base/common/jsonSchema'; -import { Extensions as ThemeingExtensions, IThemingRegistry } from 'vs/platform/theme/common/themingRegistry'; +import { Extensions as ThemeingExtensions, IColorRegistry } from 'vs/platform/theme/common/colorRegistry'; -let themingRegistry = Registry.as(ThemeingExtensions.ThemingContribution); +let themingRegistry = Registry.as(ThemeingExtensions.ColorContribution); let textMateScopes = [ 'comment', 'comment.block', diff --git a/src/vs/workbench/services/themes/electron-browser/colorThemeData.ts b/src/vs/workbench/services/themes/electron-browser/colorThemeData.ts index a1585719cca..b1c1ede3b61 100644 --- a/src/vs/workbench/services/themes/electron-browser/colorThemeData.ts +++ b/src/vs/workbench/services/themes/electron-browser/colorThemeData.ts @@ -6,7 +6,7 @@ import Paths = require('vs/base/common/paths'); import Json = require('vs/base/common/json'); import { Color } from 'vs/base/common/color'; -import { ExtensionData, ITokenColorizationRule, IColorTheme, IColorMap } from 'vs/workbench/services/themes/common/themeService'; +import { ExtensionData, ITokenColorizationRule, IColorTheme, IColorMap, VS_LIGHT_THEME, VS_HC_THEME } from 'vs/workbench/services/themes/common/themeService'; import { convertSettings } from 'vs/workbench/services/themes/electron-browser/stylesContributions'; import { TPromise } from 'vs/base/common/winjs.base'; import { getBaseThemeId, getSyntaxThemeId, isDarkTheme, isLightTheme } from 'vs/platform/theme/common/themes'; @@ -16,10 +16,11 @@ import * as types from 'vs/base/common/types'; import * as plist from 'fast-plist'; import pfs = require('vs/base/node/pfs'); -import { Extensions, IThemingRegistry, resolveColorValue } from 'vs/platform/theme/common/themingRegistry'; +import { Extensions, IColorRegistry, ColorIdentifier } from 'vs/platform/theme/common/colorRegistry'; +import { ThemeType } from 'vs/platform/theme/common/themeService'; import { Registry } from 'vs/platform/platform'; -let themingRegistry = Registry.as(Extensions.ThemingContribution); +let colorRegistry = Registry.as(Extensions.ColorContribution); export class ColorThemeData implements IColorTheme { @@ -34,26 +35,14 @@ export class ColorThemeData implements IColorTheme { extensionData: ExtensionData; colorMap?: IColorMap; - public getColor(colorId: string): Color { + public getColor(colorId: ColorIdentifier, useDefault?: boolean): Color { if (!this.colorMap) { - // not yet initialized - return null; + return null; // not yet initialized } let color = this.colorMap[colorId]; - if (types.isUndefined(color)) { - color = null; - let colorDesc = themingRegistry.getColor(colorId); - if (colorDesc && colorDesc.defaults) { - let defaults = colorDesc.defaults; - if (this.isLightTheme()) { - color = resolveColorValue(defaults.light, this); - } else if (this.isDarkTheme()) { - color = resolveColorValue(defaults.dark, this); - } else { - color = resolveColorValue(defaults.hc, this); - } - } + if (useDefault !== false && types.isUndefined(color)) { + color = colorRegistry.resolveDefaultColor(colorId, this); this.colorMap[colorId] = color; } return color; @@ -83,6 +72,14 @@ export class ColorThemeData implements IColorTheme { return JSON.stringify(content, null, '\t'); } + get type(): ThemeType { + switch (this.getBaseThemeId()) { + case VS_LIGHT_THEME: return 'light'; + case VS_HC_THEME: return 'hc'; + default: return 'dark'; + } + } + isLightTheme() { return isLightTheme(this.id); } diff --git a/src/vs/workbench/services/themes/electron-browser/stylesContributions.ts b/src/vs/workbench/services/themes/electron-browser/stylesContributions.ts index 4f8fb606288..2f67a926848 100644 --- a/src/vs/workbench/services/themes/electron-browser/stylesContributions.ts +++ b/src/vs/workbench/services/themes/electron-browser/stylesContributions.ts @@ -7,11 +7,12 @@ import nls = require('vs/nls'); import { ITokenColorizationRule, IColorMap } from 'vs/workbench/services/themes/common/themeService'; import { Color } from 'vs/base/common/color'; -import { Extensions, IThemingRegistry } from 'vs/platform/theme/common/themingRegistry'; -import { Registry } from 'vs/platform/platform'; -import { ITheme, IThemeService } from 'vs/platform/theme/common/themeService'; +import * as colorRegistry from 'vs/platform/theme/common/colorRegistry'; +import { ITheme, ICssStyleCollector, registerThemingParticipant } from 'vs/platform/theme/common/themeService'; + +import * as editorColorRegistry from 'vs/editor/common/view/editorColorRegistry'; +import * as wordHighlighter from 'vs/editor/contrib/wordHighlighter/common/wordHighlighter'; -let themingRegistry = Registry.as(Extensions.ThemingContribution); const settingToColorIdMapping: { [settingId: string]: string[] } = {}; function addSettingMapping(settingId: string, colorId: string) { @@ -43,7 +44,25 @@ export function convertSettings(oldSettings: ITokenColorizationRule[], resultRul } } - +addSettingMapping('background', colorRegistry.editorBackground); +addSettingMapping('selection', colorRegistry.editorSelection); +addSettingMapping('inactiveSelection', colorRegistry.editorInactiveSelection); +addSettingMapping('selectionHighlightColor', colorRegistry.editorSelectionHighlightColor); +addSettingMapping('findMatchHighlight', colorRegistry.editorFindMatchHighlight); +addSettingMapping('currentFindMatchHighlight', colorRegistry.editorCurrentFindMatchHighlight); +addSettingMapping('hoverHighlight', editorColorRegistry.editorHoverHighlight); +addSettingMapping('hoverHighlight', editorColorRegistry.editorHoverHighlight); +addSettingMapping('linkForeground', editorColorRegistry.editorLinkForeground); +addSettingMapping('wordHighlight', wordHighlighter.editorWordHighlight); +addSettingMapping('wordHighlightStrong', wordHighlighter.editorWordHighlightString); +addSettingMapping('findRangeHighlight', colorRegistry.editorFindRangeHighlight); +addSettingMapping('findMatchHighlight', editorColorRegistry.referencesFindMatchHighlight); +addSettingMapping('referenceHighlight', editorColorRegistry.referencesReferenceHighlight); +addSettingMapping('lineHighlight', editorColorRegistry.editorLineHighlight); +addSettingMapping('rangeHighlight', editorColorRegistry.editorRangeHighlight); +addSettingMapping('caret', editorColorRegistry.editorCursor); +addSettingMapping('invisibles', editorColorRegistry.editorInvisibles); +addSettingMapping('guide', editorColorRegistry.editorGuide); const ansiColorMap = { @@ -68,247 +87,24 @@ const keyPrefix = 'terminal'; for (let key in ansiColorMap) { let id = keyPrefix + key[0].toUpperCase() + key.substr(1); - themingRegistry.registerColor(id, nls.localize('terminal.ansiColor', 'Color for terminal {0} color', key)); + colorRegistry.registerColor(id, null, nls.localize('terminal.ansiColor', 'Color for terminal {0} color', key)); addSettingMapping(key, id); } - -const editorBackground = 'editorBackground'; -themingRegistry.registerColor(editorBackground, nls.localize('background', 'Editor background color')); -addSettingMapping('background', editorBackground); - - - -const editorHoverHighlight = 'editorHoverHighlight'; -themingRegistry.registerColor(editorHoverHighlight, nls.localize('hoverHighlight', 'Background color of the editor hover')); -addSettingMapping('hoverHighlight', editorHoverHighlight); - - - -const editorActiveLinkForeground = 'editorActiveLinkForeground'; -themingRegistry.registerColor(editorActiveLinkForeground, nls.localize('activeLinkForeground', 'Color of active links'), { dark: '#4E94CE', light: '#0000FF', hc: '#00FFFF' }); -addSettingMapping('hoverHighlight', editorHoverHighlight); - -const editorLinkForeground = 'editorLinkForeground'; -themingRegistry.registerColor(editorLinkForeground, nls.localize('linkForeground', 'Color of links')); -addSettingMapping('linkForeground', editorLinkForeground); - -const editorSelection = 'editorSelection'; -themingRegistry.registerColor(editorSelection, nls.localize('selection', 'Color of the editor selection')); -addSettingMapping('selection', editorSelection); - -const editorInactiveSelection = 'editorInactiveSelection'; -themingRegistry.registerColor(editorInactiveSelection, nls.localize('inactiveSelection', 'Color of the inactive editor selection')); -addSettingMapping('inactiveSelection', editorInactiveSelection); - -const editorSelectionHighlightColor = 'editorSelectionHighlightColor'; -themingRegistry.registerColor(editorSelectionHighlightColor, nls.localize('selectionHighlightColor', 'Background color of regions highlighted while selecting')); -addSettingMapping('selectionHighlightColor', editorSelectionHighlightColor); - -const editorWordHighlight = 'editorWordHighlight'; -themingRegistry.registerColor(editorWordHighlight, nls.localize('wordHighlight', 'Background color of a symbol during read-access, like reading a variable')); -addSettingMapping('wordHighlight', editorWordHighlight); - -const editorWordHighlightString = 'editorWordHighlightStrong'; -themingRegistry.registerColor(editorWordHighlightString, nls.localize('wordHighlightStrong', 'Background color of a symbol during write-access, like writing to a variable')); -addSettingMapping('wordHighlightStrong', editorWordHighlightString); - -const editorFindMatchHighlight = 'editorFindMatchHighlight'; -themingRegistry.registerColor(editorFindMatchHighlight, nls.localize('findMatchHighlight', 'Background color of regions matching the search')); -addSettingMapping('findMatchHighlight', editorFindMatchHighlight); - -const editorCurrentFindMatchHighlight = 'editorCurrentFindMatchHighlight'; -themingRegistry.registerColor(editorCurrentFindMatchHighlight, nls.localize('currentFindMatchHighlight', 'Background color of the current region matching the search')); -addSettingMapping('currentFindMatchHighlight', editorCurrentFindMatchHighlight); - -const editorFindRangeHighlight = 'editorFindRangeHighlight'; -themingRegistry.registerColor(editorFindRangeHighlight, nls.localize('findRangeHighlight', 'Background color of regions selected for search')); -addSettingMapping('findRangeHighlight', editorFindRangeHighlight); - -const referencesFindMatchHighlight = 'referencesFindMatchHighlight'; -themingRegistry.registerColor(referencesFindMatchHighlight, nls.localize('referencesFindMatchHighlight', 'References view match highlight color')); -addSettingMapping('findMatchHighlight', referencesFindMatchHighlight); - -const referencesReferenceHighlight = 'referencesReferenceHighlight'; -themingRegistry.registerColor(referencesReferenceHighlight, nls.localize('referencesReferenceHighlight', 'References range highlight color')); -addSettingMapping('referenceHighlight', referencesReferenceHighlight); - -const editorLineHighlight = 'editorLineHighlight'; -themingRegistry.registerColor(editorLineHighlight, nls.localize('lineHighlight', 'Editor line highlight color')); -addSettingMapping('lineHighlight', editorLineHighlight); - -const editorRangeHighlight = 'editorRangeHighlight'; -themingRegistry.registerColor(editorRangeHighlight, nls.localize('rangeHighlight', 'Background color of range highlighted, like by Quick open and Find features')); -addSettingMapping('rangeHighlight', editorRangeHighlight); - -const editorCursor = 'editorCursor'; -themingRegistry.registerColor(editorCursor, nls.localize('caret', 'Editor cursor color')); -addSettingMapping('caret', editorCursor); - -const editorInvisibles = 'editorInvisibles'; -themingRegistry.registerColor(editorInvisibles, nls.localize('invisibles', 'Editor invisibles color')); -addSettingMapping('invisibles', editorInvisibles); - -const editorGuide = 'editorGuide'; -themingRegistry.registerColor(editorGuide, nls.localize('guide', 'Editor guide color')); -addSettingMapping('guide', editorGuide); - -function addBackgroundColorRule(theme: ITheme, selector: string, color: Color, rules: string[]): void { - if (color) { - rules.push(`.monaco-editor.${theme.selector} ${selector} { background-color: ${color}; }`); +function updateTerminalStyles(theme: ITheme, collector: ICssStyleCollector) { + for (let key in ansiColorMap) { + const color = theme.getColor(keyPrefix + key); + if (color) { + const index = ansiColorMap[key]; + const rgba = color.transparent(0.996); + collector.addRule(`.${theme.selector} .panel.integrated-terminal .xterm .xterm-color-${index} { color: ${color}; }`); + collector.addRule(`.${theme.selector} .panel.integrated-terminal .xterm .xterm-color-${index}::selection { background-color: ${rgba}; }`); + collector.addRule(`.${theme.selector} .panel.integrated-terminal .xterm .xterm-bg-color-${index} { background-color: ${color}; }`); + collector.addRule(`.${theme.selector} .panel.integrated-terminal .xterm .xterm-bg-color-${index}::selection { color: ${color}; }`); + }; } } -function getSelectionHighlightColor(theme: ITheme) { - let selectionHighlight = theme.getColor(editorSelectionHighlightColor); - if (selectionHighlight) { - return selectionHighlight; - } +registerThemingParticipant(updateTerminalStyles); - let selection = theme.getColor(editorSelection); - let background = theme.getColor(editorBackground); - if (selection && background) { - return deriveLessProminentColor(selection, background); - } - - return null; -} - - -export function registerParticipants(service: IThemeService) { - - // search viewlet - - service.registerThemingParticipant((theme: ITheme, cssRules: string[]) => { - let matchHighlightColor = theme.getColor(editorFindMatchHighlight); - if (matchHighlightColor) { - cssRules.push(`.${theme.selector} .search-viewlet .findInFileMatch { background-color: ${matchHighlightColor}; }`); - cssRules.push(`.${theme.selector} .search-viewlet .highlight { background-color: ${matchHighlightColor}; }`); - } - }); - - service.registerThemingParticipant((theme: ITheme, cssRules: string[]) => { - for (let key in ansiColorMap) { - const color = theme.getColor(keyPrefix + key); - if (color) { - const index = ansiColorMap[key]; - const rgba = color.transparent(0.996); - cssRules.push(`.${theme.selector} .panel.integrated-terminal .xterm .xterm-color-${index} { color: ${color}; }`); - cssRules.push(`.${theme.selector} .panel.integrated-terminal .xterm .xterm-color-${index}::selection { background-color: ${rgba}; }`); - cssRules.push(`.${theme.selector} .panel.integrated-terminal .xterm .xterm-bg-color-${index} { background-color: ${color}; }`); - cssRules.push(`.${theme.selector} .panel.integrated-terminal .xterm .xterm-bg-color-${index}::selection { color: ${color}; }`); - }; - } - }); - - - service.registerThemingParticipant((theme: ITheme, cssRules: string[]) => { - let background = theme.getColor(editorBackground); - if (background) { - addBackgroundColorRule(theme, '.monaco-editor-background', background, cssRules); - addBackgroundColorRule(theme, '.glyph-margin', background, cssRules); - cssRules.push(`.${theme.selector} .monaco-workbench .monaco-editor-background { background-color: ${background}; }`); - } - }); - - service.registerThemingParticipant((theme: ITheme, cssRules: string[]) => { - addBackgroundColorRule(theme, '.hoverHighlight', theme.getColor(editorHoverHighlight), cssRules); - }); - - service.registerThemingParticipant((theme: ITheme, cssRules: string[]) => { - let activeLinkForeground = theme.getColor(editorActiveLinkForeground); - if (activeLinkForeground) { - cssRules.push(`.monaco-editor.${theme.selector} .detected-link-active { color: ${activeLinkForeground} !important; }`); - cssRules.push(`.monaco-editor.${theme.selector} .goto-definition-link { color: ${activeLinkForeground} !important; }`); - } - let linkForeground = theme.getColor(editorLinkForeground); - if (linkForeground) { - cssRules.push(`.monaco-editor.${theme.selector} .detected-link { color: ${linkForeground} !important; }`); - } - }); - - service.registerThemingParticipant((theme: ITheme, cssRules: string[]) => { - let selection = theme.getColor(editorSelection); - if (selection) { - addBackgroundColorRule(theme, '.focused .selected-text', selection, cssRules); - } - - let inactiveSelection = theme.getColor(editorInactiveSelection); - if (inactiveSelection) { - addBackgroundColorRule(theme, '.selected-text', inactiveSelection, cssRules); - } else if (selection) { - addBackgroundColorRule(theme, '.selected-text', selection.transparent(0.5), cssRules); - } - - let selectionHighlightColor = getSelectionHighlightColor(theme); - if (selectionHighlightColor) { - addBackgroundColorRule(theme, '.focused .selectionHighlight', selectionHighlightColor, cssRules); - addBackgroundColorRule(theme, '.selectionHighlight', selectionHighlightColor.transparent(0.5), cssRules); - } - }); - - service.registerThemingParticipant((theme: ITheme, cssRules: string[]) => { - addBackgroundColorRule(theme, '.wordHighlight', theme.getColor(editorWordHighlight), cssRules); - addBackgroundColorRule(theme, '.wordHighlightStrong', theme.getColor(editorWordHighlightString), cssRules); - }); - - service.registerThemingParticipant((theme: ITheme, cssRules: string[]) => { - addBackgroundColorRule(theme, '.findMatch', theme.getColor(editorFindMatchHighlight), cssRules); - addBackgroundColorRule(theme, '.currentFindMatch', theme.getColor(editorCurrentFindMatchHighlight), cssRules); - addBackgroundColorRule(theme, '.findScope', theme.getColor(editorFindRangeHighlight), cssRules); - }); - - service.registerThemingParticipant((theme: ITheme, cssRules: string[]) => { - addBackgroundColorRule(theme, '.reference-zone-widget .ref-tree .referenceMatch', theme.getColor(referencesFindMatchHighlight), cssRules); - addBackgroundColorRule(theme, '.reference-zone-widget .preview .reference-decoration', theme.getColor(referencesReferenceHighlight), cssRules); - }); - - service.registerThemingParticipant((theme: ITheme, cssRules: string[]) => { - let lineHighlight = theme.getColor(editorLineHighlight); - if (lineHighlight) { - cssRules.push(`.monaco-editor.${theme.selector} .view-overlays .current-line { background-color: ${lineHighlight}; border: none; }`); - cssRules.push(`.monaco-editor.${theme.selector} .margin-view-overlays .current-line-margin { background-color: ${lineHighlight}; border: none; }`); - } - addBackgroundColorRule(theme, '.rangeHighlight', theme.getColor(editorRangeHighlight), cssRules); - }); - - service.registerThemingParticipant((theme: ITheme, cssRules: string[]) => { - let caret = theme.getColor(editorCursor); - if (caret) { - let oppositeCaret = caret.opposite(); - cssRules.push(`.monaco-editor.${theme.selector} .cursor { background-color: ${caret}; border-color: ${caret}; color: ${oppositeCaret}; }`); - } - }); - - service.registerThemingParticipant((theme: ITheme, cssRules: string[]) => { - let invisibles = theme.getColor(editorInvisibles); - if (invisibles) { - cssRules.push(`.vs-whitespace { color: ${invisibles} !important; }`); - } - }); - - - service.registerThemingParticipant((theme: ITheme, cssRules: string[]) => { - let color = theme.getColor(editorGuide); - if (!color) { - color = theme.getColor(editorInvisibles); - } - if (color !== null) { - cssRules.push(`.monaco-editor.${theme.selector} .lines-content .cigr { background: ${color}; }`); - } - }); -} - - - -function deriveLessProminentColor(from: Color, backgroundColor: Color): Color { - let contrast = from.getContrast(backgroundColor); - if (contrast < 1.7 || contrast > 4.5) { - return null; - } - if (from.isDarkerThan(backgroundColor)) { - return Color.getLighterColor(from, backgroundColor, 0.4); - } - return Color.getDarkerColor(from, backgroundColor, 0.4); -} \ No newline at end of file diff --git a/src/vs/workbench/services/themes/electron-browser/themeService.ts b/src/vs/workbench/services/themes/electron-browser/themeService.ts index b683954f57d..62b727db185 100644 --- a/src/vs/workbench/services/themes/electron-browser/themeService.ts +++ b/src/vs/workbench/services/themes/electron-browser/themeService.ts @@ -28,8 +28,7 @@ import { IMessageService } from 'vs/platform/message/common/message'; import Severity from 'vs/base/common/severity'; import URI from 'vs/base/common/uri'; import { ColorThemeData } from './colorThemeData'; -import { ITheme, IThemingParticipant } from 'vs/platform/theme/common/themeService'; -import { registerParticipants } from 'vs/workbench/services/themes/electron-browser/stylesContributions'; +import { ITheme, IThemingParticipant, Extensions as ThemingExtensions, IThemingRegistry } from 'vs/platform/theme/common/themeService'; import { $ } from 'vs/base/browser/builder'; import Event, { Emitter } from 'vs/base/common/event'; @@ -53,6 +52,8 @@ const oldDefaultThemeExtensionId = 'vscode-theme-colorful-defaults'; const fileIconsEnabledClass = 'file-icons-enabled'; +const themingRegistry = Registry.as(ThemingExtensions.ThemingContribution); + function validateThemeId(theme: string): string { // migrations switch (theme) { @@ -117,8 +118,6 @@ let iconThemeExtPoint = ExtensionsRegistry.registerExtensionPoint { - return this.onColorThemeChange.event; - } - public get onDidFileIconThemeChange(): Event { return this.onFileIconThemeChange.event; } - public registerThemingParticipant(participant: IThemingParticipant): IDisposable { + public onThemeChange(participant: IThemingParticipant): IDisposable { this.themingParticipants.push(participant); return { @@ -294,10 +289,6 @@ export class WorkbenchThemeService implements IWorkbenchThemeService { }; } - public getThemingParticipants(): IThemingParticipant[] { - return this.themingParticipants; - } - private backupSettings(): TPromise { let resource = URI.file(this.environmentService.appSettingsPath); let backupFileLocation = URI.file(resource.fsPath + '-' + new Date().getTime() + '.backup'); @@ -345,8 +336,6 @@ export class WorkbenchThemeService implements IWorkbenchThemeService { private initialize(): TPromise { - registerParticipants(this); - let colorThemeSetting = this.configurationService.lookup(COLOR_THEME_SETTING).value; let iconThemeSetting = this.configurationService.lookup(ICON_THEME_SETTING).value || ''; @@ -419,7 +408,17 @@ export class WorkbenchThemeService implements IWorkbenchThemeService { if (themeData) { return themeData.ensureLoaded().then(_ => { let cssRules = []; - this.getThemingParticipants().forEach(p => p(themeData, cssRules)); + let hasRule = {}; + let ruleCollector = { + addRule: (rule: string) => { + if (!hasRule[rule]) { + cssRules.push(rule); + hasRule[rule] = true; + } + } + }; + this.themingParticipants.forEach(p => p(themeData, ruleCollector)); + themingRegistry.getThemingParticipants().forEach(p => p(themeData, ruleCollector)); _applyRules(cssRules.join('\n'), colorThemeRulesClassName); return onApply(themeData); }, error => { -- GitLab