Skip to content

Commit dbce60b

Browse files
committed
1 parent ebf55c1 commit dbce60b

5 files changed

Lines changed: 157 additions & 27 deletions

File tree

src/vs/workbench/contrib/extensions/electron-browser/extensionEditor.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ import { IExtensionsWorkbenchService, IExtensionsViewlet, VIEWLET_ID, IExtension
2828
import { RatingsWidget, InstallCountWidget, RemoteBadgeWidget } from 'vs/workbench/contrib/extensions/electron-browser/extensionsWidgets';
2929
import { EditorOptions } from 'vs/workbench/common/editor';
3030
import { ActionBar } from 'vs/base/browser/ui/actionbar/actionbar';
31-
import { CombinedInstallAction, UpdateAction, ExtensionEditorDropDownAction, ReloadAction, MaliciousStatusLabelAction, IgnoreExtensionRecommendationAction, UndoIgnoreExtensionRecommendationAction, EnableDropDownAction, DisableDropDownAction, StatusLabelAction } from 'vs/workbench/contrib/extensions/electron-browser/extensionsActions';
31+
import { CombinedInstallAction, UpdateAction, ExtensionEditorDropDownAction, ReloadAction, MaliciousStatusLabelAction, IgnoreExtensionRecommendationAction, UndoIgnoreExtensionRecommendationAction, EnableDropDownAction, DisableDropDownAction, StatusLabelAction, SetFileIconThemeAction, SetColorThemeAction } from 'vs/workbench/contrib/extensions/electron-browser/extensionsActions';
3232
import { WebviewElement } from 'vs/workbench/contrib/webview/electron-browser/webviewElement';
3333
import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding';
3434
import { DomScrollableElement } from 'vs/base/browser/ui/scrollbar/scrollableElement';
@@ -367,6 +367,8 @@ export class ExtensionEditor extends BaseEditor {
367367
reloadAction,
368368
this.instantiationService.createInstance(StatusLabelAction),
369369
this.instantiationService.createInstance(UpdateAction),
370+
this.instantiationService.createInstance(SetColorThemeAction),
371+
this.instantiationService.createInstance(SetFileIconThemeAction),
370372
this.instantiationService.createInstance(EnableDropDownAction),
371373
this.instantiationService.createInstance(DisableDropDownAction, runningExtensions),
372374
this.instantiationService.createInstance(CombinedInstallAction),

src/vs/workbench/contrib/extensions/electron-browser/extensionsActions.ts

Lines changed: 149 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ import { clipboard } from 'electron';
5555
import { IPartService } from 'vs/workbench/services/part/common/partService';
5656
import { alert } from 'vs/base/browser/ui/aria/aria';
5757
import { coalesce } from 'vs/base/common/arrays';
58-
import { IWorkbenchThemeService } from 'vs/workbench/services/themes/common/workbenchThemeService';
58+
import { IWorkbenchThemeService, COLOR_THEME_SETTING } from 'vs/workbench/services/themes/common/workbenchThemeService';
5959

6060
function toExtensionDescription(local: ILocalExtension): IExtensionDescription {
6161
return {
@@ -147,7 +147,6 @@ export class InstallAction extends ExtensionAction {
147147
@IInstantiationService private readonly instantiationService: IInstantiationService,
148148
@INotificationService private readonly notificationService: INotificationService,
149149
@IOpenerService private readonly openerService: IOpenerService,
150-
@IQuickInputService private readonly quickInputService: IQuickInputService,
151150
@IExtensionService private readonly runtimeExtensionService: IExtensionService,
152151
@IWorkbenchThemeService private readonly workbenchThemeService: IWorkbenchThemeService
153152
) {
@@ -183,8 +182,22 @@ export class InstallAction extends ExtensionAction {
183182

184183
const extension = await this.install(this.extension);
185184

186-
if (extension.local && extension.local.manifest.contributes && extension.local.manifest.contributes.themes && extension.local.manifest.contributes.themes.length) {
187-
return this.applyInstalledTheme(extension.local);
185+
if (extension.local) {
186+
const runningExtension = await this.getRunningExtension(extension.local);
187+
if (runningExtension) {
188+
const colorThemes = await this.workbenchThemeService.getColorThemes(runningExtension.identifier);
189+
const fileIconThemes = await this.workbenchThemeService.getFileIconThemes(runningExtension.identifier);
190+
if (colorThemes.length && !fileIconThemes.length) {
191+
const action = this.instantiationService.createInstance(SetColorThemeAction);
192+
action.extension = extension;
193+
return action.run(true);
194+
}
195+
if (!colorThemes.length && fileIconThemes.length) {
196+
const action = this.instantiationService.createInstance(SetFileIconThemeAction);
197+
action.extension = extension;
198+
return action.run(true);
199+
}
200+
}
188201
}
189202

190203
}
@@ -202,25 +215,6 @@ export class InstallAction extends ExtensionAction {
202215
});
203216
}
204217

205-
private async applyInstalledTheme(extension: ILocalExtension): Promise<void> {
206-
const runningExtension = await this.getRunningExtension(extension);
207-
if (runningExtension) {
208-
const currentTheme = this.workbenchThemeService.getColorTheme();
209-
const themes = await this.workbenchThemeService.getColorThemes(runningExtension.identifier);
210-
const delayer = new Delayer<void>(100);
211-
const picks: (IQuickPickItem | IQuickPickSeparator)[] = themes.map(theme => (<IQuickPickItem>{ label: theme.label, id: theme.id }));
212-
picks.push(<IQuickPickSeparator>{ type: 'separator' });
213-
picks.push(<IQuickPickItem>{ label: localize('stay with current theme', "Stay with current theme ({0})", currentTheme.label), id: currentTheme.id });
214-
const pickedTheme = await this.quickInputService.pick(
215-
picks,
216-
{
217-
placeHolder: localize('apply installed theme', "Apply installed theme or press Escape to cancel."),
218-
onDidFocus: item => delayer.trigger(() => this.workbenchThemeService.setColorTheme(item.id, ConfigurationTarget.MEMORY).then(() => undefined))
219-
});
220-
this.workbenchThemeService.setColorTheme(pickedTheme ? pickedTheme.id : currentTheme.id, undefined);
221-
}
222-
}
223-
224218
private async getRunningExtension(extension: ILocalExtension): Promise<IExtensionDescription | null> {
225219
const runningExtension = await this.runtimeExtensionService.getExtension(extension.identifier.id);
226220
if (runningExtension) {
@@ -1111,6 +1105,138 @@ export class ReloadAction extends ExtensionAction {
11111105
}
11121106
}
11131107

1108+
export class SetColorThemeAction extends ExtensionAction {
1109+
1110+
private static readonly EnabledClass = 'extension-action theme';
1111+
private static readonly DisabledClass = `${SetColorThemeAction.EnabledClass} disabled`;
1112+
1113+
private disposables: IDisposable[] = [];
1114+
1115+
constructor(
1116+
@IExtensionService extensionService: IExtensionService,
1117+
@IWorkbenchThemeService private readonly workbenchThemeService: IWorkbenchThemeService,
1118+
@IQuickInputService private readonly quickInputService: IQuickInputService,
1119+
@IConfigurationService private readonly configurationService: IConfigurationService
1120+
) {
1121+
super(`extensions.colorTheme`, localize('color theme', "Set Color Theme"), SetColorThemeAction.DisabledClass, false);
1122+
Event.any<any>(extensionService.onDidChangeExtensions, workbenchThemeService.onDidColorThemeChange)(() => this.update(), this, this.disposables);
1123+
this.update();
1124+
}
1125+
1126+
async update(): Promise<void> {
1127+
this.enabled = false;
1128+
if (this.extension) {
1129+
const isInstalled = this.extension.state === ExtensionState.Installed;
1130+
if (isInstalled) {
1131+
const colorThemes = await this.workbenchThemeService.getColorThemes(new ExtensionIdentifier(this.extension.identifier.id));
1132+
this.enabled = colorThemes.length > 0;
1133+
}
1134+
}
1135+
this.class = this.enabled ? SetColorThemeAction.EnabledClass : SetColorThemeAction.DisabledClass;
1136+
}
1137+
1138+
async run(showCurrentTheme: boolean): Promise<any> {
1139+
await this.update();
1140+
if (!this.enabled) {
1141+
return;
1142+
}
1143+
let colorThemes = await this.workbenchThemeService.getColorThemes(new ExtensionIdentifier(this.extension.identifier.id));
1144+
const currentTheme = this.workbenchThemeService.getColorTheme();
1145+
showCurrentTheme = showCurrentTheme || colorThemes.some(t => t.id === currentTheme.id);
1146+
if (showCurrentTheme) {
1147+
colorThemes = colorThemes.filter(t => t.id !== currentTheme.id);
1148+
}
1149+
1150+
const delayer = new Delayer<any>(100);
1151+
const picks: (IQuickPickItem | IQuickPickSeparator)[] = [];
1152+
picks.push(...colorThemes.map(theme => (<IQuickPickItem>{ label: theme.label, id: theme.id })));
1153+
if (showCurrentTheme) {
1154+
picks.push(<IQuickPickSeparator>{ type: 'separator', label: localize('current', "Current") });
1155+
picks.push(<IQuickPickItem>{ label: currentTheme.label, id: currentTheme.id });
1156+
}
1157+
const pickedTheme = await this.quickInputService.pick(
1158+
picks,
1159+
{
1160+
placeHolder: localize('select color theme', "Select Color Theme"),
1161+
onDidFocus: item => delayer.trigger(() => this.workbenchThemeService.setColorTheme(item.id, undefined))
1162+
});
1163+
let confValue = this.configurationService.inspect(COLOR_THEME_SETTING);
1164+
const target = typeof confValue.workspace !== 'undefined' ? ConfigurationTarget.WORKSPACE : ConfigurationTarget.USER;
1165+
return this.workbenchThemeService.setColorTheme(pickedTheme ? pickedTheme.id : currentTheme.id, target);
1166+
}
1167+
1168+
dispose() {
1169+
this.disposables = dispose(this.disposables);
1170+
super.dispose();
1171+
}
1172+
}
1173+
1174+
export class SetFileIconThemeAction extends ExtensionAction {
1175+
1176+
private static readonly EnabledClass = 'extension-action theme';
1177+
private static readonly DisabledClass = `${SetFileIconThemeAction.EnabledClass} disabled`;
1178+
1179+
private disposables: IDisposable[] = [];
1180+
1181+
constructor(
1182+
@IExtensionService extensionService: IExtensionService,
1183+
@IWorkbenchThemeService private readonly workbenchThemeService: IWorkbenchThemeService,
1184+
@IQuickInputService private readonly quickInputService: IQuickInputService,
1185+
@IConfigurationService private readonly configurationService: IConfigurationService
1186+
) {
1187+
super(`extensions.fileIconTheme`, localize('file icon theme', "Set File Icon Theme"), SetFileIconThemeAction.DisabledClass, false);
1188+
Event.any<any>(extensionService.onDidChangeExtensions, workbenchThemeService.onDidFileIconThemeChange)(() => this.update(), this, this.disposables);
1189+
this.update();
1190+
}
1191+
1192+
async update(): Promise<void> {
1193+
this.enabled = false;
1194+
if (this.extension) {
1195+
const isInstalled = this.extension.state === ExtensionState.Installed;
1196+
if (isInstalled) {
1197+
const fileIconThemes = await this.workbenchThemeService.getFileIconThemes(new ExtensionIdentifier(this.extension.identifier.id));
1198+
this.enabled = fileIconThemes.length > 0;
1199+
}
1200+
}
1201+
this.class = this.enabled ? SetFileIconThemeAction.EnabledClass : SetFileIconThemeAction.DisabledClass;
1202+
}
1203+
1204+
async run(showCurrentTheme: boolean): Promise<any> {
1205+
await this.update();
1206+
if (!this.enabled) {
1207+
return;
1208+
}
1209+
let fileIconThemes = await this.workbenchThemeService.getFileIconThemes(new ExtensionIdentifier(this.extension.identifier.id));
1210+
const currentTheme = this.workbenchThemeService.getFileIconTheme();
1211+
showCurrentTheme = showCurrentTheme || fileIconThemes.some(t => t.id === currentTheme.id);
1212+
if (showCurrentTheme) {
1213+
fileIconThemes = fileIconThemes.filter(t => t.id !== currentTheme.id);
1214+
}
1215+
1216+
const delayer = new Delayer<any>(100);
1217+
const picks: (IQuickPickItem | IQuickPickSeparator)[] = [];
1218+
picks.push(...fileIconThemes.map(theme => (<IQuickPickItem>{ label: theme.label, id: theme.id })));
1219+
if (showCurrentTheme) {
1220+
picks.push(<IQuickPickSeparator>{ type: 'separator', label: localize('current', "Current") });
1221+
picks.push(<IQuickPickItem>{ label: currentTheme.label, id: currentTheme.id });
1222+
}
1223+
const pickedTheme = await this.quickInputService.pick(
1224+
picks,
1225+
{
1226+
placeHolder: localize('select file icon theme', "Select File Icon Theme"),
1227+
onDidFocus: item => delayer.trigger(() => this.workbenchThemeService.setFileIconTheme(item.id, undefined))
1228+
});
1229+
let confValue = this.configurationService.inspect(COLOR_THEME_SETTING);
1230+
const target = typeof confValue.workspace !== 'undefined' ? ConfigurationTarget.WORKSPACE : ConfigurationTarget.USER;
1231+
return this.workbenchThemeService.setFileIconTheme(pickedTheme ? pickedTheme.id : currentTheme.id, target);
1232+
}
1233+
1234+
dispose() {
1235+
this.disposables = dispose(this.disposables);
1236+
super.dispose();
1237+
}
1238+
}
1239+
11141240
export class OpenExtensionsViewletAction extends ShowViewletAction {
11151241

11161242
static ID = VIEWLET_ID;

src/vs/workbench/contrib/extensions/electron-browser/media/extensionActions.css

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131
.monaco-action-bar .action-item.disabled .action-label.extension-action.install:not(.installing),
3232
.monaco-action-bar .action-item.disabled .action-label.extension-action.uninstall:not(.uninstalling),
3333
.monaco-action-bar .action-item.disabled .action-label.extension-action.update,
34+
.monaco-action-bar .action-item.disabled .action-label.extension-action.theme,
3435
.monaco-action-bar .action-item.disabled .action-label.extension-action.extension-editor-dropdown-action,
3536
.monaco-action-bar .action-item.disabled .action-label.extension-action.reload,
3637
.monaco-action-bar .action-item.disabled .action-label.disable-status.hide,

src/vs/workbench/services/themes/common/workbenchThemeService.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ export interface IWorkbenchThemeService extends IThemeService {
6161

6262
setFileIconTheme(iconThemeId: string | undefined, settingsTarget: ConfigurationTarget | undefined): Promise<IFileIconTheme>;
6363
getFileIconTheme(): IFileIconTheme;
64-
getFileIconThemes(): Promise<IFileIconTheme[]>;
64+
getFileIconThemes(extensionId?: ExtensionIdentifier): Promise<IFileIconTheme[]>;
6565
onDidFileIconThemeChange: Event<IFileIconTheme>;
6666
}
6767

src/vs/workbench/services/themes/electron-browser/workbenchThemeService.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -460,8 +460,9 @@ export class WorkbenchThemeService implements IWorkbenchThemeService {
460460
}
461461
}
462462

463-
public getFileIconThemes(): Promise<IFileIconTheme[]> {
464-
return this.iconThemeStore.getFileIconThemes();
463+
public async getFileIconThemes(extensionId?: ExtensionIdentifier): Promise<IFileIconTheme[]> {
464+
const filIconThemes = await this.iconThemeStore.getFileIconThemes();
465+
return extensionId ? filIconThemes.filter(c => c.extensionData && ExtensionIdentifier.equals(new ExtensionIdentifier(c.extensionData.extensionId), extensionId)) : filIconThemes;
465466
}
466467

467468
public getFileIconTheme() {

0 commit comments

Comments
 (0)