提交 46362674 编写于 作者: M Martin Aeschlimann

[theme] support custom theme

上级 e1122824
......@@ -8,6 +8,7 @@ import { IDisposable } from 'vs/base/common/lifecycle';
import Event, { Emitter } from 'vs/base/common/event';
import { ColorId, ITokenizationRegistry, ITokenizationSupport, ITokenizationSupportChangedEvent } from 'vs/editor/common/modes';
import { Color } from 'vs/base/common/color';
import * as objects from 'vs/base/common/objects';
export class TokenizationRegistryImpl implements ITokenizationRegistry {
......@@ -49,11 +50,13 @@ export class TokenizationRegistryImpl implements ITokenizationRegistry {
}
public setColorMap(colorMap: Color[]): void {
this._colorMap = colorMap;
this._onDidChange.fire({
changedLanguages: Object.keys(this._map),
changedColorMap: true
});
if (!objects.equals(colorMap, this._colorMap)) {
this._colorMap = colorMap;
this._onDidChange.fire({
changedLanguages: Object.keys(this._map),
changedColorMap: true
});
}
}
public getColorMap(): Color[] {
......
......@@ -114,57 +114,51 @@ let textMateScopes = [
'variable.parameter'
];
const schemaId = 'vscode://schemas/color-theme';
const schema: IJSONSchema = {
type: 'object',
properties: {
colors: themingRegistry.getColorSchema(),
tokenColors: {
type: 'array',
description: nls.localize('schema.colors', 'Colors for syntax highlighting'),
items: {
export const colorsSchema = themingRegistry.getColorSchema();
export const tokenColorsSchema = {
type: 'array',
description: nls.localize('schema.colors', 'Colors for syntax highlighting'),
items: {
type: 'object',
properties: {
name: {
type: 'string',
description: nls.localize('schema.properties.name', 'Description of the rule')
},
scope: {
anyOf: [
{
enum: textMateScopes
},
{
type: 'string'
},
{
type: 'array',
items: {
enum: textMateScopes
}
},
{
type: 'array',
items: {
type: 'string'
}
}
]
},
settings: {
type: 'object',
properties: {
name: {
type: 'string',
description: nls.localize('schema.properties.name', 'Description of the rule')
foreground: {
type: 'string'
},
scope: {
anyOf: [
{
enum: textMateScopes
},
{
type: 'string'
},
{
type: 'array',
items: {
enum: textMateScopes
}
},
{
type: 'array',
items: {
type: 'string'
}
}
]
background: {
type: 'string'
},
settings: {
type: 'object',
properties: {
foreground: {
type: 'string'
},
background: {
type: 'string'
},
fontStyle: {
type: 'string',
description: nls.localize('schema.fontStyle', 'Font style of the rule: One or a combination of \'italic\', \'bold\' and \'underline\'')
}
}
fontStyle: {
type: 'string',
description: nls.localize('schema.fontStyle', 'Font style of the rule: One or a combination of \'italic\', \'bold\' and \'underline\'')
}
}
}
......@@ -172,6 +166,15 @@ const schema: IJSONSchema = {
}
};
const schemaId = 'vscode://schemas/color-theme';
const schema: IJSONSchema = {
type: 'object',
properties: {
colors: colorsSchema,
tokenColors: tokenColorsSchema
}
};
export function register() {
let schemaRegistry = <IJSONContributionRegistry>Registry.as(JSONExtensions.JSONContribution);
schemaRegistry.registerSchema(schemaId, schema);
......
......@@ -19,6 +19,9 @@ export const VS_HC_THEME = 'hc-black';
export const COLOR_THEME_SETTING = 'workbench.colorTheme';
export const ICON_THEME_SETTING = 'workbench.iconTheme';
export const CUSTOM_COLOR_THEME_SETTING = 'workbench.customColorTheme';
export const CUSTOM_THEME_ID = 'Custom Theme';
export interface IColorTheme extends ITheme {
readonly id: string;
......
......@@ -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, VS_LIGHT_THEME, VS_HC_THEME } from 'vs/workbench/services/themes/common/workbenchThemeService';
import { ExtensionData, ITokenColorizationRule, IColorTheme, IColorMap, VS_LIGHT_THEME, VS_HC_THEME, VS_DARK_THEME, CUSTOM_THEME_ID } 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 { getBaseThemeId, getSyntaxThemeId, isDarkTheme, isLightTheme } from 'vs/platform/theme/common/themes';
......@@ -20,6 +20,8 @@ import pfs = require('vs/base/node/pfs');
import { Extensions, IColorRegistry, ColorIdentifier, editorBackground, editorForeground } from 'vs/platform/theme/common/colorRegistry';
import { ThemeType } from 'vs/platform/theme/common/themeService';
import { Registry } from 'vs/platform/platform';
import { WorkbenchThemeService, IUserTheme } from "vs/workbench/services/themes/electron-browser/workbenchThemeService";
import { IThemeExtensionPoint } from "vs/platform/theme/common/themeExtensionPoint";
let colorRegistry = <IColorRegistry>Registry.as(Extensions.ColorContribution);
......@@ -33,6 +35,7 @@ export class ColorThemeData implements IColorTheme {
tokenColors?: ITokenColorizationRule[];
isLoaded: boolean;
path?: string;
userThemeData: IUserTheme;
extensionData: ExtensionData;
colorMap: IColorMap = {};
defaultColorMap: IColorMap = {};
......@@ -64,17 +67,22 @@ export class ColorThemeData implements IColorTheme {
return color === null ? defaultValue === null : color.equals(defaultValue);
}
public ensureLoaded(): TPromise<void> {
public ensureLoaded(themeService: WorkbenchThemeService): TPromise<void> {
if (!this.isLoaded) {
let tokenColors = [];
let colorMap = {};
return _loadThemeDocument(this.getBaseThemeId(), this.path, tokenColors, colorMap).then(_ => {
this.tokenColors = tokenColors;
this.colorMap = colorMap;
this.defaultColorMap = {};
this.isLoaded = true;
completeTokenColors(this);
});
this.tokenColors = [];
this.colorMap = {};
this.defaultColorMap = {};
if (this.path) {
return _loadThemeDocumentFromFile(this.path, this.tokenColors, this.colorMap).then(_ => {
this.isLoaded = true;
completeTokenColors(this);
});
} else if (this.userThemeData) {
return _loadThemeDocumentFromUserTheme(themeService, this.userThemeData, this.tokenColors, this.colorMap).then(_ => {
this.isLoaded = true;
completeTokenColors(this);
});
}
}
return TPromise.as(null);
}
......@@ -151,33 +159,53 @@ export function fromStorageData(input: string): ColorThemeData {
return theme;
}
let defaultThemeColors: { [baseTheme: string]: ITokenColorizationRule[] } = {
'vs': [
{ scope: 'token.info-token', settings: { foreground: '#316bcd' } },
{ scope: 'token.warn-token', settings: { foreground: '#cd9731' } },
{ scope: 'token.error-token', settings: { foreground: '#cd3131' } },
{ scope: 'token.debug-token', settings: { foreground: 'purple' } }
],
'vs-dark': [
{ scope: 'token.info-token', settings: { foreground: '#6796e6' } },
{ scope: 'token.warn-token', settings: { foreground: '#cd9731' } },
{ scope: 'token.error-token', settings: { foreground: '#f44747' } },
{ scope: 'token.debug-token', settings: { foreground: '#b267e6' } }
],
'hc-black': [
{ scope: 'token.info-token', settings: { foreground: '#6796e6' } },
{ scope: 'token.warn-token', settings: { foreground: '#008000' } },
{ scope: 'token.error-token', settings: { foreground: '#FF0000' } },
{ scope: 'token.debug-token', settings: { foreground: '#b267e6' } }
],
};
let counter = 0;
export function fromUserTheme(userTheme: IUserTheme): ColorThemeData {
let baseTheme = VS_LIGHT_THEME;
if (userTheme.type === 'dark') {
baseTheme = VS_DARK_THEME;
} else if (userTheme.type === 'hc') {
baseTheme = VS_HC_THEME;
}
let themeId = 'customtheme' + counter++;
let theme = new ColorThemeData();
theme.id = baseTheme + ' ' + themeId;
theme.selector = baseTheme + '.' + themeId;
theme.label = CUSTOM_THEME_ID;
theme.settingsId = CUSTOM_THEME_ID;
theme.userThemeData = userTheme;
theme.isLoaded = false;
return theme;
}
function _loadThemeDocument(baseTheme: string, themePath: string, resultRules: ITokenColorizationRule[], resultColors: IColorMap): TPromise<any> {
export function fromExtensionTheme(theme: IThemeExtensionPoint, normalizedAbsolutePath: string, extensionData: ExtensionData): ColorThemeData {
let baseTheme = theme.uiTheme || 'vs-dark';
let themeSelector = toCSSSelector(extensionData.extensionId + '-' + Paths.normalize(theme.path));
let themeData = new ColorThemeData();
themeData.id = `${baseTheme} ${themeSelector}`;
themeData.label = theme.label || Paths.basename(theme.path);
themeData.settingsId = theme.id || themeData.label;
themeData.selector = `${baseTheme}.${themeSelector}`;
themeData.description = theme.description;
themeData.path = normalizedAbsolutePath;
themeData.extensionData = extensionData;
themeData.isLoaded = false;
return themeData;
}
function toCSSSelector(str: string) {
str = str.replace(/[^_\-a-zA-Z0-9]/g, '-');
if (str.charAt(0).match(/[0-9\-]/)) {
str = '_' + str;
}
return str;
}
function _loadThemeDocumentFromFile(themePath: string, resultRules: ITokenColorizationRule[], resultColors: IColorMap): TPromise<any> {
return pfs.readFile(themePath).then(content => {
if (resultRules.length === 0) {
let defaultRules = defaultThemeColors[baseTheme] || [];
resultRules.push(...defaultRules);
}
if (Paths.extname(themePath) === '.json') {
let errors: Json.ParseError[] = [];
let contentValue = Json.parse(content.toString(), errors);
......@@ -186,7 +214,7 @@ function _loadThemeDocument(baseTheme: string, themePath: string, resultRules: I
}
let includeCompletes = TPromise.as(null);
if (contentValue.include) {
includeCompletes = _loadThemeDocument(baseTheme, Paths.join(Paths.dirname(themePath), contentValue.include), resultRules, resultColors);
includeCompletes = _loadThemeDocumentFromFile(Paths.join(Paths.dirname(themePath), contentValue.include), resultRules, resultColors);
}
return includeCompletes.then(_ => {
if (Array.isArray(contentValue.settings)) {
......@@ -225,10 +253,41 @@ function _loadThemeDocument(baseTheme: string, themePath: string, resultRules: I
});
}
function _loadThemeDocumentFromUserTheme(themeService: WorkbenchThemeService, userTheme: IUserTheme, resultRules: ITokenColorizationRule[], resultColors: IColorMap): TPromise<any> {
let extendsCompletes = TPromise.as(null);
if (userTheme.extends) {
extendsCompletes = themeService.findThemeDataBySettingsId(userTheme.extends, null).then(theme => {
if (theme && !theme.userThemeData) {
return theme.ensureLoaded(themeService).then(_ => {
resultRules.push(...theme.tokenColors);
for (let colorId in theme.colorMap) {
resultColors[colorId] = theme.colorMap[colorId];
}
});
}
return null;
});
}
return extendsCompletes.then(_ => {
if (userTheme.tokenColors) {
resultRules.push(...userTheme.tokenColors);
}
if (userTheme.colors) {
let colors = userTheme.colors;
for (let colorId in colors) {
let colorHex = colors[colorId];
resultColors[colorId] = Color.fromHex(colorHex);
}
}
return null;
});
}
/**
* Make sure that the token colors contain the default fore and background
*/
function completeTokenColors(theme: ColorThemeData) {
let hasDefaultTokens = false;
theme.tokenColors.forEach(rule => {
if (!rule.scope) {
if (!rule.settings.background) {
......@@ -237,6 +296,33 @@ function completeTokenColors(theme: ColorThemeData) {
if (!rule.settings.foreground) {
rule.settings.foreground = theme.getColor(editorForeground).toRGBAHex();
}
} else if (rule.scope === 'token.info-token') {
hasDefaultTokens = true;
}
});
}
\ No newline at end of file
if (!hasDefaultTokens) {
theme.tokenColors.push(...defaultThemeColors[theme.type]);
}
}
let defaultThemeColors: { [baseTheme: string]: ITokenColorizationRule[] } = {
'light': [
{ scope: 'token.info-token', settings: { foreground: '#316bcd' } },
{ scope: 'token.warn-token', settings: { foreground: '#cd9731' } },
{ scope: 'token.error-token', settings: { foreground: '#cd3131' } },
{ scope: 'token.debug-token', settings: { foreground: '#800080' } }
],
'dark': [
{ scope: 'token.info-token', settings: { foreground: '#6796e6' } },
{ scope: 'token.warn-token', settings: { foreground: '#cd9731' } },
{ scope: 'token.error-token', settings: { foreground: '#f44747' } },
{ scope: 'token.debug-token', settings: { foreground: '#b267e6' } }
],
'hc': [
{ scope: 'token.info-token', settings: { foreground: '#6796e6' } },
{ scope: 'token.warn-token', settings: { foreground: '#008000' } },
{ scope: 'token.error-token', settings: { foreground: '#FF0000' } },
{ scope: 'token.debug-token', settings: { foreground: '#b267e6' } }
],
};
\ No newline at end of file
......@@ -9,10 +9,11 @@ import nls = require('vs/nls');
import Paths = require('vs/base/common/paths');
import Json = require('vs/base/common/json');
import * as types from 'vs/base/common/types';
import * as objects from 'vs/base/common/objects';
import { IThemeExtensionPoint } from 'vs/platform/theme/common/themeExtensionPoint';
import { IExtensionService } from 'vs/platform/extensions/common/extensions';
import { ExtensionsRegistry, ExtensionMessageCollector } from 'vs/platform/extensions/common/extensionsRegistry';
import { IWorkbenchThemeService, IColorTheme, IFileIconTheme, ExtensionData, VS_LIGHT_THEME, VS_DARK_THEME, VS_HC_THEME, COLOR_THEME_SETTING, ICON_THEME_SETTING } from 'vs/workbench/services/themes/common/workbenchThemeService';
import { IWorkbenchThemeService, IColorTheme, IFileIconTheme, ExtensionData, VS_LIGHT_THEME, VS_DARK_THEME, VS_HC_THEME, COLOR_THEME_SETTING, ICON_THEME_SETTING, CUSTOM_COLOR_THEME_SETTING, ITokenColorizationRule, CUSTOM_THEME_ID } from 'vs/workbench/services/themes/common/workbenchThemeService';
import { IWindowIPCService } from 'vs/workbench/services/window/electron-browser/windowService';
import { IStorageService, StorageScope } from 'vs/platform/storage/common/storage';
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
......@@ -26,7 +27,7 @@ import { IEnvironmentService } from 'vs/platform/environment/common/environment'
import { IMessageService } from 'vs/platform/message/common/message';
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
import Severity from 'vs/base/common/severity';
import { ColorThemeData, fromStorageData } from './colorThemeData';
import { ColorThemeData, fromStorageData, fromUserTheme, fromExtensionTheme } from './colorThemeData';
import { ITheme, Extensions as ThemingExtensions, IThemingRegistry } from 'vs/platform/theme/common/themeService';
import { editorBackground, editorForeground } from 'vs/platform/theme/common/colorRegistry';
......@@ -47,8 +48,6 @@ const DEFAULT_THEME_SETTING_VALUE = 'Default Dark+';
const PERSISTED_THEME_STORAGE_KEY = 'colorThemeData';
const defaultBaseTheme = 'vs-dark';
const defaultThemeExtensionId = 'vscode-theme-defaults';
const oldDefaultThemeExtensionId = 'vscode-theme-colorful-defaults';
......@@ -167,6 +166,13 @@ interface IconThemeDocument extends IconsAssociation {
highContrast?: IconsAssociation;
}
export interface IUserTheme {
type: string;
extends?: string;
colors?: { [colorId: string]: string; };
tokenColors?: ITokenColorizationRule[];
}
const noFileIconTheme: IFileIconTheme = {
id: '',
label: '',
......@@ -177,10 +183,15 @@ const noFileIconTheme: IFileIconTheme = {
extensionData: null
};
const defaultUserTheme: IUserTheme = {
type: 'dark'
};
export class WorkbenchThemeService implements IWorkbenchThemeService {
_serviceBrand: any;
private knownColorThemes: ColorThemeData[];
private extensionsColorThemes: ColorThemeData[];
private userColorTheme: ColorThemeData;
private currentColorTheme: ColorThemeData;
private container: HTMLElement;
private onColorThemeChange: Emitter<IColorTheme>;
......@@ -204,7 +215,8 @@ export class WorkbenchThemeService implements IWorkbenchThemeService {
@IInstantiationService private instantiationService: IInstantiationService) {
this.container = container;
this.knownColorThemes = [];
this.extensionsColorThemes = [];
this.userColorTheme = fromUserTheme(defaultUserTheme);
this.onFileIconThemeChange = new Emitter<IFileIconTheme>();
this.knownIconThemes = [];
this.onColorThemeChange = new Emitter<IColorTheme>();
......@@ -337,6 +349,11 @@ export class WorkbenchThemeService implements IWorkbenchThemeService {
private initialize(): TPromise<any> {
let userTheme = this.configurationService.lookup<IUserTheme>(CUSTOM_COLOR_THEME_SETTING).value;
if (userTheme) {
this.updateUserTheme(userTheme);
}
let colorThemeSetting = this.configurationService.lookup<string>(COLOR_THEME_SETTING).value;
let iconThemeSetting = this.configurationService.lookup<string>(ICON_THEME_SETTING).value || '';
......@@ -367,6 +384,9 @@ export class WorkbenchThemeService implements IWorkbenchThemeService {
this.setFileIconTheme(theme && theme.id, null);
});
}
let userTheme = this.configurationService.lookup<IUserTheme>(CUSTOM_COLOR_THEME_SETTING).value || defaultUserTheme;
this.updateUserTheme(userTheme);
});
}
......@@ -391,7 +411,7 @@ export class WorkbenchThemeService implements IWorkbenchThemeService {
return this.findThemeData(themeId, DEFAULT_THEME_ID).then(themeData => {
if (themeData) {
return themeData.ensureLoaded().then(_ => {
return themeData.ensureLoaded(this).then(_ => {
if (themeId === this.currentColorTheme.id && !this.currentColorTheme.isLoaded && this.currentColorTheme.hasEqualData(themeData)) {
// the loaded theme is identical to the perisisted theme. Don't need to send an event.
this.currentColorTheme = themeData;
......@@ -475,7 +495,7 @@ export class WorkbenchThemeService implements IWorkbenchThemeService {
});
}
private findThemeDataBySettingsId(settingsId: string, defaultId: string): TPromise<ColorThemeData> {
public findThemeDataBySettingsId(settingsId: string, defaultId: string): TPromise<ColorThemeData> {
return this.getColorThemes().then(allThemes => {
let defaultTheme: IColorTheme = void 0;
for (let t of allThemes) {
......@@ -492,10 +512,19 @@ export class WorkbenchThemeService implements IWorkbenchThemeService {
public getColorThemes(): TPromise<IColorTheme[]> {
return this.extensionService.onReady().then(isReady => {
return this.knownColorThemes;
return this.extensionsColorThemes.concat([this.userColorTheme]);
});
}
private updateUserTheme(userTheme: IUserTheme): void {
if (!objects.equals(this.userColorTheme.userThemeData, userTheme)) {
this.userColorTheme = fromUserTheme(userTheme);
if (!!this.currentColorTheme.userThemeData) {
this.setColorTheme(this.userColorTheme.id, null);
}
}
}
private onThemes(extensionFolderPath: string, extensionData: ExtensionData, themes: IThemeExtensionPoint[], collector: ExtensionMessageCollector): void {
if (!Array.isArray(themes)) {
collector.error(nls.localize(
......@@ -520,24 +549,13 @@ export class WorkbenchThemeService implements IWorkbenchThemeService {
if (normalizedAbsolutePath.indexOf(extensionFolderPath) !== 0) {
collector.warn(nls.localize('invalid.path.1', "Expected `contributes.{0}.path` ({1}) to be included inside extension's folder ({2}). This might make the extension non-portable.", themesExtPoint.name, normalizedAbsolutePath, extensionFolderPath));
}
let themeData = fromExtensionTheme(theme, normalizedAbsolutePath, extensionData);
this.extensionsColorThemes.push(themeData);
let baseTheme = theme.uiTheme || defaultBaseTheme;
let themeSelector = toCSSSelector(extensionData.extensionId + '-' + Paths.normalize(theme.path));
let themeData = new ColorThemeData();
themeData.id = `${baseTheme} ${themeSelector}`;
themeData.label = theme.label || Paths.basename(theme.path);
themeData.settingsId = theme.id || themeData.label;
themeData.selector = `${baseTheme}.${themeSelector}`;
themeData.description = theme.description;
themeData.path = normalizedAbsolutePath;
themeData.extensionData = extensionData;
themeData.isLoaded = false;
this.knownColorThemes.push(themeData);
colorThemeSetting.enum.push(themeData.settingsId);
colorThemeSetting.enumDescriptions.push(themeData.description || '');
colorThemeSettingSchema.enum.push(themeData.settingsId);
colorThemeSettingSchema.enumDescriptions.push(themeData.description || '');
extendsSchema.enum.push(themeData.settingsId);
extendsSchema.enumDescriptions.push(themeData.description || '');
});
}
......@@ -586,23 +604,25 @@ export class WorkbenchThemeService implements IWorkbenchThemeService {
};
this.knownIconThemes.push(themeData);
iconThemeSetting.enum.push(themeData.settingsId);
iconThemeSetting.enumDescriptions.push(themeData.description || '');
iconThemeSettingSchema.enum.push(themeData.settingsId);
iconThemeSettingSchema.enumDescriptions.push(themeData.description || '');
});
}
private themeExtensionsActivated = new Map<string, boolean>();
private sendTelemetry(themeId: string, themeData: ExtensionData, themeType: string) {
let key = themeType + themeData.extensionId;
if (!this.themeExtensionsActivated.get(key)) {
this.telemetryService.publicLog('activatePlugin', {
id: themeData.extensionId,
name: themeData.extensionName,
isBuiltin: themeData.extensionIsBuiltin,
publisherDisplayName: themeData.extensionPublisher,
themeId: themeId
});
this.themeExtensionsActivated.set(key, true);
if (themeData) {
let key = themeType + themeData.extensionId;
if (!this.themeExtensionsActivated.get(key)) {
this.telemetryService.publicLog('activatePlugin', {
id: themeData.extensionId,
name: themeData.extensionName,
isBuiltin: themeData.extensionIsBuiltin,
publisherDisplayName: themeData.extensionPublisher,
themeId: themeId
});
this.themeExtensionsActivated.set(key, true);
}
}
}
......@@ -867,16 +887,6 @@ function escapeCSS(str: string) {
return window['CSS'].escape(str);
}
function toCSSSelector(str: string) {
str = str.replace(/[^_\-a-zA-Z0-9]/g, '-');
if (str.charAt(0).match(/[0-9\-]/)) {
str = '_' + str;
}
return str;
}
let colorThemeRulesClassName = 'contributedColorTheme';
let iconThemeRulesClassName = 'contributedIconTheme';
......@@ -923,15 +933,15 @@ class ConfigurationWriter {
// Configuration: Themes
const configurationRegistry = Registry.as<IConfigurationRegistry>(ConfigurationExtensions.Configuration);
const colorThemeSetting: IJSONSchema = {
const colorThemeSettingSchema: IJSONSchema = {
type: 'string',
description: nls.localize('colorTheme', "Specifies the color theme used in the workbench."),
default: DEFAULT_THEME_SETTING_VALUE,
enum: [],
enumDescriptions: [],
enum: [CUSTOM_THEME_ID],
enumDescriptions: [nls.localize('customThemeDescription', "Custom theme as defined in '{0}'", CUSTOM_COLOR_THEME_SETTING)],
errorMessage: nls.localize('colorThemeError', "Theme is unknown or not installed."),
};
const iconThemeSetting: IJSONSchema = {
const iconThemeSettingSchema: IJSONSchema = {
type: ['string', 'null'],
default: null,
description: nls.localize('iconTheme', "Specifies the icon theme used in the workbench."),
......@@ -939,12 +949,37 @@ const iconThemeSetting: IJSONSchema = {
enumDescriptions: [nls.localize('noIconThemeDesc', 'No file icons')],
errorMessage: nls.localize('iconThemeError', "File icon theme is unknown or not installed.")
};
const extendsSchema: IJSONSchema = {
description: nls.localize('customTheme.extends', "theme to extend. This will inherit color and token colors from the selected theme."),
type: 'string',
enum: [],
enumDescriptions: []
};
const userThemeSettingSchema: IJSONSchema = {
type: 'object',
description: nls.localize('customTheme', "Custom theme."),
properties: {
id: {
type: 'string'
},
type: {
enum: ['light', 'dark', 'hc']
},
extends: extendsSchema,
colors: colorThemeSchema.colorsSchema,
tokenColors: colorThemeSchema.tokenColorsSchema
},
required: ['type']
};
configurationRegistry.registerConfiguration({
id: 'workbench',
order: 7.1,
type: 'object',
properties: {
[COLOR_THEME_SETTING]: colorThemeSetting,
[ICON_THEME_SETTING]: iconThemeSetting
[COLOR_THEME_SETTING]: colorThemeSettingSchema,
[ICON_THEME_SETTING]: iconThemeSettingSchema,
[CUSTOM_COLOR_THEME_SETTING]: userThemeSettingSchema
}
});
\ No newline at end of file
});
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册