Allow to contribute to icon registry from icon contribution point. Fixes #114942
This commit is contained in:
parent
082af46e66
commit
684f61b456
7 changed files with 364 additions and 35 deletions
|
@ -1230,6 +1230,10 @@ export function asCSSUrl(uri: URI): string {
|
|||
return `url('${FileAccess.asBrowserUri(uri).toString(true).replace(/'/g, '%27')}')`;
|
||||
}
|
||||
|
||||
export function asCSSPropertyValue(value: string) {
|
||||
return `'${value.replace(/'/g, '%27')}'`;
|
||||
}
|
||||
|
||||
export function triggerDownload(dataOrUri: Uint8Array | URI, name: string): void {
|
||||
|
||||
// If the data is provided as Buffer, we create a
|
||||
|
|
|
@ -16,7 +16,7 @@ import { ColorIdentifier, Extensions, IColorRegistry } from 'vs/platform/theme/c
|
|||
import { Extensions as ThemingExtensions, ICssStyleCollector, IFileIconTheme, IThemingRegistry, ITokenStyle } from 'vs/platform/theme/common/themeService';
|
||||
import { IDisposable, Disposable } from 'vs/base/common/lifecycle';
|
||||
import { ColorScheme } from 'vs/platform/theme/common/theme';
|
||||
import { getIconRegistry } from 'vs/platform/theme/common/iconRegistry';
|
||||
import { getIconsStyleSheet } from 'vs/platform/theme/browser/iconsStyleSheet';
|
||||
|
||||
const VS_THEME_NAME = 'vs';
|
||||
const VS_DARK_THEME_NAME = 'vs-dark';
|
||||
|
@ -214,9 +214,9 @@ export class StandaloneThemeServiceImpl extends Disposable implements IStandalon
|
|||
this._knownThemes.set(VS_DARK_THEME_NAME, newBuiltInTheme(VS_DARK_THEME_NAME));
|
||||
this._knownThemes.set(HC_BLACK_THEME_NAME, newBuiltInTheme(HC_BLACK_THEME_NAME));
|
||||
|
||||
const iconRegistry = getIconRegistry();
|
||||
const iconsStyleSheet = getIconsStyleSheet();
|
||||
|
||||
this._codiconCSS = iconRegistry.getCSS();
|
||||
this._codiconCSS = iconsStyleSheet.getCSS();
|
||||
this._themeCSS = '';
|
||||
this._allCSS = `${this._codiconCSS}\n${this._themeCSS}`;
|
||||
this._globalStyleElement = null;
|
||||
|
@ -224,8 +224,8 @@ export class StandaloneThemeServiceImpl extends Disposable implements IStandalon
|
|||
this._colorMapOverride = null;
|
||||
this.setTheme(VS_THEME_NAME);
|
||||
|
||||
iconRegistry.onDidChange(() => {
|
||||
this._codiconCSS = iconRegistry.getCSS();
|
||||
iconsStyleSheet.onDidChange(() => {
|
||||
this._codiconCSS = iconsStyleSheet.getCSS();
|
||||
this._updateCSS();
|
||||
});
|
||||
}
|
||||
|
|
61
src/vs/platform/theme/browser/iconsStyleSheet.ts
Normal file
61
src/vs/platform/theme/browser/iconsStyleSheet.ts
Normal file
|
@ -0,0 +1,61 @@
|
|||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { ThemeIcon } from 'vs/platform/theme/common/themeService';
|
||||
import { getIconRegistry, IconContribution, IconFontContribution } from 'vs/platform/theme/common/iconRegistry';
|
||||
import { asCSSPropertyValue, asCSSUrl } from 'vs/base/browser/dom';
|
||||
import { Event, Emitter } from 'vs/base/common/event';
|
||||
|
||||
|
||||
export interface IIconsStyleSheet {
|
||||
getCSS(): string;
|
||||
readonly onDidChange: Event<void>;
|
||||
}
|
||||
|
||||
export function getIconsStyleSheet(): IIconsStyleSheet {
|
||||
const onDidChangeEmmiter = new Emitter<void>();
|
||||
const iconRegistry = getIconRegistry();
|
||||
iconRegistry.onDidChange(() => onDidChangeEmmiter.fire());
|
||||
|
||||
return {
|
||||
onDidChange: onDidChangeEmmiter.event,
|
||||
getCSS() {
|
||||
const usedFontIds: { [id: string]: IconFontContribution } = {};
|
||||
const formatIconRule = (contribution: IconContribution): string | undefined => {
|
||||
let definition = contribution.defaults;
|
||||
while (ThemeIcon.isThemeIcon(definition)) {
|
||||
const c = iconRegistry.getIcon(definition.id);
|
||||
if (!c) {
|
||||
return undefined;
|
||||
}
|
||||
definition = c.defaults;
|
||||
}
|
||||
const fontId = definition.fontId;
|
||||
if (fontId) {
|
||||
const fontContribution = iconRegistry.getIconFont(fontId);
|
||||
if (fontContribution) {
|
||||
usedFontIds[fontId] = fontContribution;
|
||||
return `.codicon-${contribution.id}:before { content: '${definition.character}'; font-family: ${asCSSPropertyValue(fontId)}; }`;
|
||||
}
|
||||
}
|
||||
return `.codicon-${contribution.id}:before { content: '${definition.character}'; }`;
|
||||
};
|
||||
|
||||
const rules = [];
|
||||
for (let contribution of iconRegistry.getIcons()) {
|
||||
const rule = formatIconRule(contribution);
|
||||
if (rule) {
|
||||
rules.push(rule);
|
||||
}
|
||||
}
|
||||
for (let id in usedFontIds) {
|
||||
const fontContribution = usedFontIds[id];
|
||||
const src = fontContribution.definition.src.map(l => `${asCSSUrl(l.location)} format('${l.format}')`).join(', ');
|
||||
rules.push(`@font-face { src: ${src}; font-family: ${asCSSPropertyValue(id)}; }`);
|
||||
}
|
||||
return rules.join('\n');
|
||||
}
|
||||
};
|
||||
}
|
|
@ -11,11 +11,11 @@ import { localize } from 'vs/nls';
|
|||
import { Extensions as JSONExtensions, IJSONContributionRegistry } from 'vs/platform/jsonschemas/common/jsonContributionRegistry';
|
||||
import { RunOnceScheduler } from 'vs/base/common/async';
|
||||
import * as Codicons from 'vs/base/common/codicons';
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
|
||||
// ------ API types
|
||||
|
||||
|
||||
// color registry
|
||||
// icon registry
|
||||
export const Extensions = {
|
||||
IconContribution: 'base.contributions.icons'
|
||||
};
|
||||
|
@ -34,6 +34,15 @@ export interface IconContribution {
|
|||
defaults: IconDefaults;
|
||||
}
|
||||
|
||||
export interface IconFontContribution {
|
||||
id: string;
|
||||
definition: IconFontDefinition;
|
||||
}
|
||||
|
||||
export interface IconFontDefinition {
|
||||
src: { location: URI, format: string; }[]
|
||||
}
|
||||
|
||||
export interface IIconRegistry {
|
||||
|
||||
readonly onDidChange: Event<void>;
|
||||
|
@ -42,12 +51,12 @@ export interface IIconRegistry {
|
|||
* Register a icon to the registry.
|
||||
* @param id The icon id
|
||||
* @param defaults The default values
|
||||
* @description the description
|
||||
* @param description The description
|
||||
*/
|
||||
registerIcon(id: string, defaults: IconDefaults, description?: string): ThemeIcon;
|
||||
|
||||
/**
|
||||
* Register a icon to the registry.
|
||||
* Deregister a icon from the registry.
|
||||
*/
|
||||
deregisterIcon(id: string): void;
|
||||
|
||||
|
@ -62,7 +71,7 @@ export interface IIconRegistry {
|
|||
getIcon(id: string): IconContribution | undefined;
|
||||
|
||||
/**
|
||||
* JSON schema for an object to assign icon values to one of the color contributions.
|
||||
* JSON schema for an object to assign icon values to one of the icon contributions.
|
||||
*/
|
||||
getIconSchema(): IJSONSchema;
|
||||
|
||||
|
@ -72,10 +81,26 @@ export interface IIconRegistry {
|
|||
getIconReferenceSchema(): IJSONSchema;
|
||||
|
||||
/**
|
||||
* The CSS for all icons
|
||||
* Register a icon font to the registry.
|
||||
* @param id The icon font id
|
||||
* @param definition The iocn font definition
|
||||
*/
|
||||
getCSS(): string;
|
||||
registerIconFont(id: string, definition: IconFontDefinition): IconFontContribution;
|
||||
|
||||
/**
|
||||
* Deregister an icon font to the registry.
|
||||
*/
|
||||
deregisterIconFont(id: string): void;
|
||||
|
||||
/**
|
||||
* Get all icon font contributions
|
||||
*/
|
||||
getIconFonts(): IconFontContribution[];
|
||||
|
||||
/**
|
||||
* Get the icon font for the given id
|
||||
*/
|
||||
getIconFont(id: string): IconFontContribution | undefined;
|
||||
}
|
||||
|
||||
class IconRegistry implements IIconRegistry {
|
||||
|
@ -99,10 +124,13 @@ class IconRegistry implements IIconRegistry {
|
|||
type: 'object',
|
||||
properties: {}
|
||||
};
|
||||
private iconReferenceSchema: IJSONSchema & { enum: string[], enumDescriptions: string[] } = { type: 'string', enum: [], enumDescriptions: [] };
|
||||
private iconReferenceSchema: IJSONSchema & { enum: string[], enumDescriptions: string[] } = { type: 'string', pattern: `^${Codicons.CSSIcon.iconNameExpression}$`, enum: [], enumDescriptions: [] };
|
||||
|
||||
private iconFontsById: { [key: string]: IconFontContribution };
|
||||
|
||||
constructor() {
|
||||
this.iconsById = {};
|
||||
this.iconFontsById = {};
|
||||
}
|
||||
|
||||
public registerIcon(id: string, defaults: IconDefaults, description?: string, deprecationMessage?: string): ThemeIcon {
|
||||
|
@ -164,27 +192,27 @@ class IconRegistry implements IIconRegistry {
|
|||
return this.iconReferenceSchema;
|
||||
}
|
||||
|
||||
public getCSS() {
|
||||
const rules = [];
|
||||
for (let id in this.iconsById) {
|
||||
const rule = this.formatRule(id);
|
||||
if (rule) {
|
||||
rules.push(rule);
|
||||
}
|
||||
public registerIconFont(id: string, definition: IconFontDefinition): IconFontContribution {
|
||||
const existing = this.iconFontsById[id];
|
||||
if (existing) {
|
||||
return existing;
|
||||
}
|
||||
return rules.join('\n');
|
||||
let iconFontContribution: IconFontContribution = { id, definition };
|
||||
this.iconFontsById[id] = iconFontContribution;
|
||||
this._onDidChange.fire();
|
||||
return iconFontContribution;
|
||||
}
|
||||
|
||||
private formatRule(id: string): string | undefined {
|
||||
let definition = this.iconsById[id].defaults;
|
||||
while (ThemeIcon.isThemeIcon(definition)) {
|
||||
const c = this.iconsById[definition.id];
|
||||
if (!c) {
|
||||
return undefined;
|
||||
}
|
||||
definition = c.defaults;
|
||||
}
|
||||
return `.codicon-${id}:before { content: '${definition.character}'; }`;
|
||||
public deregisterIconFont(id: string): void {
|
||||
delete this.iconFontsById[id];
|
||||
}
|
||||
|
||||
public getIconFonts(): IconFontContribution[] {
|
||||
return Object.keys(this.iconFontsById).map(id => this.iconFontsById[id]);
|
||||
}
|
||||
|
||||
public getIconFont(id: string): IconFontContribution | undefined {
|
||||
return this.iconFontsById[id];
|
||||
}
|
||||
|
||||
public toString() {
|
||||
|
|
|
@ -11,6 +11,7 @@ import { LifecyclePhase } from 'vs/workbench/services/lifecycle/common/lifecycle
|
|||
// --- other interested parties
|
||||
import { JSONValidationExtensionPoint } from 'vs/workbench/api/common/jsonValidationExtensionPoint';
|
||||
import { ColorExtensionPoint } from 'vs/workbench/services/themes/common/colorExtensionPoint';
|
||||
import { IconExtensionPoint, IconFontExtensionPoint } from 'vs/workbench/services/themes/common/iconExtensionPoint';
|
||||
import { TokenClassificationExtensionPoints } from 'vs/workbench/services/themes/common/tokenClassificationExtensionPoint';
|
||||
import { LanguageConfigurationFileHandler } from 'vs/workbench/contrib/codeEditor/browser/languageConfigurationExtensionPoint';
|
||||
|
||||
|
@ -79,6 +80,8 @@ export class ExtensionPoints implements IWorkbenchContribution {
|
|||
// Classes that handle extension points...
|
||||
this.instantiationService.createInstance(JSONValidationExtensionPoint);
|
||||
this.instantiationService.createInstance(ColorExtensionPoint);
|
||||
this.instantiationService.createInstance(IconExtensionPoint);
|
||||
this.instantiationService.createInstance(IconFontExtensionPoint);
|
||||
this.instantiationService.createInstance(TokenClassificationExtensionPoints);
|
||||
this.instantiationService.createInstance(LanguageConfigurationFileHandler);
|
||||
}
|
||||
|
|
|
@ -38,7 +38,7 @@ import { ColorScheme } from 'vs/platform/theme/common/theme';
|
|||
import { IHostColorSchemeService } from 'vs/workbench/services/themes/common/hostColorSchemeService';
|
||||
import { RunOnceScheduler, Sequencer } from 'vs/base/common/async';
|
||||
import { IUserDataInitializationService } from 'vs/workbench/services/userData/browser/userDataInit';
|
||||
import { getIconRegistry } from 'vs/platform/theme/common/iconRegistry';
|
||||
import { getIconsStyleSheet } from 'vs/platform/theme/browser/iconsStyleSheet';
|
||||
|
||||
// implementation
|
||||
|
||||
|
@ -183,13 +183,13 @@ export class WorkbenchThemeService implements IWorkbenchThemeService {
|
|||
const codiconStyleSheet = createStyleSheet();
|
||||
codiconStyleSheet.id = 'codiconStyles';
|
||||
|
||||
const iconRegistry = getIconRegistry();
|
||||
const iconsStyleSheet = getIconsStyleSheet();
|
||||
function updateAll() {
|
||||
codiconStyleSheet.textContent = iconRegistry.getCSS();
|
||||
codiconStyleSheet.textContent = iconsStyleSheet.getCSS();
|
||||
}
|
||||
|
||||
const delayer = new RunOnceScheduler(updateAll, 0);
|
||||
iconRegistry.onDidChange(() => delayer.schedule());
|
||||
iconsStyleSheet.onDidChange(() => delayer.schedule());
|
||||
delayer.schedule();
|
||||
}
|
||||
|
||||
|
|
233
src/vs/workbench/services/themes/common/iconExtensionPoint.ts
Normal file
233
src/vs/workbench/services/themes/common/iconExtensionPoint.ts
Normal file
|
@ -0,0 +1,233 @@
|
|||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import * as nls from 'vs/nls';
|
||||
import { ExtensionsRegistry } from 'vs/workbench/services/extensions/common/extensionsRegistry';
|
||||
import { IIconRegistry, Extensions as IconRegistryExtensions, IconFontDefinition } from 'vs/platform/theme/common/iconRegistry';
|
||||
import { Registry } from 'vs/platform/registry/common/platform';
|
||||
import { CSSIcon } from 'vs/base/common/codicons';
|
||||
import { fontIdRegex } from 'vs/workbench/services/themes/common/productIconThemeSchema';
|
||||
import * as resources from 'vs/base/common/resources';
|
||||
import { IExtensionDescription } from 'vs/platform/extensions/common/extensions';
|
||||
|
||||
interface IIconExtensionPoint {
|
||||
id: string;
|
||||
description: string;
|
||||
default: { iconFontId: string; character: string; } | string;
|
||||
}
|
||||
|
||||
interface IIconFontExtensionPoint {
|
||||
id: string;
|
||||
src: {
|
||||
path: string;
|
||||
format: string;
|
||||
}[];
|
||||
}
|
||||
|
||||
const iconRegistry: IIconRegistry = Registry.as<IIconRegistry>(IconRegistryExtensions.IconContribution);
|
||||
|
||||
const iconReferenceSchema = iconRegistry.getIconReferenceSchema();
|
||||
const iconIdPattern = `^${CSSIcon.iconNameExpression}$`;
|
||||
|
||||
const iconConfigurationExtPoint = ExtensionsRegistry.registerExtensionPoint<IIconExtensionPoint[]>({
|
||||
extensionPoint: 'icons',
|
||||
jsonSchema: {
|
||||
description: nls.localize('contributes.icons', 'Contributes extension defined themable icons'),
|
||||
type: 'array',
|
||||
items: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
id: {
|
||||
type: 'string',
|
||||
description: nls.localize('contributes.icon.id', 'The identifier of the themable icon'),
|
||||
pattern: iconIdPattern,
|
||||
patternErrorMessage: nls.localize('contributes.icon.id.format', 'Identifiers must only contain letters, digits and minus.'),
|
||||
},
|
||||
description: {
|
||||
type: 'string',
|
||||
description: nls.localize('contributes.icon.description', 'The description of the themable icon'),
|
||||
},
|
||||
default: {
|
||||
anyOf: [
|
||||
iconReferenceSchema,
|
||||
{
|
||||
type: 'object',
|
||||
properties: {
|
||||
iconFontId: {
|
||||
description: nls.localize('contributes.default.fontId', 'The id of the icon font that defines the default icon.'),
|
||||
type: 'string'
|
||||
},
|
||||
character: {
|
||||
description: nls.localize('contributes.default.character', 'The character in the icon font.'),
|
||||
type: 'string'
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
description: nls.localize('contributes.default', 'The default of the icon. Either a reference to a '),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
const iconFontConfigurationExtPoint = ExtensionsRegistry.registerExtensionPoint<IIconFontExtensionPoint[]>({
|
||||
extensionPoint: 'iconFonts',
|
||||
jsonSchema: {
|
||||
description: nls.localize('contributes.iconFonts', 'Contributes icons fonts to be used by contributed icons'),
|
||||
type: 'array',
|
||||
items: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
id: {
|
||||
type: 'string',
|
||||
description: nls.localize('contributes.iconFonts.id', 'The ID of the font.'),
|
||||
pattern: fontIdRegex,
|
||||
patternErrorMessage: nls.localize('contributes.iconFonts.id.formatError', 'The ID must only contain letters, numbers, underscore and minus.')
|
||||
},
|
||||
src: {
|
||||
type: 'array',
|
||||
description: nls.localize('contributes.iconFonts.src', 'The location of the font.'),
|
||||
items: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
path: {
|
||||
type: 'string',
|
||||
description: nls.localize('contributes.iconFonts.font-path', 'The font path, relative to the current product icon theme file.'),
|
||||
},
|
||||
format: {
|
||||
type: 'string',
|
||||
description: nls.localize('contributes.iconFonts.font-format', 'The format of the font.'),
|
||||
enum: ['woff', 'woff2', 'truetype', 'opentype', 'embedded-opentype', 'svg']
|
||||
}
|
||||
},
|
||||
required: [
|
||||
'path',
|
||||
'format'
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
export class IconExtensionPoint {
|
||||
|
||||
constructor() {
|
||||
iconConfigurationExtPoint.setHandler((extensions, delta) => {
|
||||
for (const extension of delta.added) {
|
||||
const extensionValue = <IIconExtensionPoint[]>extension.value;
|
||||
const collector = extension.collector;
|
||||
|
||||
if (!extension.description.enableProposedApi) {
|
||||
collector.error(nls.localize('invalid.icons.proposedAPI', "'configuration.icons is a proposed constribution point and only available when running out of dev or with the following command line switch: --enable-proposed-api {0}", extension.description.identifier.value));
|
||||
return;
|
||||
}
|
||||
|
||||
if (!extensionValue || !Array.isArray(extensionValue)) {
|
||||
collector.error(nls.localize('invalid.icons.configuration', "'configuration.icons' must be a array"));
|
||||
return;
|
||||
}
|
||||
|
||||
for (const iconContribution of extensionValue) {
|
||||
if (typeof iconContribution.id !== 'string' || iconContribution.id.length === 0) {
|
||||
collector.error(nls.localize('invalid.icons.id', "'configuration.icons.id' must be defined and can not be empty"));
|
||||
return;
|
||||
}
|
||||
if (!iconContribution.id.match(iconIdPattern)) {
|
||||
collector.error(nls.localize('invalid.icons.id.format', "'configuration.icons.id' must only contain letters, digits and minuses"));
|
||||
return;
|
||||
}
|
||||
if (typeof iconContribution.description !== 'string' || iconContribution.id.length === 0) {
|
||||
collector.error(nls.localize('invalid.icons.description', "'configuration.icons.description' must be defined and can not be empty"));
|
||||
return;
|
||||
}
|
||||
let defaultIcon = iconContribution.default;
|
||||
if (typeof defaultIcon === 'string') {
|
||||
iconRegistry.registerIcon(iconContribution.id, { id: defaultIcon }, iconContribution.description);
|
||||
} else if (typeof defaultIcon === 'object' && typeof defaultIcon.iconFontId === 'string' && typeof defaultIcon.character === 'string') {
|
||||
iconRegistry.registerIcon(iconContribution.id, {
|
||||
fontId: getFontId(extension.description, defaultIcon.iconFontId),
|
||||
character: defaultIcon.character,
|
||||
}, iconContribution.description);
|
||||
} else {
|
||||
collector.error(nls.localize('invalid.icons.default', "'configuration.icons.default' must be either a reference to the id of an other theme icon (string) or a icon definition (object)"));
|
||||
}
|
||||
}
|
||||
}
|
||||
for (const extension of delta.removed) {
|
||||
const extensionValue = <IIconExtensionPoint[]>extension.value;
|
||||
for (const iconContribution of extensionValue) {
|
||||
iconRegistry.deregisterIcon(iconContribution.id);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
export class IconFontExtensionPoint {
|
||||
|
||||
constructor() {
|
||||
iconFontConfigurationExtPoint.setHandler((_extensions, delta) => {
|
||||
for (const extension of delta.added) {
|
||||
const extensionValue = <IIconFontExtensionPoint[]>extension.value;
|
||||
const collector = extension.collector;
|
||||
|
||||
if (!extension.description.enableProposedApi) {
|
||||
collector.error(nls.localize('invalid.iconFonts.proposedAPI', "'configuration.iconFonts is a proposed constribution point and only available when running out of dev or with the following command line switch: --enable-proposed-api {0}", extension.description.identifier.value));
|
||||
return;
|
||||
}
|
||||
|
||||
if (!extensionValue || !Array.isArray(extensionValue)) {
|
||||
collector.error(nls.localize('invalid.iconFonts.configuration', "'configuration.iconFonts' must be a array"));
|
||||
return;
|
||||
}
|
||||
|
||||
for (const iconFontContribution of extensionValue) {
|
||||
if (typeof iconFontContribution.id !== 'string' || iconFontContribution.id.length === 0) {
|
||||
collector.error(nls.localize('invalid.iconFonts.id', "'configuration.iconFonts.id' must be defined and can not be empty"));
|
||||
return;
|
||||
}
|
||||
if (!iconFontContribution.id.match(fontIdRegex)) {
|
||||
collector.error(nls.localize('invalid.iconFonts.id.format', "'configuration.iconFonts.id' must only contain letters, numbers, underscore and minus."));
|
||||
return;
|
||||
}
|
||||
if (!Array.isArray(iconFontContribution.src) || !iconFontContribution.src.length) {
|
||||
collector.error(nls.localize('invalid.iconFonts.src', "'configuration.iconFonts.src' must be an array with locations of the icon font."));
|
||||
return;
|
||||
}
|
||||
const def: IconFontDefinition = { src: [] };
|
||||
for (const src of iconFontContribution.src) {
|
||||
if (typeof src === 'object' && typeof src.path === 'string' && typeof src.format === 'string') {
|
||||
const extensionLocation = extension.description.extensionLocation;
|
||||
const iconFontLocation = resources.joinPath(extensionLocation, src.path);
|
||||
if (!resources.isEqualOrParent(iconFontLocation, extensionLocation)) {
|
||||
collector.warn(nls.localize('invalid.iconFonts.src.path', "Expected `contributes.iconFonts.src.path` ({0}) to be included inside extension's folder ({0}). This might make the extension non-portable.", iconFontLocation.path, extensionLocation.path));
|
||||
}
|
||||
def.src.push({
|
||||
location: iconFontLocation,
|
||||
format: src.format,
|
||||
});
|
||||
} else {
|
||||
collector.error(nls.localize('invalid.iconFonts.src.item', "Items of 'configuration.iconFonts.src' must be objects with properties 'path' and 'format'"));
|
||||
}
|
||||
}
|
||||
iconRegistry.registerIconFont(getFontId(extension.description, iconFontContribution.id), def);
|
||||
}
|
||||
}
|
||||
for (const extension of delta.removed) {
|
||||
const extensionValue = <IIconFontExtensionPoint[]>extension.value;
|
||||
for (const iconFontContribution of extensionValue) {
|
||||
iconRegistry.deregisterIconFont(getFontId(extension.description, iconFontContribution.id));
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function getFontId(description: IExtensionDescription, iconFontId: string) {
|
||||
return `${description.identifier.value}/${iconFontId}`;
|
||||
}
|
Loading…
Reference in a new issue