mirror of
https://github.com/Microsoft/vscode
synced 2024-10-04 02:14:06 +00:00
[themes] add type to color theme file
This commit is contained in:
parent
b90893cb31
commit
c3984ce5ef
|
@ -1,5 +1,6 @@
|
|||
{
|
||||
"name": "Abyss",
|
||||
"type": "dark",
|
||||
"tokenColors": [
|
||||
{
|
||||
"settings": {
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
{
|
||||
"$schema": "vscode://schemas/color-theme",
|
||||
"name": "Dark Default Colors",
|
||||
"type": "dark",
|
||||
"colors": {
|
||||
"editorBackground": "#1e1e1e",
|
||||
"editorForeground": "#D4D4D4",
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
{
|
||||
"$schema": "vscode://schemas/color-theme",
|
||||
"name": "Dark+ (default dark)",
|
||||
"type": "dark",
|
||||
"include": "./dark_vs.json",
|
||||
"tokenColors": [
|
||||
{
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
{
|
||||
"$schema": "vscode://schemas/color-theme",
|
||||
"name": "Dark (Visual Studio)",
|
||||
"type": "dark",
|
||||
"include": "./dark_defaults.json",
|
||||
"tokenColors": [
|
||||
{
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
{
|
||||
"$schema": "vscode://schemas/color-theme",
|
||||
"name": "Dark High Contrast",
|
||||
"type": "hc",
|
||||
"include": "./hc_black_defaults.json",
|
||||
"settings": [
|
||||
{
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
{
|
||||
"$schema": "vscode://schemas/color-theme",
|
||||
"name": "High Contrast Default Colors",
|
||||
"type": "hc",
|
||||
"colors": {
|
||||
"editorBackground": "#000000",
|
||||
"editorForeground": "#FFFFFF",
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
{
|
||||
"$schema": "vscode://schemas/color-theme",
|
||||
"name": "Light Default Colors",
|
||||
"type": "light",
|
||||
"colors": {
|
||||
"editorBackground": "#ffffff",
|
||||
"editorForeground": "#000000",
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
{
|
||||
"$schema": "vscode://schemas/color-theme",
|
||||
"name": "Light+ (default light)",
|
||||
"type": "light",
|
||||
"include": "./light_vs.json",
|
||||
"tokenColors": [
|
||||
{
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
{
|
||||
"$schema": "vscode://schemas/color-theme",
|
||||
"name": "Light (Visual Studio)",
|
||||
"type": "light",
|
||||
"include": "./light_defaults.json",
|
||||
"tokenColors": [
|
||||
{
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
{
|
||||
"name": "Quiet Light",
|
||||
"type": "light",
|
||||
"tokenColors": [
|
||||
{
|
||||
"settings": {
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
{
|
||||
"name": "Solarized (dark)",
|
||||
"type": "dark",
|
||||
"tokenColors": [
|
||||
{
|
||||
"settings": {
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
{
|
||||
"name": "Solarized (light)",
|
||||
"type": "light",
|
||||
"tokenColors": [
|
||||
{
|
||||
"settings": {
|
||||
|
|
|
@ -172,9 +172,15 @@ const schemaId = 'vscode://schemas/color-theme';
|
|||
const schema: IJSONSchema = {
|
||||
type: 'object',
|
||||
properties: {
|
||||
type: {
|
||||
description: nls.localize('schema.type', 'The type of the theme, either light, dark or high contrast. Depending on the type, a different set of icons is used.'),
|
||||
enum: ['light', 'dark', 'hc'],
|
||||
enumDescriptions: [nls.localize('schema.light', 'Light theme, using dark icons'), nls.localize('schema.dark', 'Dark theme, using light icons'), nls.localize('schema.hc', 'High contrast theme, using light icons')]
|
||||
},
|
||||
colors: colorsSchema,
|
||||
tokenColors: tokenColorsSchema
|
||||
}
|
||||
},
|
||||
required: ['type']
|
||||
};
|
||||
|
||||
export function register() {
|
||||
|
|
|
@ -9,7 +9,7 @@ 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 { 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';
|
||||
import { getBaseThemeId, getSyntaxThemeId } from 'vs/platform/theme/common/themes';
|
||||
import nls = require('vs/nls');
|
||||
import * as types from 'vs/base/common/types';
|
||||
import * as objects from 'vs/base/common/objects';
|
||||
|
@ -31,6 +31,7 @@ export class ColorThemeData implements IColorTheme {
|
|||
}
|
||||
|
||||
id: string;
|
||||
type: ThemeType;
|
||||
label: string;
|
||||
settingsId: string;
|
||||
description?: string;
|
||||
|
@ -79,7 +80,8 @@ export class ColorThemeData implements IColorTheme {
|
|||
this.colorMap = {};
|
||||
this.defaultColorMap = {};
|
||||
if (this.path) {
|
||||
return _loadColorThemeFromFile(this.path, this.tokenColors, this.colorMap).then(_ => {
|
||||
return _loadColorThemeFromFile(this.path, this.tokenColors, this.colorMap, this.type).then(type => {
|
||||
this.type = type;
|
||||
this.isLoaded = true;
|
||||
_completeTokenColors(this);
|
||||
});
|
||||
|
@ -106,6 +108,7 @@ export class ColorThemeData implements IColorTheme {
|
|||
}
|
||||
return JSON.stringify({
|
||||
id: this.id,
|
||||
type: this.type,
|
||||
label: this.label,
|
||||
settingsId: this.settingsId,
|
||||
selector: this.selector,
|
||||
|
@ -119,20 +122,12 @@ export class ColorThemeData implements IColorTheme {
|
|||
return objects.equals(this.colorMap, other.colorMap) && objects.equals(this.tokenColors, other.tokenColors);
|
||||
}
|
||||
|
||||
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);
|
||||
return this.type === 'light';
|
||||
}
|
||||
|
||||
isDarkTheme() {
|
||||
return isDarkTheme(this.id);
|
||||
return this.type === 'dark';
|
||||
}
|
||||
|
||||
getSyntaxThemeId() {
|
||||
|
@ -157,6 +152,9 @@ export function fromStorageData(themeService: WorkbenchThemeService, input: stri
|
|||
}
|
||||
}
|
||||
}
|
||||
if (!theme.type) {
|
||||
theme.type = baseThemeToType(theme.id);
|
||||
}
|
||||
return theme;
|
||||
}
|
||||
|
||||
|
@ -166,6 +164,7 @@ export function fromExtensionTheme(themeService: WorkbenchThemeService, theme: I
|
|||
let themeSelector = toCSSSelector(extensionData.extensionId + '-' + Paths.normalize(theme.path));
|
||||
let themeData = new ColorThemeData(themeService);
|
||||
themeData.id = `${baseTheme} ${themeSelector}`;
|
||||
themeData.type = baseThemeToType(baseTheme);
|
||||
themeData.label = theme.label || Paths.basename(theme.path);
|
||||
themeData.settingsId = theme.id || themeData.label;
|
||||
themeData.selector = `${baseTheme}.${themeSelector}`;
|
||||
|
@ -176,6 +175,14 @@ export function fromExtensionTheme(themeService: WorkbenchThemeService, theme: I
|
|||
return themeData;
|
||||
}
|
||||
|
||||
function baseThemeToType(baseTheme: string): ThemeType {
|
||||
switch (getBaseThemeId(baseTheme)) {
|
||||
case VS_LIGHT_THEME: return 'light';
|
||||
case VS_HC_THEME: return 'hc';
|
||||
default: return 'dark';
|
||||
}
|
||||
}
|
||||
|
||||
function toCSSSelector(str: string) {
|
||||
str = str.replace(/[^_\-a-zA-Z0-9]/g, '-');
|
||||
if (str.charAt(0).match(/[0-9\-]/)) {
|
||||
|
@ -184,27 +191,33 @@ function toCSSSelector(str: string) {
|
|||
return str;
|
||||
}
|
||||
|
||||
function _loadColorThemeFromFile(themePath: string, resultRules: ITokenColorizationRule[], resultColors: IColorMap): TPromise<any> {
|
||||
function _loadColorThemeFromFile(themePath: string, resultRules: ITokenColorizationRule[], resultColors: IColorMap, defaultType: ThemeType): TPromise<ThemeType> {
|
||||
if (Paths.extname(themePath) === '.json') {
|
||||
return pfs.readFile(themePath).then(content => {
|
||||
let errors: Json.ParseError[] = [];
|
||||
let contentValue = Json.parse(content.toString(), errors);
|
||||
if (errors.length > 0) {
|
||||
return TPromise.wrapError(new Error(nls.localize('error.cannotparsejson', "Problems parsing JSON theme file: {0}", errors.map(e => Json.getParseErrorMessage(e.error)).join(', '))));
|
||||
return TPromise.wrapError<ThemeType>(new Error(nls.localize('error.cannotparsejson', "Problems parsing JSON theme file: {0}", errors.map(e => Json.getParseErrorMessage(e.error)).join(', '))));
|
||||
}
|
||||
let includeCompletes = TPromise.as(null);
|
||||
let includeCompletes = TPromise.as(defaultType);
|
||||
if (contentValue.include) {
|
||||
includeCompletes = _loadColorThemeFromFile(Paths.join(Paths.dirname(themePath), contentValue.include), resultRules, resultColors);
|
||||
includeCompletes = _loadColorThemeFromFile(Paths.join(Paths.dirname(themePath), contentValue.include), resultRules, resultColors, defaultType);
|
||||
}
|
||||
return includeCompletes.then(_ => {
|
||||
return includeCompletes.then(type => {
|
||||
if (Array.isArray(contentValue.settings)) {
|
||||
convertSettings(contentValue.settings, resultRules, resultColors);
|
||||
return null;
|
||||
return type;
|
||||
}
|
||||
let themeType = contentValue.type;
|
||||
if (themeType !== 'light' && themeType !== 'dark' && themeType !== 'hc') {
|
||||
return TPromise.wrapError<ThemeType>(new Error(nls.localize({ key: 'error.invalidformat.type', comment: ['{0} will be replaced by a path. Values in quotes should not be translated.'] }, "Problem parsing color theme file: {0}. Property 'type' must be 'light', 'dark' or 'hc'", themePath)));
|
||||
}
|
||||
type = themeType;
|
||||
|
||||
let colors = contentValue.colors;
|
||||
if (colors) {
|
||||
if (typeof colors !== 'object') {
|
||||
return TPromise.wrapError(new Error(nls.localize({ key: 'error.invalidformat.colors', comment: ['{0} will be replaced by a path. Values in quotes should not be translated.'] }, "Problem parsing color theme file: {0}. Property 'colors' is not of type 'object'.", themePath)));
|
||||
return TPromise.wrapError<ThemeType>(new Error(nls.localize({ key: 'error.invalidformat.colors', comment: ['{0} will be replaced by a path. Values in quotes should not be translated.'] }, "Problem parsing color theme file: {0}. Property 'colors' is not of type 'object'.", themePath)));
|
||||
}
|
||||
// new JSON color themes format
|
||||
for (let colorId in colors) {
|
||||
|
@ -218,36 +231,35 @@ function _loadColorThemeFromFile(themePath: string, resultRules: ITokenColorizat
|
|||
if (tokenColors) {
|
||||
if (Array.isArray(tokenColors)) {
|
||||
resultRules.push(...tokenColors);
|
||||
return null;
|
||||
} else if (typeof tokenColors === 'string') {
|
||||
return _loadSyntaxTokensFromFile(Paths.join(Paths.dirname(themePath), tokenColors), resultRules, {});
|
||||
return _loadSyntaxTokensFromFile(Paths.join(Paths.dirname(themePath), tokenColors), resultRules, {}, type);
|
||||
} else {
|
||||
return TPromise.wrapError(new Error(nls.localize({ key: 'error.invalidformat.tokenColors', comment: ['{0} will be replaced by a path. Values in quotes should not be translated.'] }, "Problem parsing color theme file: {0}. Property 'tokenColors' should be either an array specifying colors or a path to a text mate theme file", themePath)));
|
||||
return TPromise.wrapError<ThemeType>(new Error(nls.localize({ key: 'error.invalidformat.tokenColors', comment: ['{0} will be replaced by a path. Values in quotes should not be translated.'] }, "Problem parsing color theme file: {0}. Property 'tokenColors' should be either an array specifying colors or a path to a text mate theme file", themePath)));
|
||||
}
|
||||
}
|
||||
return null;
|
||||
return type;
|
||||
});
|
||||
});
|
||||
} else {
|
||||
return _loadSyntaxTokensFromFile(themePath, resultRules, resultColors);
|
||||
return _loadSyntaxTokensFromFile(themePath, resultRules, resultColors, defaultType);
|
||||
}
|
||||
}
|
||||
|
||||
function _loadSyntaxTokensFromFile(themePath: string, resultRules: ITokenColorizationRule[], resultColors: IColorMap): TPromise<any> {
|
||||
function _loadSyntaxTokensFromFile(themePath: string, resultRules: ITokenColorizationRule[], resultColors: IColorMap, type: ThemeType): TPromise<ThemeType> {
|
||||
return pfs.readFile(themePath).then(content => {
|
||||
try {
|
||||
let contentValue = plist.parse(content.toString());
|
||||
let settings: ITokenColorizationRule[] = contentValue.settings;
|
||||
if (!Array.isArray(settings)) {
|
||||
return TPromise.wrapError(new Error(nls.localize('error.plist.invalidformat', "Problem parsing tmTheme file: {0}. 'settings' is not array.")));
|
||||
return TPromise.wrapError<ThemeType>(new Error(nls.localize('error.plist.invalidformat', "Problem parsing tmTheme file: {0}. 'settings' is not array.")));
|
||||
}
|
||||
convertSettings(settings, resultRules, resultColors);
|
||||
return TPromise.as(null);
|
||||
return TPromise.as(type);
|
||||
} catch (e) {
|
||||
return TPromise.wrapError(new Error(nls.localize('error.cannotparse', "Problems parsing tmTheme file: {0}", e.message)));
|
||||
return TPromise.wrapError<ThemeType>(new Error(nls.localize('error.cannotparse', "Problems parsing tmTheme file: {0}", e.message)));
|
||||
}
|
||||
}, error => {
|
||||
return TPromise.wrapError(new Error(nls.localize('error.cannotload', "Problems loading tmTheme file {0}: {1}", themePath, error.message)));
|
||||
return TPromise.wrapError<ThemeType>(new Error(nls.localize('error.cannotload', "Problems loading tmTheme file {0}: {1}", themePath, error.message)));
|
||||
});
|
||||
}
|
||||
/**
|
||||
|
|
|
@ -84,12 +84,8 @@ let themesExtPoint = ExtensionsRegistry.registerExtensionPoint<IThemeExtensionPo
|
|||
description: nls.localize('vscode.extension.contributes.themes.label', 'Label of the color theme as shown in the UI.'),
|
||||
type: 'string'
|
||||
},
|
||||
uiTheme: {
|
||||
description: nls.localize('vscode.extension.contributes.themes.uiTheme', 'Base theme defining the colors around the editor: \'vs\' is the light color theme, \'vs-dark\' is the dark color theme. \'hc-black\' is the dark high contrast theme.'),
|
||||
enum: [VS_LIGHT_THEME, VS_DARK_THEME, VS_HC_THEME]
|
||||
},
|
||||
path: {
|
||||
description: nls.localize('vscode.extension.contributes.themes.path', 'Path of the tmTheme file. The path is relative to the extension folder and is typically \'./themes/themeFile.tmTheme\'.'),
|
||||
description: nls.localize('vscode.extension.contributes.themes.path', 'Path of the color theme file. The path is relative to the extension folder and is typically \'./themes/my-color-theme.json\'.'),
|
||||
type: 'string'
|
||||
}
|
||||
},
|
||||
|
@ -240,6 +236,7 @@ export class WorkbenchThemeService implements IWorkbenchThemeService {
|
|||
|
||||
let initialTheme = new ColorThemeData(this);
|
||||
initialTheme.id = isLightTheme ? VS_LIGHT_THEME : VS_DARK_THEME;
|
||||
initialTheme.type = isLightTheme ? 'light' : 'dark';
|
||||
initialTheme.label = '';
|
||||
initialTheme.selector = isLightTheme ? VS_LIGHT_THEME : VS_DARK_THEME;
|
||||
initialTheme.settingsId = null;
|
||||
|
@ -303,9 +300,9 @@ export class WorkbenchThemeService implements IWorkbenchThemeService {
|
|||
return pfs.writeFile(backupFileLocation, content).then(_ => backupFileLocation);
|
||||
}, err => {
|
||||
if (err && err.code === 'ENOENT') {
|
||||
return TPromise.as(null); // ignore, user config file doesn't exist yet
|
||||
return TPromise.as<string>(null); // ignore, user config file doesn't exist yet
|
||||
};
|
||||
return TPromise.wrapError(err);
|
||||
return TPromise.wrapError<string>(err);
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -406,14 +403,14 @@ export class WorkbenchThemeService implements IWorkbenchThemeService {
|
|||
if (themeData) {
|
||||
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.
|
||||
// the loaded theme is identical to the persisted theme. Don't need to send an event.
|
||||
this.currentColorTheme = themeData;
|
||||
return TPromise.as(themeData);
|
||||
}
|
||||
this.updateDynamicCSSRules(themeData);
|
||||
return this.applyTheme(themeData, settingsTarget);
|
||||
}, error => {
|
||||
return TPromise.wrapError(nls.localize('error.cannotloadtheme', "Unable to load {0}: {1}", themeData.path, error.message));
|
||||
return TPromise.wrapError<IColorTheme>(nls.localize('error.cannotloadtheme', "Unable to load {0}: {1}", themeData.path, error.message));
|
||||
});
|
||||
}
|
||||
return null;
|
||||
|
@ -435,7 +432,7 @@ export class WorkbenchThemeService implements IWorkbenchThemeService {
|
|||
_applyRules(cssRules.join('\n'), colorThemeRulesClassName);
|
||||
}
|
||||
|
||||
private applyTheme(newTheme: ColorThemeData, settingsTarget: ConfigurationTarget, silent = false): TPromise<IFileIconTheme> {
|
||||
private applyTheme(newTheme: ColorThemeData, settingsTarget: ConfigurationTarget, silent = false): TPromise<IColorTheme> {
|
||||
if (this.container) {
|
||||
if (this.currentColorTheme) {
|
||||
$(this.container).removeClass(this.currentColorTheme.id);
|
||||
|
@ -466,7 +463,7 @@ export class WorkbenchThemeService implements IWorkbenchThemeService {
|
|||
return this.writeColorThemeConfiguration(settingsTarget);
|
||||
};
|
||||
|
||||
private writeColorThemeConfiguration(settingsTarget: ConfigurationTarget): TPromise<IFileIconTheme> {
|
||||
private writeColorThemeConfiguration(settingsTarget: ConfigurationTarget): TPromise<IColorTheme> {
|
||||
if (!types.isUndefinedOrNull(settingsTarget)) {
|
||||
return this.configurationWriter.writeConfiguration(COLOR_THEME_SETTING, this.currentColorTheme.settingsId, settingsTarget).then(_ => this.currentColorTheme);
|
||||
}
|
||||
|
@ -479,13 +476,13 @@ export class WorkbenchThemeService implements IWorkbenchThemeService {
|
|||
|
||||
private findThemeData(themeId: string, defaultId?: string): TPromise<ColorThemeData> {
|
||||
return this.getColorThemes().then(allThemes => {
|
||||
let defaultTheme: IColorTheme = void 0;
|
||||
let defaultTheme: ColorThemeData = void 0;
|
||||
for (let t of allThemes) {
|
||||
if (t.id === themeId) {
|
||||
return t;
|
||||
return <ColorThemeData>t;
|
||||
}
|
||||
if (t.id === defaultId) {
|
||||
defaultTheme = t;
|
||||
defaultTheme = <ColorThemeData>t;
|
||||
}
|
||||
}
|
||||
return defaultTheme;
|
||||
|
@ -494,13 +491,13 @@ export class WorkbenchThemeService implements IWorkbenchThemeService {
|
|||
|
||||
public findThemeDataBySettingsId(settingsId: string, defaultId: string): TPromise<ColorThemeData> {
|
||||
return this.getColorThemes().then(allThemes => {
|
||||
let defaultTheme: IColorTheme = void 0;
|
||||
let defaultTheme: ColorThemeData = void 0;
|
||||
for (let t of allThemes) {
|
||||
if (t.settingsId === settingsId) {
|
||||
return t;
|
||||
return <ColorThemeData>t;
|
||||
}
|
||||
if (t.id === defaultId) {
|
||||
defaultTheme = t;
|
||||
defaultTheme = <ColorThemeData>t;
|
||||
}
|
||||
}
|
||||
return defaultTheme;
|
||||
|
@ -735,7 +732,7 @@ function _applyIconTheme(data: IInternalIconThemeData, onApply: (theme: IInterna
|
|||
_applyRules(data.styleSheetContent, iconThemeRulesClassName);
|
||||
return onApply(data);
|
||||
}, error => {
|
||||
return TPromise.wrapError(nls.localize('error.cannotloadicontheme', "Unable to load {0}", data.path));
|
||||
return TPromise.wrapError<IFileIconTheme>(nls.localize('error.cannotloadicontheme', "Unable to load {0}", data.path));
|
||||
});
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue