Skip to content

Commit

Permalink
[monaco] load themes from tmTheme files
Browse files Browse the repository at this point in the history
Signed-off-by: Anton Kosyakov <anton.kosyakov@typefox.io>
  • Loading branch information
akosyakov committed Nov 1, 2019
1 parent e41eb63 commit e7ee215
Show file tree
Hide file tree
Showing 5 changed files with 42 additions and 19 deletions.
1 change: 1 addition & 0 deletions packages/monaco/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
"@theia/outline-view": "^0.11.0",
"@theia/workspace": "^0.11.0",
"deepmerge": "2.0.1",
"fast-plist": "^0.1.2",
"jsonc-parser": "^2.0.2",
"monaco-css": "^2.5.0",
"monaco-html": "^2.5.2",
Expand Down
52 changes: 37 additions & 15 deletions packages/monaco/src/browser/monaco-theming-service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@

import { injectable, inject } from 'inversify';
import * as jsoncparser from 'jsonc-parser';
import * as plistparser from 'fast-plist';
import { ThemeService, BuiltinThemeProvider } from '@theia/core/lib/browser/theming';
import URI from '@theia/core/lib/common/uri';
import { Disposable, DisposableCollection } from '@theia/core/lib/common/disposable';
Expand All @@ -41,23 +42,19 @@ export class MonacoThemingService {
protected readonly fileSystem: FileSystem;

// tslint:disable-next-line:no-any
register(theme: MonacoTheme, pendingIncludes: { [uri: string]: Promise<any> } = {}): Disposable {
register(theme: MonacoTheme, pending: { [uri: string]: Promise<any> } = {}): Disposable {
const toDispose = new DisposableCollection(Disposable.create(() => { /* mark as not disposed */ }));
this.doRegister(theme, pendingIncludes, toDispose);
this.doRegister(theme, pending, toDispose);
return toDispose;
}

protected async doRegister(theme: MonacoTheme,
pendingIncludes: { [uri: string]: Promise<any> },
pending: { [uri: string]: Promise<any> },
toDispose: DisposableCollection
): Promise<void> {
try {
if (new URI(theme.uri).path.ext !== '.json') {
console.error('Unknown theme file: ' + theme.uri);
return;
}
const includes = {};
const json = await this.loadTheme(theme.uri, includes, pendingIncludes, toDispose);
const json = await this.loadTheme(theme.uri, includes, pending, toDispose);
if (toDispose.disposed) {
return;
}
Expand All @@ -75,28 +72,53 @@ export class MonacoThemingService {
protected async loadTheme(
uri: string,
includes: { [include: string]: any },
pendingIncludes: { [uri: string]: Promise<any> },
pending: { [uri: string]: Promise<any> },
toDispose: DisposableCollection
): Promise<any> {
// tslint:enabled:no-any
const { content } = await this.fileSystem.resolveContent(uri);
if (toDispose.disposed) {
return undefined;
return;
}
const themeUri = new URI(uri);
if (themeUri.path.ext !== '.json') {
const value = plistparser.parse(content);
if (value && 'settings' in value && Array.isArray(value.settings)) {
return { tokenColors: value.settings };
}
throw new Error(`Problem parsing tmTheme file: ${uri}. 'settings' is not array.`);
}
const json = jsoncparser.parse(content, undefined, { disallowComments: false });
if (json.include) {
const includeUri = new URI(uri).parent.resolve(json.include).toString();
if (!pendingIncludes[includeUri]) {
pendingIncludes[includeUri] = this.loadTheme(includeUri, includes, pendingIncludes, toDispose);
if ('tokenColors' in json && typeof json.tokenColors === 'string') {
const value = await this.doLoadTheme(themeUri, json.tokenColors, includes, pending, toDispose);
if (toDispose.disposed) {
return;
}
includes[json.include] = await pendingIncludes[includeUri];
json.tokenColors = value.tokenColors;
}
if (json.include) {
includes[json.include] = await this.doLoadTheme(themeUri, json.include, includes, pending, toDispose);
if (toDispose.disposed) {
return;
}
}
return json;
}

protected doLoadTheme(
themeUri: URI,
referencedPath: string,
includes: { [include: string]: any },
pending: { [uri: string]: Promise<any> },
toDispose: DisposableCollection
): Promise<any> {
const referencedUri = themeUri.parent.resolve(referencedPath).toString();
if (!pending[referencedUri]) {
pending[referencedUri] = this.loadTheme(referencedUri, includes, pending, toDispose);
}
return pending[referencedUri];
}

static init(): void {
ThemeService.get().onThemeChange(e =>
MonacoThemingService.store(MonacoThemingService.monacoThemes.get(e.newTheme.id))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -91,8 +91,7 @@ export class MonacoThemeRegistry {
if (typeof tokenColor.scope === 'undefined') {
tokenColor.scope = [''];
} else if (typeof tokenColor.scope === 'string') {
// tokenColor.scope = tokenColor.scope.split(',').map((scope: string) => scope.trim()); // ?
tokenColor.scope = [tokenColor.scope];
tokenColor.scope = tokenColor.scope.split(',').map((scope: string) => scope.trim());
}

for (const scope of tokenColor.scope) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -239,9 +239,9 @@ export class PluginContributionHandler {
}

if (contributions.themes && contributions.themes.length) {
const includes = {};
const pending = {};
for (const theme of contributions.themes) {
pushContribution(`themes.${theme.uri}`, () => this.monacoThemingService.register(theme, includes));
pushContribution(`themes.${theme.uri}`, () => this.monacoThemingService.register(theme, pending));
}
}

Expand Down
1 change: 1 addition & 0 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -4755,6 +4755,7 @@ fast-levenshtein@~2.0.4:
fast-plist@^0.1.2:
version "0.1.2"
resolved "https://registry.yarnpkg.com/fast-plist/-/fast-plist-0.1.2.tgz#a45aff345196006d406ca6cdcd05f69051ef35b8"
integrity sha1-pFr/NFGWAG1AbKbNzQX2kFHvNbg=

fast-safe-stringify@^2.0.4:
version "2.0.6"
Expand Down

0 comments on commit e7ee215

Please sign in to comment.