Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Editor.TokenColorCustomizations #29393

Merged
merged 4 commits into from
Jul 7, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
36 changes: 19 additions & 17 deletions src/vs/workbench/services/themes/common/colorThemeSchema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,24 @@ let textMateScopes = [
'variable.parameter'
];

export const tokenColorizationSettingSchema = {
type: 'object',
properties: {
foreground: {
type: 'string',
format: 'color'
},
background: {
type: 'string',
format: 'color'
},
fontStyle: {
type: 'string',
description: nls.localize('schema.fontStyle', 'Font style of the rule: One or a combination of \'italic\', \'bold\' and \'underline\'')
}
}
};

export const colorsSchema = themingRegistry.getColorSchema();
export const tokenColorsSchema = {
type: 'array',
Expand Down Expand Up @@ -147,23 +165,7 @@ export const tokenColorsSchema = {
}
]
},
settings: {
type: 'object',
properties: {
foreground: {
type: 'string',
format: 'color'
},
background: {
type: 'string',
format: 'color'
},
fontStyle: {
type: 'string',
description: nls.localize('schema.fontStyle', 'Font style of the rule: One or a combination of \'italic\', \'bold\' and \'underline\'')
}
}
}
settings: tokenColorizationSettingSchema
}
}
};
Expand Down
15 changes: 14 additions & 1 deletion src/vs/workbench/services/themes/common/workbenchThemeService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,10 @@ export const VS_HC_THEME = 'hc-black';

export const COLOR_THEME_SETTING = 'workbench.colorTheme';
export const ICON_THEME_SETTING = 'workbench.iconTheme';
export const CUSTOM_COLORS_SETTING = 'workbench.colorCustomizations';
export const CUSTOM_WORKBENCH_COLORS_SETTING = 'workbench.colorCustomizations';
export const DEPRECATED_CUSTOM_COLORS_SETTING = 'workbench.experimental.colorCustomizations';
export const CUSTOM_EDITOR_COLORS_SETTING = 'editor.tokenColorCustomizations';
export const CUSTOM_EDITOR_SCOPE_COLORS_SETTING = 'textMateRules';

export interface IColorTheme extends ITheme {
readonly id: string;
Expand Down Expand Up @@ -61,6 +63,17 @@ export interface IWorkbenchThemeService extends IThemeService {
onDidFileIconThemeChange: Event<IFileIconTheme>;
}

export interface ITokenColorCustomizations {
comments?: string | ITokenColorizationSetting;
strings?: string | ITokenColorizationSetting;
numbers?: string | ITokenColorizationSetting;
keywords?: string | ITokenColorizationSetting;
types?: string | ITokenColorizationSetting;
functions?: string | ITokenColorizationSetting;
variables?: string | ITokenColorizationSetting;
textMateRules?: ITokenColorizationRule[];
}

export interface ITokenColorizationRule {
name?: string;
scope?: string | string[];
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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, IThemeExtensionPoint, VS_LIGHT_THEME, VS_HC_THEME } from 'vs/workbench/services/themes/common/workbenchThemeService';
import { ExtensionData, ITokenColorCustomizations, ITokenColorizationRule, IColorTheme, IColorMap, IThemeExtensionPoint, VS_LIGHT_THEME, VS_HC_THEME } from 'vs/workbench/services/themes/common/workbenchThemeService';
import { convertSettings } from 'vs/workbench/services/themes/electron-browser/themeCompatibility';
import { TPromise } from 'vs/base/common/winjs.base';
import nls = require('vs/nls');
Expand All @@ -24,6 +24,16 @@ import { getParseErrorMessage } from 'vs/base/common/jsonErrorMessages';

let colorRegistry = <IColorRegistry>Registry.as(Extensions.ColorContribution);

const tokenGroupToScopesMap = {
comments: 'comment',
strings: 'string',
keywords: 'keyword',
numbers: 'constant.numeric',
types: 'entity.name.type',
functions: 'entity.name.function',
variables: 'variable'
};

export class ColorThemeData implements IColorTheme {

constructor() {
Expand All @@ -33,7 +43,13 @@ export class ColorThemeData implements IColorTheme {
label: string;
settingsId: string;
description?: string;
tokenColors?: ITokenColorizationRule[];
get tokenColors(): ITokenColorizationRule[] {
// Add the custom colors after the theme colors
// so that they will override them
return this.themeTokenColors.concat(this.customTokenColors || []);
}
themeTokenColors?: ITokenColorizationRule[];
customTokenColors?: ITokenColorizationRule[];
isLoaded: boolean;
path?: string;
extensionData: ExtensionData;
Expand Down Expand Up @@ -76,12 +92,40 @@ export class ColorThemeData implements IColorTheme {
}
}

public setCustomTokenColors(customTokenColors: ITokenColorCustomizations) {
let generalRules: ITokenColorizationRule[] = [];

let value, settings, scope;
Object.keys(tokenGroupToScopesMap).forEach(key => {
value = customTokenColors[key];
settings = typeof value === 'string'
? { foreground: value }
: value;
scope = tokenGroupToScopesMap[key];

if (!settings) {
return;
}

generalRules.push({
scope,
settings
});
});

const textMateRules: ITokenColorizationRule[] = customTokenColors.textMateRules || [];

// Put the general customizations such as comments, strings, etc. first so that
// they can be overriden by specific customizations like "string.interpolated"
this.customTokenColors = generalRules.concat(textMateRules);
}

public ensureLoaded(themeService: WorkbenchThemeService): TPromise<void> {
if (!this.isLoaded) {
this.tokenColors = [];
this.themeTokenColors = [];
this.colorMap = {};
if (this.path) {
return _loadColorThemeFromFile(this.path, this.tokenColors, this.colorMap).then(_ => {
return _loadColorThemeFromFile(this.path, this.themeTokenColors, this.colorMap).then(_ => {
this.isLoaded = true;
_sanitizeTokenColors(this);
});
Expand Down Expand Up @@ -137,7 +181,7 @@ export function createUnloadedTheme(id: string): ColorThemeData {
themeData.label = '';
themeData.settingsId = null;
themeData.isLoaded = false;
themeData.tokenColors = [{ settings: {} }];
themeData.themeTokenColors = [{ settings: {} }];
return themeData;
}

Expand Down Expand Up @@ -267,7 +311,7 @@ function _sanitizeTokenColors(theme: ColorThemeData) {
if (!hasDefaultTokens) {
updatedTokenColors.push(...defaultThemeColors[theme.type]);
}
theme.tokenColors = updatedTokenColors;
theme.themeTokenColors = updatedTokenColors;
}

function updateDefaultRuleSettings(defaultRule: ITokenColorizationRule, theme: ColorThemeData): ITokenColorizationRule {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ export function convertSettings(oldSettings: ITokenColorizationRule[], resultRul
}
}
}
if (key !== 'foreground' && key !== 'background') {
if (key !== 'foreground' && key !== 'background' && key !== 'fontStyle') {
delete settings[key];
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import * as types from 'vs/base/common/types';
import * as objects from 'vs/base/common/objects';
import { IExtensionService } from 'vs/platform/extensions/common/extensions';
import { ExtensionsRegistry, ExtensionMessageCollector } from 'vs/platform/extensions/common/extensionsRegistry';
import { IWorkbenchThemeService, IColorTheme, IFileIconTheme, ExtensionData, IThemeExtensionPoint, VS_LIGHT_THEME, VS_DARK_THEME, VS_HC_THEME, COLOR_THEME_SETTING, ICON_THEME_SETTING, CUSTOM_COLORS_SETTING, DEPRECATED_CUSTOM_COLORS_SETTING } from 'vs/workbench/services/themes/common/workbenchThemeService';
import { IWorkbenchThemeService, IColorTheme, ITokenColorCustomizations, IFileIconTheme, ExtensionData, IThemeExtensionPoint, VS_LIGHT_THEME, VS_DARK_THEME, VS_HC_THEME, COLOR_THEME_SETTING, ICON_THEME_SETTING, CUSTOM_WORKBENCH_COLORS_SETTING, DEPRECATED_CUSTOM_COLORS_SETTING, CUSTOM_EDITOR_COLORS_SETTING, CUSTOM_EDITOR_SCOPE_COLORS_SETTING } from 'vs/workbench/services/themes/common/workbenchThemeService';
import { IStorageService, StorageScope } from 'vs/platform/storage/common/storage';
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
import { Registry } from 'vs/platform/registry/common/platform';
Expand Down Expand Up @@ -186,6 +186,7 @@ export class WorkbenchThemeService implements IWorkbenchThemeService {

private extensionsColorThemes: ColorThemeData[];
private colorCustomizations: IColorCustomizations;
private tokenColorCustomizations: ITokenColorCustomizations;
private numberOfColorCustomizations: number;
private currentColorTheme: ColorThemeData;
private container: HTMLElement;
Expand All @@ -212,7 +213,7 @@ export class WorkbenchThemeService implements IWorkbenchThemeService {
this.container = container;
this.extensionsColorThemes = [];
this.colorCustomizations = {};
this.numberOfColorCustomizations = 0;
this.tokenColorCustomizations = {};
this.onFileIconThemeChange = new Emitter<IFileIconTheme>();
this.knownIconThemes = [];
this.onColorThemeChange = new Emitter<IColorTheme>();
Expand Down Expand Up @@ -396,9 +397,11 @@ export class WorkbenchThemeService implements IWorkbenchThemeService {
// the loaded theme is identical to the perisisted theme. Don't need to send an event.
this.currentColorTheme = themeData;
themeData.setCustomColors(this.colorCustomizations);
themeData.setCustomTokenColors(this.tokenColorCustomizations);
return TPromise.as(themeData);
}
themeData.setCustomColors(this.colorCustomizations);
themeData.setCustomTokenColors(this.tokenColorCustomizations);
this.updateDynamicCSSRules(themeData);
return this.applyTheme(themeData, settingsTarget);
}, error => {
Expand Down Expand Up @@ -504,7 +507,7 @@ export class WorkbenchThemeService implements IWorkbenchThemeService {
});
}

private hasCustomizationChanged(newColorCustomizations: IColorCustomizations, newColorIds: string[]): boolean {
private hasCustomizationChanged(newColorCustomizations: IColorCustomizations, newColorIds: string[], newTokenColorCustomizations: ITokenColorCustomizations): boolean {
if (newColorIds.length !== this.numberOfColorCustomizations) {
return true;
}
Expand All @@ -514,21 +517,32 @@ export class WorkbenchThemeService implements IWorkbenchThemeService {
return true;
}
}

if (!objects.equals(newTokenColorCustomizations, this.tokenColorCustomizations)) {
return true;
}

return false;
}

private updateColorCustomizations(notify = true): void {
let newColorCustomizations = this.configurationService.lookup<IColorCustomizations>(CUSTOM_COLORS_SETTING).value || {};
let newColorCustomizations = this.configurationService.lookup<IColorCustomizations>(CUSTOM_WORKBENCH_COLORS_SETTING).value || {};
let newColorIds = Object.keys(newColorCustomizations);
if (newColorIds.length === 0) {
newColorCustomizations = this.configurationService.lookup<IColorCustomizations>(DEPRECATED_CUSTOM_COLORS_SETTING).value || {};
newColorIds = Object.keys(newColorCustomizations);
}
if (this.hasCustomizationChanged(newColorCustomizations, newColorIds)) {

let newTokenColorCustomizations = this.configurationService.lookup<ITokenColorCustomizations>(CUSTOM_EDITOR_COLORS_SETTING).value || {};

if (this.hasCustomizationChanged(newColorCustomizations, newColorIds, newTokenColorCustomizations)) {
this.colorCustomizations = newColorCustomizations;
this.numberOfColorCustomizations = newColorIds.length;
this.tokenColorCustomizations = newTokenColorCustomizations;

if (this.currentColorTheme) {
this.currentColorTheme.setCustomColors(newColorCustomizations);
this.currentColorTheme.setCustomTokenColors(newTokenColorCustomizations);
if (notify) {
this.updateDynamicCSSRules(this.currentColorTheme);
this.onColorThemeChange.fire(this.currentColorTheme);
Expand Down Expand Up @@ -986,8 +1000,39 @@ configurationRegistry.registerConfiguration({
properties: {
[COLOR_THEME_SETTING]: colorThemeSettingSchema,
[ICON_THEME_SETTING]: iconThemeSettingSchema,
[CUSTOM_COLORS_SETTING]: colorCustomizationsSchema,
[CUSTOM_WORKBENCH_COLORS_SETTING]: colorCustomizationsSchema,
[DEPRECATED_CUSTOM_COLORS_SETTING]: deprecatedColorCustomizationsSchema
}
});

const tokenGroupSettings = {
anyOf: [
{
type: 'string',
format: 'color'
},
colorThemeSchema.tokenColorizationSettingSchema
]
};

configurationRegistry.registerConfiguration({
id: 'editor',
order: 7.2,
type: 'object',
properties: {
[CUSTOM_EDITOR_COLORS_SETTING]: {
description: nls.localize('editorColors', "Overrides editor colors and font style from the currently selected color theme."),
properties: {
comments: tokenGroupSettings,
strings: tokenGroupSettings,
keywords: tokenGroupSettings,
numbers: tokenGroupSettings,
types: tokenGroupSettings,
functions: tokenGroupSettings,
variables: tokenGroupSettings,
[CUSTOM_EDITOR_SCOPE_COLORS_SETTING]: colorThemeSchema.tokenColorsSchema
}
}
}
});