Skip to content

Commit 2faa56e

Browse files
author
Akos Kitta
committed
feat: can remove theme from indexedDB
Signed-off-by: Akos Kitta <a.kitta@arduino.cc>
1 parent a49cc52 commit 2faa56e

File tree

3 files changed

+116
-8
lines changed

3 files changed

+116
-8
lines changed

arduino-ide-extension/src/browser/arduino-ide-frontend-module.ts

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -330,7 +330,10 @@ import { WindowTitleUpdater } from './theia/core/window-title-updater';
330330
import { WindowTitleUpdater as TheiaWindowTitleUpdater } from '@theia/core/lib/browser/window/window-title-updater';
331331
import { ThemeServiceWithDB } from './theia/core/theming';
332332
import { ThemeServiceWithDB as TheiaThemeServiceWithDB } from '@theia/monaco/lib/browser/monaco-indexed-db';
333-
import { MonacoThemingService } from './theia/monaco/monaco-theming-service';
333+
import {
334+
MonacoThemingService,
335+
ObsoleteThemesCleanup,
336+
} from './theia/monaco/monaco-theming-service';
334337
import { MonacoThemingService as TheiaMonacoThemingService } from '@theia/monaco/lib/browser/monaco-theming-service';
335338
import { TypeHierarchyServiceProvider } from './theia/typehierarchy/type-hierarchy-service';
336339
import { TypeHierarchyServiceProvider as TheiaTypeHierarchyServiceProvider } from '@theia/typehierarchy/lib/browser/typehierarchy-service';
@@ -986,6 +989,11 @@ export default new ContainerModule((bind, unbind, isBound, rebind) => {
986989
bind(MonacoThemingService).toSelf().inSingletonScope();
987990
rebind(TheiaMonacoThemingService).toService(MonacoThemingService);
988991

992+
// workaround for themes cannot be removed after registration
993+
// https://github.com/eclipse-theia/theia/issues/11151
994+
bind(ObsoleteThemesCleanup).toSelf().inSingletonScope();
995+
bind(FrontendApplicationContribution).toService(ObsoleteThemesCleanup);
996+
989997
// disable type-hierarchy support
990998
// https://github.com/eclipse-theia/theia/commit/16c88a584bac37f5cf3cc5eb92ffdaa541bda5be
991999
bind(TypeHierarchyServiceProvider).toSelf().inSingletonScope();

arduino-ide-extension/src/browser/theia/core/theming.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ export namespace ArduinoThemes {
2222
};
2323
}
2424

25-
const builtInThemeIds = new Set(
25+
export const builtInThemeIds = new Set(
2626
[
2727
ArduinoThemes.Light,
2828
ArduinoThemes.Dark,
@@ -43,7 +43,7 @@ export const contributedThemeLabel = nls.localize(
4343
@injectable()
4444
export class ThemeServiceWithDB extends TheiaThemeServiceWithDB {
4545
protected override init(): void {
46-
this.register(ArduinoThemes.Light, ArduinoThemes.Dark);
46+
// this.register(ArduinoThemes.Light, ArduinoThemes.Dark); // TODO: check if needed
4747
super.init();
4848
}
4949
}

arduino-ide-extension/src/browser/theia/monaco/monaco-theming-service.ts

Lines changed: 105 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,23 @@
1-
import { injectable } from '@theia/core/shared/inversify';
2-
import { MonacoThemingService as TheiaMonacoThemingService } from '@theia/monaco/lib/browser/monaco-theming-service';
3-
import { ArduinoThemes } from '../core/theming';
1+
import { FrontendApplicationContribution } from '@theia/core/lib/browser/frontend-application';
2+
import { BuiltinThemeProvider } from '@theia/core/lib/browser/theming';
3+
import { DisposableCollection } from '@theia/core/lib/common/disposable';
4+
import URI from '@theia/core/lib/common/uri';
5+
import { inject, injectable } from '@theia/core/shared/inversify';
6+
import {
7+
deleteTheme as deleteThemeFromIndexedDB,
8+
getThemes as getThemesFromIndexedDB,
9+
} from '@theia/monaco/lib/browser/monaco-indexed-db';
10+
import {
11+
MonacoTheme,
12+
MonacoThemingService as TheiaMonacoThemingService,
13+
} from '@theia/monaco/lib/browser/monaco-theming-service';
14+
import { HostedPluginSupport } from '@theia/plugin-ext/lib/hosted/browser/hosted-plugin';
15+
import { ArduinoThemes, builtInThemeIds } from '../core/theming';
416

517
@injectable()
618
export class MonacoThemingService extends TheiaMonacoThemingService {
19+
private readonly _pluginContributedThemeIds = new Set<string>();
20+
721
protected override restore(): Promise<void> {
822
const { Light, Dark } = ArduinoThemes;
923
this.registerParsedTheme({
@@ -19,9 +33,95 @@ export class MonacoThemingService extends TheiaMonacoThemingService {
1933
json: require('../../../../src/browser/data/dark.color-theme.json'),
2034
});
2135
// The custom theme registration must happen before restoring the themes.
22-
// Otherwise, the theme content change is not picked up by Theia.
23-
// There is a indexedDB getAll before the DB put.
36+
// Otherwise, theme changes are not picked up.
2437
// https://github.com/arduino/arduino-ide/issues/1251#issuecomment-1436737702
2538
return super.restore();
2639
}
40+
41+
// Customized to populate `_pluginContributedThemeIds`. The rest of the code is vanilla Theia.
42+
protected override async doRegister(
43+
theme: MonacoTheme,
44+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
45+
pending: { [uri: string]: Promise<any> },
46+
toDispose: DisposableCollection
47+
): Promise<void> {
48+
try {
49+
const includes = {};
50+
const json = await this.loadTheme(
51+
theme.uri,
52+
includes,
53+
pending,
54+
toDispose
55+
);
56+
if (toDispose.disposed) {
57+
return;
58+
}
59+
const label = theme.label || new URI(theme.uri).path.base;
60+
const { id, description, uiTheme } = theme;
61+
toDispose.push(
62+
this.registerParsedTheme({
63+
id,
64+
label,
65+
description,
66+
uiTheme: uiTheme,
67+
json,
68+
includes,
69+
})
70+
);
71+
// This implementation depends on how Theia internally works.
72+
// Collect all theme IDs contributed by VSIXs.
73+
// When all VISXs are loaded, IDE2 checks the indexedDB for registered themes,
74+
// and if there are obsolete ones, deletes them. A theme is obsolete if it was
75+
// in the DB but was not loaded from a VSIX during the startup.
76+
// See https://github.com/eclipse-theia/theia/issues/11151.
77+
if (new URI(theme.uri).scheme === 'file') {
78+
this._pluginContributedThemeIds.add(theme.id ?? label);
79+
}
80+
} catch (e) {
81+
console.error('Failed to load theme from ' + theme.uri, e);
82+
}
83+
}
84+
85+
get pluginContributedThemeIds(): string[] {
86+
return Array.from(this._pluginContributedThemeIds.values());
87+
}
88+
}
89+
90+
const compiledThemeIds = new Set([
91+
...builtInThemeIds.values(),
92+
BuiltinThemeProvider.lightTheme,
93+
BuiltinThemeProvider.darkTheme,
94+
]);
95+
96+
/**
97+
* Workaround for removing VSIX themes from the indexedDB if they do not load during app startup.
98+
* This logic cannot be in MonacoThemingService due to a cycle in the DI object graph.
99+
*/
100+
@injectable()
101+
export class ObsoleteThemesCleanup implements FrontendApplicationContribution {
102+
@inject(HostedPluginSupport)
103+
private readonly hostedPlugin: HostedPluginSupport;
104+
@inject(MonacoThemingService)
105+
private readonly monacoTheme: MonacoThemingService;
106+
107+
onStart(): void {
108+
this.hostedPlugin.didStart.then(() => this.cleanObsoleteThemes());
109+
}
110+
111+
private async cleanObsoleteThemes(): Promise<void> {
112+
const pluginContributedThemes = this.monacoTheme.pluginContributedThemeIds;
113+
const persistedThemes = await getThemesFromIndexedDB();
114+
// if neither registered by code (e.g. webpack load such as the Arduino Theme) or VSIX, remove from the indexedDB.
115+
const obsoleteThemes = persistedThemes.filter(
116+
({ id }) =>
117+
!pluginContributedThemes.includes(id) && !compiledThemeIds.has(id)
118+
);
119+
if (!obsoleteThemes.length) {
120+
return;
121+
}
122+
await obsoleteThemes.reduce(async (previousTask, theme) => {
123+
await previousTask;
124+
return deleteThemeFromIndexedDB(theme.id);
125+
}, Promise.resolve());
126+
}
27127
}

0 commit comments

Comments
 (0)