提交 86df35e8 编写于 作者: M Martin Aeschlimann

[themes] api polish, split editor colors

上级 305544d9
/*---------------------------------------------------------------------------------------------
* 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 = <colorRegistry.IColorRegistry>Registry.as(colorRegistry.Extensions.ColorContribution);
let themingReg = <IThemingRegistry>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}; }`);
}
}
......@@ -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
......@@ -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<DocumentHighlight[]> {
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
......@@ -11,17 +11,18 @@ import { ITheme } from 'vs/platform/theme/common/themeService';
import nls = require('vs/nls');
export const Extensions = {
ThemingContribution: 'base.contributions.theming'
};
// ------ API types
export interface IColorContribution {
readonly id: string;
export type ColorIdentifier = string;
export interface ColorContribution {
readonly id: ColorIdentifier;
readonly description: string;
readonly defaults: ColorDefaults;
}
export interface DerivedColor {
export interface ColorFunction {
(theme: ITheme): Color;
}
......@@ -31,26 +32,35 @@ export interface ColorDefaults {
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;
/**
* 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 IThemingRegistry {
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, description: string, defaults?: ColorDefaults): IColorContribution;
registerColor(id: string, defaults: ColorDefaults, description: string): ColorIdentifier;
/**
* Get all color contributions
*/
getColors(): IColorContribution[];
getColors(): ColorContribution[];
/**
* Gets the color of the given id
* Gets the default color of the given id
*/
getColor(id: string): IColorContribution;
resolveDefaultColor(id: ColorIdentifier, theme: ITheme): Color;
/**
* JSON schema of all colors
......@@ -59,38 +69,32 @@ export interface IThemingRegistry {
}
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 };
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, description: string, defaults: ColorDefaults): IColorContribution {
let colorContribution: IColorContribution = { id, description, defaults };
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 colorContribution;
return id;
}
public getColors(): IColorContribution[] {
public getColors(): ColorContribution[] {
return Object.keys(this.colorsById).map(id => this.colorsById[id]);
}
public getColor(id: string): IColorContribution {
return 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 {
......@@ -99,16 +103,70 @@ class ThemingRegistry implements IThemingRegistry {
}
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
*/
export function resolveColorValue(colorValue: ColorValue, theme: ITheme): Color {
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);
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);
}
......@@ -116,5 +174,6 @@ export function resolveColorValue(colorValue: ColorValue, theme: ITheme): Color
}
const themingRegistry = new ThemingRegistry();
platform.Registry.add(Extensions.ThemingContribution, themingRegistry);
\ No newline at end of file
......@@ -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<IThemeService>('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 <code>useDefault</code> 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<ITheme>;
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
......@@ -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<string>();
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<void> {
super.create(parent);
......
......@@ -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 = <IThemingRegistry>Registry.as(ThemeingExtensions.ThemingContribution);
let themingRegistry = <IColorRegistry>Registry.as(ThemeingExtensions.ColorContribution);
let textMateScopes = [
'comment',
'comment.block',
......
......@@ -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 = <IThemingRegistry>Registry.as(Extensions.ThemingContribution);
let colorRegistry = <IColorRegistry>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);
}
......
......@@ -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 = <IThemingRegistry>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
......@@ -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<IThemingRegistry>(ThemingExtensions.ThemingContribution);
function validateThemeId(theme: string): string {
// migrations
switch (theme) {
......@@ -117,8 +118,6 @@ let iconThemeExtPoint = ExtensionsRegistry.registerExtensionPoint<IThemeExtensio
}
});
interface IInternalIconThemeData extends IFileIconTheme {
id: string;
label: string;
......@@ -275,15 +274,11 @@ export class WorkbenchThemeService implements IWorkbenchThemeService {
return this.onColorThemeChange.event;
}
public get onDidThemeChange(): Event<ITheme> {
return this.onColorThemeChange.event;
}
public get onDidFileIconThemeChange(): Event<IFileIconTheme> {
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<string> {
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<any> {
registerParticipants(this);
let colorThemeSetting = this.configurationService.lookup<string>(COLOR_THEME_SETTING).value;
let iconThemeSetting = this.configurationService.lookup<string>(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 => {
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册