@sussudio/platform
Version:
Internal APIs for VS Code's service injection the base services.
234 lines (233 loc) • 8.06 kB
JavaScript
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { RunOnceScheduler } from '@sussudio/base/common/async.mjs';
import { Codicon, CSSIcon } from '@sussudio/base/common/codicons.mjs';
import { Emitter } from '@sussudio/base/common/event.mjs';
import { isString } from '@sussudio/base/common/types.mjs';
import { URI } from '@sussudio/base/common/uri.mjs';
import { localize } from 'vscode-nls.mjs';
import { Extensions as JSONExtensions } from '../../jsonschemas/common/jsonContributionRegistry.mjs';
import * as platform from '../../registry/common/platform.mjs';
import { ThemeIcon } from './themeService.mjs';
// icon registry
export const Extensions = {
IconContribution: 'base.contributions.icons',
};
export var IconContribution;
(function (IconContribution) {
function getDefinition(contribution, registry) {
let definition = contribution.defaults;
while (ThemeIcon.isThemeIcon(definition)) {
const c = iconRegistry.getIcon(definition.id);
if (!c) {
return undefined;
}
definition = c.defaults;
}
return definition;
}
IconContribution.getDefinition = getDefinition;
})(IconContribution || (IconContribution = {}));
export var IconFontDefinition;
(function (IconFontDefinition) {
function toJSONObject(iconFont) {
return {
weight: iconFont.weight,
style: iconFont.style,
src: iconFont.src.map((s) => ({ format: s.format, location: s.location.toString() })),
};
}
IconFontDefinition.toJSONObject = toJSONObject;
function fromJSONObject(json) {
const stringOrUndef = (s) => (isString(s) ? s : undefined);
if (json && Array.isArray(json.src) && json.src.every((s) => isString(s.format) && isString(s.location))) {
return {
weight: stringOrUndef(json.weight),
style: stringOrUndef(json.style),
src: json.src.map((s) => ({ format: s.format, location: URI.parse(s.location) })),
};
}
return undefined;
}
IconFontDefinition.fromJSONObject = fromJSONObject;
})(IconFontDefinition || (IconFontDefinition = {}));
class IconRegistry {
_onDidChange = new Emitter();
onDidChange = this._onDidChange.event;
iconsById;
iconSchema = {
definitions: {
icons: {
type: 'object',
properties: {
fontId: {
type: 'string',
description: localize(
'iconDefinition.fontId',
'The id of the font to use. If not set, the font that is defined first is used.',
),
},
fontCharacter: {
type: 'string',
description: localize(
'iconDefinition.fontCharacter',
'The font character associated with the icon definition.',
),
},
},
additionalProperties: false,
defaultSnippets: [{ body: { fontCharacter: '\\\\e030' } }],
},
},
type: 'object',
properties: {},
};
iconReferenceSchema = { type: 'string', pattern: `^${CSSIcon.iconNameExpression}$`, enum: [], enumDescriptions: [] };
iconFontsById;
constructor() {
this.iconsById = {};
this.iconFontsById = {};
}
registerIcon(id, defaults, description, deprecationMessage) {
const existing = this.iconsById[id];
if (existing) {
if (description && !existing.description) {
existing.description = description;
this.iconSchema.properties[id].markdownDescription = `${description} $(${id})`;
const enumIndex = this.iconReferenceSchema.enum.indexOf(id);
if (enumIndex !== -1) {
this.iconReferenceSchema.enumDescriptions[enumIndex] = description;
}
this._onDidChange.fire();
}
return existing;
}
const iconContribution = { id, description, defaults, deprecationMessage };
this.iconsById[id] = iconContribution;
const propertySchema = { $ref: '#/definitions/icons' };
if (deprecationMessage) {
propertySchema.deprecationMessage = deprecationMessage;
}
if (description) {
propertySchema.markdownDescription = `${description}: $(${id})`;
}
this.iconSchema.properties[id] = propertySchema;
this.iconReferenceSchema.enum.push(id);
this.iconReferenceSchema.enumDescriptions.push(description || '');
this._onDidChange.fire();
return { id };
}
deregisterIcon(id) {
delete this.iconsById[id];
delete this.iconSchema.properties[id];
const index = this.iconReferenceSchema.enum.indexOf(id);
if (index !== -1) {
this.iconReferenceSchema.enum.splice(index, 1);
this.iconReferenceSchema.enumDescriptions.splice(index, 1);
}
this._onDidChange.fire();
}
getIcons() {
return Object.keys(this.iconsById).map((id) => this.iconsById[id]);
}
getIcon(id) {
return this.iconsById[id];
}
getIconSchema() {
return this.iconSchema;
}
getIconReferenceSchema() {
return this.iconReferenceSchema;
}
registerIconFont(id, definition) {
const existing = this.iconFontsById[id];
if (existing) {
return existing;
}
this.iconFontsById[id] = definition;
this._onDidChange.fire();
return definition;
}
deregisterIconFont(id) {
delete this.iconFontsById[id];
}
getIconFont(id) {
return this.iconFontsById[id];
}
toString() {
const sorter = (i1, i2) => {
return i1.id.localeCompare(i2.id);
};
const classNames = (i) => {
while (ThemeIcon.isThemeIcon(i.defaults)) {
i = this.iconsById[i.defaults.id];
}
return `codicon codicon-${i ? i.id : ''}`;
};
const reference = [];
reference.push(
`| preview | identifier | default codicon ID | description`,
);
reference.push(
`| ----------- | --------------------------------- | --------------------------------- | --------------------------------- |`,
);
const contributions = Object.keys(this.iconsById).map((key) => this.iconsById[key]);
for (const i of contributions.filter((i) => !!i.description).sort(sorter)) {
reference.push(
`|<i class="${classNames(i)}"></i>|${i.id}|${ThemeIcon.isThemeIcon(i.defaults) ? i.defaults.id : i.id}|${
i.description || ''
}|`,
);
}
reference.push(`| preview | identifier `);
reference.push(`| ----------- | --------------------------------- |`);
for (const i of contributions.filter((i) => !ThemeIcon.isThemeIcon(i.defaults)).sort(sorter)) {
reference.push(`|<i class="${classNames(i)}"></i>|${i.id}|`);
}
return reference.join('\n');
}
}
const iconRegistry = new IconRegistry();
platform.Registry.add(Extensions.IconContribution, iconRegistry);
export function registerIcon(id, defaults, description, deprecationMessage) {
return iconRegistry.registerIcon(id, defaults, description, deprecationMessage);
}
export function getIconRegistry() {
return iconRegistry;
}
function initialize() {
for (const icon of Codicon.getAll()) {
iconRegistry.registerIcon(icon.id, icon.definition, icon.description);
}
}
initialize();
export const iconsSchemaId = 'vscode://schemas/icons';
const schemaRegistry = platform.Registry.as(JSONExtensions.JSONContribution);
schemaRegistry.registerSchema(iconsSchemaId, iconRegistry.getIconSchema());
const delayer = new RunOnceScheduler(() => schemaRegistry.notifySchemaChanged(iconsSchemaId), 200);
iconRegistry.onDidChange(() => {
if (!delayer.isScheduled()) {
delayer.schedule();
}
});
//setTimeout(_ => console.log(iconRegistry.toString()), 5000);
// common icons
export const widgetClose = registerIcon(
'widget-close',
Codicon.close,
localize('widgetClose', 'Icon for the close action in widgets.'),
);
export const gotoPreviousLocation = registerIcon(
'goto-previous-location',
Codicon.arrowUp,
localize('previousChangeIcon', 'Icon for goto previous editor location.'),
);
export const gotoNextLocation = registerIcon(
'goto-next-location',
Codicon.arrowDown,
localize('nextChangeIcon', 'Icon for goto next editor location.'),
);
export const syncing = ThemeIcon.modify(Codicon.sync, 'spin');
export const spinningLoading = ThemeIcon.modify(Codicon.loading, 'spin');