diff --git a/packages/plugin-ext/src/common/plugin-api-rpc.ts b/packages/plugin-ext/src/common/plugin-api-rpc.ts index 6f8ec9fd68506..c6552eb6523a0 100644 --- a/packages/plugin-ext/src/common/plugin-api-rpc.ts +++ b/packages/plugin-ext/src/common/plugin-api-rpc.ts @@ -936,7 +936,7 @@ export interface SourceControlGroupFeatures { export interface ScmRawResource { handle: number, sourceUri: UriComponents, - icons: UriComponents[], + icons: [UriComponents | ThemeIcon | undefined, UriComponents | ThemeIcon | undefined], tooltip: string, strikeThrough: boolean, faded: boolean, diff --git a/packages/plugin-ext/src/main/browser/scm-main.ts b/packages/plugin-ext/src/main/browser/scm-main.ts index 280471cb2d73e..cc9c3174f704c 100644 --- a/packages/plugin-ext/src/main/browser/scm-main.ts +++ b/packages/plugin-ext/src/main/browser/scm-main.ts @@ -40,6 +40,7 @@ import { URI as vscodeURI } from '@theia/core/shared/vscode-uri'; import { Splice } from '../../common/arrays'; import { UriComponents } from '../../common/uri-components'; import { ColorRegistry } from '@theia/core/lib/browser/color-registry'; +import { ThemeIcon } from '@theia/monaco-editor-core/esm/vs/platform/theme/common/themeService'; export class PluginScmResourceGroup implements ScmResourceGroup { @@ -222,13 +223,14 @@ export class PluginScmProvider implements ScmProvider { const { start, deleteCount, rawResources } = groupSlice; const resources = rawResources.map(rawResource => { const { handle, sourceUri, icons, tooltip, strikeThrough, faded, contextValue, command } = rawResource; - const icon = icons[0]; - const iconDark = icons[1] || icon; + const [light, dark] = icons; + const icon = ThemeIcon.isThemeIcon(light) ? light : vscodeURI.revive(light); + const iconDark = (ThemeIcon.isThemeIcon(dark) ? dark : vscodeURI.revive(dark)) || icon; // eslint-disable-next-line @typescript-eslint/no-explicit-any const colorVariable = (rawResource as any).colorId && this.colors.toCssVariableName((rawResource as any).colorId); const decorations = { - icon: icon ? vscodeURI.revive(icon) : undefined, - iconDark: iconDark ? vscodeURI.revive(iconDark) : undefined, + icon: icon, + iconDark: iconDark, tooltip, strikeThrough, // TODO remove the letter and colorId fields when the FileDecorationProvider is applied, see https://github.com/eclipse-theia/theia/pull/8911 diff --git a/packages/plugin-ext/src/plugin/scm.ts b/packages/plugin-ext/src/plugin/scm.ts index 200326b713716..e1181b9a7ef34 100644 --- a/packages/plugin-ext/src/plugin/scm.ts +++ b/packages/plugin-ext/src/plugin/scm.ts @@ -38,17 +38,22 @@ import { RPCProtocol } from '../common/rpc-protocol'; import { URI } from './types-impl'; import { ScmCommandArg } from '../common/plugin-api-rpc'; import { sep } from '@theia/core/lib/common/paths'; +import { ThemeIcon } from '@theia/monaco-editor-core/esm/vs/platform/theme/common/themeService'; type ProviderHandle = number; type GroupHandle = number; type ResourceStateHandle = number; -function getIconResource(decorations?: theia.SourceControlResourceThemableDecorations): theia.Uri | undefined { +function getIconResource(decorations?: theia.SourceControlResourceThemableDecorations): UriComponents | ThemeIcon | undefined { if (!decorations) { return undefined; } else if (typeof decorations.iconPath === 'string') { return URI.file(decorations.iconPath); - } else { + } else if (URI.isUri(decorations.iconPath)) { + return decorations.iconPath; + } else if (ThemeIcon.isThemeIcon(decorations.iconPath)) { return decorations.iconPath; + } else { + return undefined; } } @@ -111,8 +116,8 @@ function compareResourceThemableDecorations(a: theia.SourceControlResourceThemab return 1; } - const aPath = typeof a.iconPath === 'string' ? a.iconPath : a.iconPath.fsPath; - const bPath = typeof b.iconPath === 'string' ? b.iconPath : b.iconPath.fsPath; + const aPath = typeof a.iconPath === 'string' ? a.iconPath : URI.isUri(a.iconPath) ? a.iconPath.fsPath : (a.iconPath as ThemeIcon).id; + const bPath = typeof b.iconPath === 'string' ? b.iconPath : URI.isUri(b.iconPath) ? b.iconPath.fsPath : (b.iconPath as ThemeIcon).id; return comparePaths(aPath, bPath); } @@ -423,7 +428,7 @@ class SsmResourceGroupImpl implements theia.SourceControlResourceGroup { } takeResourceStateSnapshot(): ScmRawResourceSplice[] { - const snapshot = [...this._resourceStates]; + const snapshot = [...this._resourceStates].sort(compareResourceStates); const diffs = sortedDiff(this.resourceSnapshot, snapshot, compareResourceStates); const splices = diffs.map>(diff => { @@ -432,12 +437,8 @@ class SsmResourceGroupImpl implements theia.SourceControlResourceGroup { this.resourceStatesMap.set(handle, r); const sourceUri = r.resourceUri; - const iconUri = getIconResource(r.decorations); - const lightIconUri = r.decorations && getIconResource(r.decorations.light) || iconUri; - const darkIconUri = r.decorations && getIconResource(r.decorations.dark) || iconUri; - const icons: UriComponents[] = []; - let command: Command | undefined; + let command: Command | undefined; if (r.command) { if (r.command.command === 'theia.open' || r.command.command === 'theia.diff') { const disposables = new DisposableCollection(); @@ -448,13 +449,10 @@ class SsmResourceGroupImpl implements theia.SourceControlResourceGroup { } } - if (lightIconUri) { - icons.push(lightIconUri); - } - - if (darkIconUri && (darkIconUri.toString() !== lightIconUri?.toString())) { - icons.push(darkIconUri); - } + const iconUri = getIconResource(r.decorations); + const lightIconUri = r.decorations && getIconResource(r.decorations.light) || iconUri; + const darkIconUri = r.decorations && getIconResource(r.decorations.dark) || iconUri; + const icons: ScmRawResource['icons'] = [lightIconUri, darkIconUri]; const tooltip = (r.decorations && r.decorations.tooltip) || ''; const strikeThrough = r.decorations && !!r.decorations.strikeThrough; @@ -464,7 +462,7 @@ class SsmResourceGroupImpl implements theia.SourceControlResourceGroup { // TODO remove the letter and colorId fields when the FileDecorationProvider is applied, see https://github.com/eclipse-theia/theia/pull/8911 const rawResource = { // eslint-disable-next-line @typescript-eslint/no-explicit-any - handle, sourceUri, letter: (r as any).letter, colorId: (r as any).color.id, icons, + handle, sourceUri, icons, tooltip, strikeThrough, faded, contextValue, command } as ScmRawResource; diff --git a/packages/plugin/src/theia.d.ts b/packages/plugin/src/theia.d.ts index cd0b39eb88ad1..7e8d76d17a1d8 100644 --- a/packages/plugin/src/theia.d.ts +++ b/packages/plugin/src/theia.d.ts @@ -10710,7 +10710,7 @@ export module '@theia/plugin' { * The icon path for a specific * {@link SourceControlResourceState source control resource state}. */ - readonly iconPath?: string | Uri; + readonly iconPath?: string | Uri | ThemeIcon; } /** diff --git a/packages/scm/src/browser/scm-provider.ts b/packages/scm/src/browser/scm-provider.ts index fc6f391327a13..9c8f0dc70da79 100644 --- a/packages/scm/src/browser/scm-provider.ts +++ b/packages/scm/src/browser/scm-provider.ts @@ -18,6 +18,8 @@ import { Disposable, Event } from '@theia/core/lib/common'; import URI from '@theia/core/lib/common/uri'; +// eslint-disable-next-line import/no-extraneous-dependencies +import { ThemeIcon } from '@theia/monaco-editor-core/esm/vs/platform/theme/common/themeService'; export interface ScmProvider extends Disposable { readonly id: string; @@ -58,10 +60,14 @@ export interface ScmResource { } export interface ScmResourceDecorations { + icon?: URI | ThemeIcon; + iconDark?: URI | ThemeIcon; tooltip?: string; source?: string; letter?: string; color?: string; + strikeThrough?: boolean; + faded?: boolean; } export interface ScmCommand {