提交 96168a88 编写于 作者: M Martin Aeschlimann

workbenchThemeService: extract stores

上级 c50042a6
......@@ -29,6 +29,12 @@ export interface IConfigurationRegistry {
*/
registerConfigurations(configurations: IConfigurationNode[], validate?: boolean): void;
/**
* Signal that the schema of a configuration setting has changes. It is currently only supported to change enumeration values.
* Property or default value changes are not allowed.
*/
notifyConfigurationSchemaUpdated(configuration: IConfigurationNode): void;
registerDefaultConfigurations(defaultConfigurations: IDefaultConfigurationExtension[]): void;
/**
......@@ -126,6 +132,10 @@ class ConfigurationRegistry implements IConfigurationRegistry {
this._onDidRegisterConfiguration.fire(this);
}
public notifyConfigurationSchemaUpdated(configuration: IConfigurationNode) {
contributionRegistry.registerSchema(editorConfigurationSchemaId, this.editorConfigurationSchema);
}
public registerOverrideIdentifiers(overrideIdentifiers: string[]): void {
this.overrideIdentifiers.push(...overrideIdentifiers);
this.updateOverridePropertyPatternKey();
......
......@@ -2,6 +2,7 @@
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
'use strict';
import Paths = require('vs/base/common/paths');
import Json = require('vs/base/common/json');
......@@ -36,7 +37,7 @@ const tokenGroupToScopesMap = {
export class ColorThemeData implements IColorTheme {
constructor() {
private constructor() {
}
id: string;
......@@ -171,57 +172,61 @@ export class ColorThemeData implements IColorTheme {
default: return 'dark';
}
}
}
export function createUnloadedTheme(id: string): ColorThemeData {
let themeData = new ColorThemeData();
themeData.id = id;
themeData.label = '';
themeData.settingsId = null;
themeData.isLoaded = false;
themeData.themeTokenColors = [{ settings: {} }];
return themeData;
}
// constructors
export function fromStorageData(input: string): ColorThemeData {
try {
let data = JSON.parse(input);
let theme = new ColorThemeData();
for (let key in data) {
switch (key) {
case 'colorMap':
let colorMapData = data[key];
for (let id in colorMapData) {
theme.colorMap[id] = Color.fromHex(colorMapData[id]);
}
break;
case 'themeTokenColors':
case 'id': case 'label': case 'settingsId': case 'extensionData':
theme[key] = data[key];
break;
static createUnloadedTheme(id: string): ColorThemeData {
let themeData = new ColorThemeData();
themeData.id = id;
themeData.label = '';
themeData.settingsId = null;
themeData.isLoaded = false;
themeData.themeTokenColors = [{ settings: {} }];
return themeData;
}
static fromStorageData(input: string): ColorThemeData {
try {
let data = JSON.parse(input);
let theme = new ColorThemeData();
for (let key in data) {
switch (key) {
case 'colorMap':
let colorMapData = data[key];
for (let id in colorMapData) {
theme.colorMap[id] = Color.fromHex(colorMapData[id]);
}
break;
case 'themeTokenColors':
case 'id': case 'label': case 'settingsId': case 'extensionData':
theme[key] = data[key];
break;
}
}
return theme;
} catch (e) {
return null;
}
return theme;
} catch (e) {
return null;
}
}
export function fromExtensionTheme(theme: IThemeExtensionPoint, normalizedAbsolutePath: string, extensionData: ExtensionData): ColorThemeData {
let baseTheme: string = 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.description = theme.description;
themeData.path = normalizedAbsolutePath;
themeData.extensionData = extensionData;
themeData.isLoaded = false;
return themeData;
static fromExtensionTheme(theme: IThemeExtensionPoint, normalizedAbsolutePath: string, extensionData: ExtensionData): ColorThemeData {
let baseTheme: string = 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.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\-]/)) {
......
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
'use strict';
import nls = require('vs/nls');
import * as types from 'vs/base/common/types';
import * as Paths from 'path';
import { ExtensionsRegistry, ExtensionMessageCollector } from 'vs/platform/extensions/common/extensionsRegistry';
import { IColorTheme, ExtensionData, IThemeExtensionPoint, VS_LIGHT_THEME, VS_DARK_THEME, VS_HC_THEME } from 'vs/workbench/services/themes/common/workbenchThemeService';
import { ColorThemeData } from 'vs/workbench/services/themes/electron-browser/colorThemeData';
import { IExtensionService } from 'vs/platform/extensions/common/extensions';
import { TPromise } from 'vs/base/common/winjs.base';
import Event, { Emitter } from 'vs/base/common/event';
let themesExtPoint = ExtensionsRegistry.registerExtensionPoint<IThemeExtensionPoint[]>('themes', [], {
description: nls.localize('vscode.extension.contributes.themes', 'Contributes textmate color themes.'),
type: 'array',
items: {
type: 'object',
defaultSnippets: [{ body: { label: '${1:label}', id: '${2:id}', uiTheme: VS_DARK_THEME, path: './themes/${3:id}.tmTheme.' } }],
properties: {
id: {
description: nls.localize('vscode.extension.contributes.themes.id', 'Id of the icon theme as used in the user settings.'),
type: 'string'
},
label: {
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\'.'),
type: 'string'
}
},
required: ['path', 'uiTheme']
}
});
export class ColorThemeStore {
private extensionsColorThemes: ColorThemeData[];
private onDidChangeEmitter: Emitter<ColorThemeData[]>;
public get onDidChange(): Event<ColorThemeData[]> { return this.onDidChangeEmitter.event; }
constructor( @IExtensionService private extensionService: IExtensionService) {
this.extensionsColorThemes = [];
this.onDidChangeEmitter = new Emitter<ColorThemeData[]>();
this.initialize();
}
private initialize() {
themesExtPoint.setHandler((extensions) => {
for (let ext of extensions) {
let extensionData = {
extensionId: ext.description.id,
extensionPublisher: ext.description.publisher,
extensionName: ext.description.name,
extensionIsBuiltin: ext.description.isBuiltin
};
this.onThemes(ext.description.extensionFolderPath, extensionData, ext.value, ext.collector);
}
this.onDidChangeEmitter.fire(this.extensionsColorThemes);
});
}
private onThemes(extensionFolderPath: string, extensionData: ExtensionData, themes: IThemeExtensionPoint[], collector: ExtensionMessageCollector): void {
if (!Array.isArray(themes)) {
collector.error(nls.localize(
'reqarray',
"Extension point `{0}` must be an array.",
themesExtPoint.name
));
return;
}
themes.forEach(theme => {
if (!theme.path || !types.isString(theme.path)) {
collector.error(nls.localize(
'reqpath',
"Expected string in `contributes.{0}.path`. Provided value: {1}",
themesExtPoint.name,
String(theme.path)
));
return;
}
let normalizedAbsolutePath = Paths.normalize(Paths.join(extensionFolderPath, theme.path));
if (normalizedAbsolutePath.indexOf(Paths.normalize(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 = ColorThemeData.fromExtensionTheme(theme, normalizedAbsolutePath, extensionData);
this.extensionsColorThemes.push(themeData);
});
}
public findThemeData(themeId: string, defaultId?: string): TPromise<ColorThemeData> {
return this.getColorThemes().then(allThemes => {
let defaultTheme: ColorThemeData = void 0;
for (let t of allThemes) {
if (t.id === themeId) {
return <ColorThemeData>t;
}
if (t.id === defaultId) {
defaultTheme = <ColorThemeData>t;
}
}
return defaultTheme;
});
}
public findThemeDataBySettingsId(settingsId: string, defaultId: string): TPromise<ColorThemeData> {
return this.getColorThemes().then(allThemes => {
let defaultTheme: ColorThemeData = void 0;
for (let t of allThemes) {
if (t.settingsId === settingsId) {
return <ColorThemeData>t;
}
if (t.id === defaultId) {
defaultTheme = <ColorThemeData>t;
}
}
return defaultTheme;
});
}
public getColorThemes(): TPromise<IColorTheme[]> {
return this.extensionService.onReady().then(isReady => {
return this.extensionsColorThemes;
});
}
}
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
'use strict';
import Paths = require('vs/base/common/paths');
import { ExtensionData, IThemeExtensionPoint, IFileIconTheme } from 'vs/workbench/services/themes/common/workbenchThemeService';
export class FileIconThemeData implements IFileIconTheme {
id: string;
label: string;
settingsId: string;
description?: string;
hasFileIcons?: boolean;
hasFolderIcons?: boolean;
isLoaded: boolean;
path?: string;
styleSheetContent?: string;
extensionData: ExtensionData;
private constructor() {
}
static fromExtensionTheme(iconTheme: IThemeExtensionPoint, normalizedAbsolutePath: string, extensionData: ExtensionData): FileIconThemeData {
let themeData = new FileIconThemeData();
themeData.id = extensionData.extensionId + '-' + iconTheme.id;
themeData.label = iconTheme.label || Paths.basename(iconTheme.path);
themeData.settingsId = iconTheme.id;
themeData.description = iconTheme.description;
themeData.path = normalizedAbsolutePath;
themeData.extensionData = extensionData;
themeData.isLoaded = false;
return themeData;
}
}
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
'use strict';
import nls = require('vs/nls');
import * as types from 'vs/base/common/types';
import * as Paths from 'path';
import { ExtensionsRegistry, ExtensionMessageCollector } from 'vs/platform/extensions/common/extensionsRegistry';
import { ExtensionData, IThemeExtensionPoint } from 'vs/workbench/services/themes/common/workbenchThemeService';
import { ColorThemeData } from 'vs/workbench/services/themes/electron-browser/colorThemeData';
import { IExtensionService } from 'vs/platform/extensions/common/extensions';
import { TPromise } from 'vs/base/common/winjs.base';
import Event, { Emitter } from 'vs/base/common/event';
import { FileIconThemeData } from 'vs/workbench/services/themes/electron-browser/fileIconThemeData';
let iconThemeExtPoint = ExtensionsRegistry.registerExtensionPoint<IThemeExtensionPoint[]>('iconThemes', [], {
description: nls.localize('vscode.extension.contributes.iconThemes', 'Contributes file icon themes.'),
type: 'array',
items: {
type: 'object',
defaultSnippets: [{ body: { id: '${1:id}', label: '${2:label}', path: './fileicons/${3:id}-icon-theme.json' } }],
properties: {
id: {
description: nls.localize('vscode.extension.contributes.iconThemes.id', 'Id of the icon theme as used in the user settings.'),
type: 'string'
},
label: {
description: nls.localize('vscode.extension.contributes.iconThemes.label', 'Label of the icon theme as shown in the UI.'),
type: 'string'
},
path: {
description: nls.localize('vscode.extension.contributes.iconThemes.path', 'Path of the icon theme definition file. The path is relative to the extension folder and is typically \'./icons/awesome-icon-theme.json\'.'),
type: 'string'
}
},
required: ['path', 'id']
}
});
export class FileIconThemeStore {
private knownIconThemes: FileIconThemeData[];
private onDidChangeEmitter: Emitter<FileIconThemeData[]>;
public get onDidChange(): Event<FileIconThemeData[]> { return this.onDidChangeEmitter.event; }
constructor( @IExtensionService private extensionService: IExtensionService) {
this.knownIconThemes = [];
this.onDidChangeEmitter = new Emitter<FileIconThemeData[]>();
this.initialize();
}
private initialize() {
iconThemeExtPoint.setHandler((extensions) => {
for (let ext of extensions) {
let extensionData = {
extensionId: ext.description.id,
extensionPublisher: ext.description.publisher,
extensionName: ext.description.name,
extensionIsBuiltin: ext.description.isBuiltin
};
this.onIconThemes(ext.description.extensionFolderPath, extensionData, ext.value, ext.collector);
}
this.onDidChangeEmitter.fire(this.knownIconThemes);
});
}
private onIconThemes(extensionFolderPath: string, extensionData: ExtensionData, iconThemes: IThemeExtensionPoint[], collector: ExtensionMessageCollector): void {
if (!Array.isArray(iconThemes)) {
collector.error(nls.localize(
'reqarray',
"Extension point `{0}` must be an array.",
iconThemeExtPoint.name
));
return;
}
iconThemes.forEach(iconTheme => {
if (!iconTheme.path || !types.isString(iconTheme.path)) {
collector.error(nls.localize(
'reqpath',
"Expected string in `contributes.{0}.path`. Provided value: {1}",
iconThemeExtPoint.name,
String(iconTheme.path)
));
return;
}
if (!iconTheme.id || !types.isString(iconTheme.id)) {
collector.error(nls.localize(
'reqid',
"Expected string in `contributes.{0}.id`. Provided value: {1}",
iconThemeExtPoint.name,
String(iconTheme.path)
));
return;
}
let normalizedAbsolutePath = Paths.normalize(Paths.join(extensionFolderPath, iconTheme.path));
if (normalizedAbsolutePath.indexOf(Paths.normalize(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.", iconThemeExtPoint.name, normalizedAbsolutePath, extensionFolderPath));
}
let themeData = ColorThemeData.fromExtensionTheme(iconTheme, normalizedAbsolutePath, extensionData);
this.knownIconThemes.push(themeData);
});
}
public findThemeData(iconTheme: string): TPromise<FileIconThemeData> {
return this.getFileIconThemes().then(allIconSets => {
for (let iconSet of allIconSets) {
if (iconSet.id === iconTheme) {
return iconSet;
}
}
return null;
});
}
public findThemeBySettingsId(settingsId: string): TPromise<FileIconThemeData> {
return this.getFileIconThemes().then(allIconSets => {
for (let iconSet of allIconSets) {
if (iconSet.settingsId === settingsId) {
return iconSet;
}
}
return null;
});
}
public getFileIconThemes(): TPromise<FileIconThemeData[]> {
return this.extensionService.onReady().then(isReady => {
return this.knownIconThemes;
});
}
}
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册