From f35a67b397143fdd148e33804506c903ce9b7c66 Mon Sep 17 00:00:00 2001 From: Anton Kosyakov Date: Wed, 29 Jul 2020 13:04:54 +0000 Subject: [PATCH] [vscode] fix #7634: support theme icons Signed-off-by: Anton Kosyakov --- packages/monaco/src/browser/monaco-loader.ts | 5 +++-- packages/monaco/src/typings/monaco/index.d.ts | 4 ++++ packages/plugin-ext/src/common/plugin-api-rpc.ts | 2 +- packages/plugin-ext/src/common/plugin-protocol.ts | 1 + .../plugin-ext/src/hosted/node/scanners/scanner-theia.ts | 9 +++++++-- .../src/main/browser/plugin-contribution-handler.ts | 5 ++++- packages/plugin-ext/src/main/browser/quick-open-main.ts | 8 ++++---- .../browser/view/plugin-tree-view-node-label-provider.ts | 7 +++++-- .../src/main/browser/view/tree-view-widget.tsx | 2 +- 9 files changed, 30 insertions(+), 13 deletions(-) diff --git a/packages/monaco/src/browser/monaco-loader.ts b/packages/monaco/src/browser/monaco-loader.ts index d3aeaf041145e..417e625a5bc5f 100644 --- a/packages/monaco/src/browser/monaco-loader.ts +++ b/packages/monaco/src/browser/monaco-loader.ts @@ -59,6 +59,7 @@ export function loadMonaco(vsRequire: any): Promise { 'vs/base/parts/quickopen/browser/quickOpenWidget', 'vs/base/parts/quickopen/browser/quickOpenModel', 'vs/base/common/filters', + 'vs/platform/theme/common/themeService', 'vs/platform/theme/common/styler', 'vs/platform/theme/common/colorRegistry', 'vs/base/common/color', @@ -81,7 +82,7 @@ export function loadMonaco(vsRequire: any): Promise { keybindingsRegistry: any, keybindingResolver: any, resolvedKeybinding: any, keybindingLabels: any, keyCodes: any, mime: any, editorExtensions: any, simpleServices: any, standaloneServices: any, standaloneLanguages: any, quickOpenWidget: any, quickOpenModel: any, - filters: any, styler: any, colorRegistry: any, color: any, + filters: any, themeService: any, styler: any, colorRegistry: any, color: any, platform: any, modes: any, suggest: any, snippetParser: any, configuration: any, configurationModels: any, resolverService: any, @@ -99,7 +100,7 @@ export function loadMonaco(vsRequire: any): Promise { resolverService, codeEditorService, codeEditorServiceImpl, markerService, openerService); global.monaco.quickOpen = Object.assign({}, quickOpenWidget, quickOpenModel); global.monaco.filters = filters; - global.monaco.theme = styler; + global.monaco.theme = Object.assign({}, themeService, styler); global.monaco.color = Object.assign({}, colorRegistry, color); global.monaco.platform = platform; global.monaco.editorExtensions = editorExtensions; diff --git a/packages/monaco/src/typings/monaco/index.d.ts b/packages/monaco/src/typings/monaco/index.d.ts index a9e0b94511580..6c8c79f2ad2c4 100644 --- a/packages/monaco/src/typings/monaco/index.d.ts +++ b/packages/monaco/src/typings/monaco/index.d.ts @@ -748,6 +748,10 @@ declare module monaco.theme { export interface ThemeIcon { readonly id: string; } + export namespace ThemeIcon { + export function fromString(value: string): ThemeIcon | undefined; + export function asClassName(icon: ThemeIcon): string | undefined; + } } declare module monaco.color { diff --git a/packages/plugin-ext/src/common/plugin-api-rpc.ts b/packages/plugin-ext/src/common/plugin-api-rpc.ts index 350be201ce1b5..b76eb6a6f9536 100644 --- a/packages/plugin-ext/src/common/plugin-api-rpc.ts +++ b/packages/plugin-ext/src/common/plugin-api-rpc.ts @@ -591,7 +591,7 @@ export interface TreeViewItem { icon?: string; iconUrl?: IconUrl; - themeIconId?: 'folder' | 'file'; + themeIconId?: string | 'folder' | 'file'; resourceUri?: UriComponents; diff --git a/packages/plugin-ext/src/common/plugin-protocol.ts b/packages/plugin-ext/src/common/plugin-protocol.ts index 8da14ed3c30ea..6c42c526dcc47 100644 --- a/packages/plugin-ext/src/common/plugin-protocol.ts +++ b/packages/plugin-ext/src/common/plugin-protocol.ts @@ -616,6 +616,7 @@ export interface PluginCommand { title: string; category?: string; iconUrl?: IconUrl; + themeIcon?: string; } export type IconUrl = string | { light: string; dark: string; }; diff --git a/packages/plugin-ext/src/hosted/node/scanners/scanner-theia.ts b/packages/plugin-ext/src/hosted/node/scanners/scanner-theia.ts index c13341be70384..59340023dc058 100644 --- a/packages/plugin-ext/src/hosted/node/scanners/scanner-theia.ts +++ b/packages/plugin-ext/src/hosted/node/scanners/scanner-theia.ts @@ -299,10 +299,15 @@ export class TheiaPluginScanner implements PluginScanner { } protected readCommand({ command, title, category, icon }: PluginPackageCommand, pck: PluginPackage): PluginCommand { + let themeIcon: string | undefined; let iconUrl: IconUrl | undefined; if (icon) { if (typeof icon === 'string') { - iconUrl = this.toPluginUrl(pck, icon); + if (icon.startsWith('$(')) { + themeIcon = icon; + } else { + iconUrl = this.toPluginUrl(pck, icon); + } } else { iconUrl = { light: this.toPluginUrl(pck, icon.light), @@ -310,7 +315,7 @@ export class TheiaPluginScanner implements PluginScanner { }; } } - return { command, title, category, iconUrl }; + return { command, title, category, iconUrl, themeIcon }; } protected toPluginUrl(pck: PluginPackage, relativePath: string): string { diff --git a/packages/plugin-ext/src/main/browser/plugin-contribution-handler.ts b/packages/plugin-ext/src/main/browser/plugin-contribution-handler.ts index 7cc3c6bd5d083..cddd784f4251e 100644 --- a/packages/plugin-ext/src/main/browser/plugin-contribution-handler.ts +++ b/packages/plugin-ext/src/main/browser/plugin-contribution-handler.ts @@ -313,12 +313,15 @@ export class PluginContributionHandler { return Disposable.NULL; } const toDispose = new DisposableCollection(); - for (const { iconUrl, command, category, title } of contribution.commands) { + for (const { iconUrl, themeIcon, command, category, title } of contribution.commands) { const reference = iconUrl && this.style.toIconClass(iconUrl); + const icon = themeIcon && monaco.theme.ThemeIcon.fromString(themeIcon); let iconClass; if (reference) { toDispose.push(reference); iconClass = reference.object.iconClass; + } else if (icon) { + iconClass = monaco.theme.ThemeIcon.asClassName(icon); } toDispose.push(this.registerCommand({ id: command, category, label: title, iconClass })); } diff --git a/packages/plugin-ext/src/main/browser/quick-open-main.ts b/packages/plugin-ext/src/main/browser/quick-open-main.ts index c7b5ab87611d1..fc8a19d448e30 100644 --- a/packages/plugin-ext/src/main/browser/quick-open-main.ts +++ b/packages/plugin-ext/src/main/browser/quick-open-main.ts @@ -171,7 +171,7 @@ export class QuickOpenMainImpl implements QuickOpenMain, QuickOpenModel, Disposa protected convertQuickInputButton(quickInputButton: QuickInputButton, index: number, toDispose: DisposableCollection): QuickInputTitleButtonHandle { const currentIconPath = quickInputButton.iconPath; let newIcon = ''; - let newIconClass = ''; + let newIconClass: string | undefined; if ('id' in currentIconPath || currentIconPath instanceof ThemeIcon) { newIconClass = this.resolveIconClassFromThemeIcon(currentIconPath); } else if (currentIconPath instanceof URI) { @@ -197,8 +197,8 @@ export class QuickOpenMainImpl implements QuickOpenMain, QuickOpenModel, Disposa }; } - private resolveIconClassFromThemeIcon(themeIconID: ThemeIcon): string { - switch (themeIconID.id) { + private resolveIconClassFromThemeIcon(themeIcon: ThemeIcon): string | undefined { + switch (themeIcon.id) { case 'folder': { return this.labelProvider.folderIcon; } @@ -209,7 +209,7 @@ export class QuickOpenMainImpl implements QuickOpenMain, QuickOpenModel, Disposa return 'fa fa-arrow-left'; } default: { - return ''; + return monaco.theme.ThemeIcon.asClassName(themeIcon); } } } diff --git a/packages/plugin-ext/src/main/browser/view/plugin-tree-view-node-label-provider.ts b/packages/plugin-ext/src/main/browser/view/plugin-tree-view-node-label-provider.ts index 3cba13e34fc6d..8518a69119121 100644 --- a/packages/plugin-ext/src/main/browser/view/plugin-tree-view-node-label-provider.ts +++ b/packages/plugin-ext/src/main/browser/view/plugin-tree-view-node-label-provider.ts @@ -43,8 +43,11 @@ export class PluginTreeViewNodeLabelProvider implements LabelProviderContributio return node.icon; } if (node.themeIconId) { - const uri = node.resourceUri && new URI(node.resourceUri) || undefined; - return this.labelProvider.getIcon(URIIconReference.create(node.themeIconId, uri)); + if (node.themeIconId === 'file' || node.themeIconId === 'folder') { + const uri = node.resourceUri && new URI(node.resourceUri) || undefined; + return this.labelProvider.getIcon(URIIconReference.create(node.themeIconId, uri)); + } + return monaco.theme.ThemeIcon.asClassName({ id: node.themeIconId }); } if (node.resourceUri) { return this.labelProvider.getIcon(new URI(node.resourceUri)); diff --git a/packages/plugin-ext/src/main/browser/view/tree-view-widget.tsx b/packages/plugin-ext/src/main/browser/view/tree-view-widget.tsx index 392eb8fa82a93..1fa3e3a4ce00e 100644 --- a/packages/plugin-ext/src/main/browser/view/tree-view-widget.tsx +++ b/packages/plugin-ext/src/main/browser/view/tree-view-widget.tsx @@ -56,7 +56,7 @@ export interface TreeViewNode extends SelectableTreeNode { contextValue?: string; command?: Command; resourceUri?: string; - themeIconId?: 'folder' | 'file'; + themeIconId?: string | 'folder' | 'file'; tooltip?: string; // eslint-disable-next-line @typescript-eslint/no-explicit-any description?: string | boolean | any;