Skip to content

Commit 8ba6bc5

Browse files
committed
Add standalone editor API for theme customization
1 parent ed5613d commit 8ba6bc5

6 files changed

Lines changed: 120 additions & 26 deletions

File tree

build/monaco/monaco.d.ts.recipe

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,8 @@ declare module monaco {
5454
declare module monaco.editor {
5555

5656
#includeAll(vs/editor/browser/standalone/standaloneEditor;modes.=>languages.;editorCommon.=>):
57+
#include(vs/editor/common/services/standaloneColorService): BuiltinTheme, ITheme
58+
#include(vs/editor/common/modes/supports/tokenization): IThemeRule
5759
#include(vs/editor/common/services/webWorker): MonacoWebWorker, IWebWorkerOptions
5860
#include(vs/editor/browser/standalone/standaloneCodeEditor): IEditorConstructionOptions, IDiffEditorConstructionOptions, IStandaloneCodeEditor, IStandaloneDiffEditor
5961
export interface ICommandHandler {

src/vs/editor/browser/services/standaloneColorServiceImpl.ts

Lines changed: 71 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -5,22 +5,60 @@
55
'use strict';
66

77
import { Theme, IThemeRule } from 'vs/editor/common/modes/supports/tokenization';
8-
import { IStandaloneColorService } from 'vs/editor/common/services/standaloneColorService';
8+
import { IStandaloneColorService, BuiltinTheme, ITheme } from 'vs/editor/common/services/standaloneColorService';
99
import { vs, vs_dark, hc_black } from 'vs/editor/common/standalone/themes';
1010
import * as dom from 'vs/base/browser/dom';
1111
import { TokenizationRegistry } from 'vs/editor/common/modes';
1212

13+
class KnownTheme {
14+
cssClassName: string;
15+
rules: IThemeRule[];
16+
17+
constructor(cssClassName: string, rules: IThemeRule[]) {
18+
this.cssClassName = cssClassName;
19+
this.rules = rules;
20+
}
21+
}
22+
23+
const VS_THEME_NAME = 'vs';
24+
const VS_DARK_THEME_NAME = 'vs-dark';
25+
const HC_BLACK_THEME_NAME = 'hc-black';
26+
27+
function isBuiltinTheme(themeName: string): themeName is BuiltinTheme {
28+
return (
29+
themeName === VS_THEME_NAME
30+
|| themeName === VS_DARK_THEME_NAME
31+
|| themeName === HC_BLACK_THEME_NAME
32+
);
33+
}
34+
35+
function getBuiltinRules(builtinTheme: BuiltinTheme): IThemeRule[] {
36+
switch (builtinTheme) {
37+
case VS_THEME_NAME:
38+
return vs;
39+
case VS_DARK_THEME_NAME:
40+
return vs_dark;
41+
case HC_BLACK_THEME_NAME:
42+
return hc_black;
43+
}
44+
}
45+
1346
export class StandaloneColorServiceImpl implements IStandaloneColorService {
1447

1548
_serviceBrand: any;
1649

17-
private _theme: Theme;
50+
private _knownThemes: Map<string, KnownTheme>;
1851
private _styleElement: HTMLStyleElement;
52+
private _theme: Theme;
1953

2054
constructor() {
55+
this._knownThemes = new Map<string, KnownTheme>();
56+
this._knownThemes.set(VS_THEME_NAME, new KnownTheme(VS_THEME_NAME, getBuiltinRules(VS_THEME_NAME)));
57+
this._knownThemes.set(VS_DARK_THEME_NAME, new KnownTheme(VS_DARK_THEME_NAME, getBuiltinRules(VS_DARK_THEME_NAME)));
58+
this._knownThemes.set(HC_BLACK_THEME_NAME, new KnownTheme(HC_BLACK_THEME_NAME, getBuiltinRules(HC_BLACK_THEME_NAME)));
2159
this._styleElement = dom.createStyleSheet();
2260
this._styleElement.className = 'monaco-tokens-styles';
23-
this.setTheme('vs');
61+
this.setTheme(VS_THEME_NAME);
2462
}
2563

2664
private static _generateCSS(colorMap: string[]): string {
@@ -35,30 +73,45 @@ export class StandaloneColorServiceImpl implements IStandaloneColorService {
3573
return rules.join('\n');
3674
}
3775

76+
public defineTheme(themeName: string, themeData: ITheme): void {
77+
if (!/^[a-z0-9\-]+$/i.test(themeName) || isBuiltinTheme(themeName)) {
78+
throw new Error('Illegal theme name!');
79+
}
80+
if (!isBuiltinTheme(themeData.base)) {
81+
throw new Error('Illegal theme base!');
82+
}
83+
84+
let cssClassName = themeData.base + ' ' + themeName;
85+
86+
let rules: IThemeRule[] = [];
87+
if (themeData.inherit) {
88+
rules = rules.concat(getBuiltinRules(themeData.base));
89+
}
90+
rules = rules.concat(themeData.rules);
91+
92+
this._knownThemes.set(themeName, new KnownTheme(cssClassName, rules));
93+
}
94+
3895
public getTheme(): Theme {
3996
return this._theme;
4097
}
4198

42-
public setTheme(themeName: string): void {
43-
let themeRules: IThemeRule[] = null;
44-
switch (themeName) {
45-
case 'vs':
46-
themeRules = vs;
47-
break;
48-
case 'vs-dark':
49-
themeRules = vs_dark;
50-
break;
51-
case 'hc-black':
52-
themeRules = hc_black;
53-
break;
54-
default:
55-
themeRules = [];
99+
public setTheme(themeName: string): string {
100+
let themeData: KnownTheme;
101+
if (this._knownThemes.has(themeName)) {
102+
themeData = this._knownThemes.get(themeName);
103+
} else {
104+
themeData = this._knownThemes.get(VS_THEME_NAME);
56105
}
57-
this._theme = Theme.createFromRawTheme(themeRules);
106+
107+
108+
this._theme = Theme.createFromRawTheme(themeData.rules);
58109
let colorMap = this._theme.getColorMap();
59110
let cssRules = StandaloneColorServiceImpl._generateCSS(colorMap);
60111
this._styleElement.innerHTML = cssRules;
61112

62113
TokenizationRegistry.setColorMap(colorMap);
114+
115+
return themeData.cssClassName;
63116
}
64117
}

src/vs/editor/browser/standalone/standaloneCodeEditor.ts

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,9 @@ export class StandaloneEditor extends CodeEditor implements IStandaloneCodeEdito
7676
@IStandaloneColorService standaloneColorService: IStandaloneColorService
7777
) {
7878
options = options || {};
79+
if (typeof options.theme === 'string') {
80+
options.theme = standaloneColorService.setTheme(options.theme);
81+
}
7982
super(domElement, options, instantiationService, codeEditorService, commandService, contextKeyService);
8083
this._standaloneColorService = standaloneColorService;
8184

@@ -116,12 +119,10 @@ export class StandaloneEditor extends CodeEditor implements IStandaloneCodeEdito
116119
}
117120

118121
public updateOptions(newOptions: IEditorOptions): void {
119-
let oldTheme = this._configuration.editor.viewInfo.theme;
120-
super.updateOptions(newOptions);
121-
let newTheme = this._configuration.editor.viewInfo.theme;
122-
if (oldTheme !== newTheme) {
123-
this._standaloneColorService.setTheme(newTheme);
122+
if (typeof newOptions.theme === 'string') {
123+
newOptions.theme = this._standaloneColorService.setTheme(newOptions.theme);
124124
}
125+
super.updateOptions(newOptions);
125126
}
126127

127128
public addCommand(keybinding: number, handler: ICommandHandler, context: string): string {

src/vs/editor/browser/standalone/standaloneEditor.ts

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ import { ICodeEditorService } from 'vs/editor/common/services/codeEditorService'
3131
import { IEditorWorkerService } from 'vs/editor/common/services/editorWorkerService';
3232
import { ITextModelResolverService } from 'vs/editor/common/services/resolverService';
3333
import { NULL_STATE, nullTokenize } from 'vs/editor/common/modes/nullMode';
34-
import { IStandaloneColorService } from 'vs/editor/common/services/standaloneColorService';
34+
import { ITheme, IStandaloneColorService } from 'vs/editor/common/services/standaloneColorService';
3535
import { Token } from 'vs/editor/common/core/token';
3636

3737
/**
@@ -283,6 +283,13 @@ export function tokenize(text: string, languageId: string): Token[][] {
283283
return result;
284284
}
285285

286+
/**
287+
* Define a new theme.
288+
*/
289+
export function defineTheme(themeName: string, themeData: ITheme): void {
290+
StaticServices.standaloneColorService.get().defineTheme(themeName, themeData);
291+
}
292+
286293
/**
287294
* @internal
288295
*/
@@ -308,6 +315,7 @@ export function createMonacoEditorAPI(): typeof monaco.editor {
308315
colorize: colorize,
309316
colorizeModelLine: colorizeModelLine,
310317
tokenize: tokenize,
318+
defineTheme: defineTheme,
311319

312320
// enums
313321
ScrollbarVisibility: ScrollbarVisibility,

src/vs/editor/common/services/standaloneColorService.ts

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,14 +5,24 @@
55
'use strict';
66

77
import { createDecorator } from 'vs/platform/instantiation/common/instantiation';
8-
import { Theme } from 'vs/editor/common/modes/supports/tokenization';
8+
import { Theme, IThemeRule } from 'vs/editor/common/modes/supports/tokenization';
99

1010
export var IStandaloneColorService = createDecorator<IStandaloneColorService>('standaloneColorService');
1111

12+
export type BuiltinTheme = 'vs' | 'vs-dark' | 'hc-black';
13+
14+
export interface ITheme {
15+
base: BuiltinTheme;
16+
inherit: boolean;
17+
rules: IThemeRule[];
18+
}
19+
1220
export interface IStandaloneColorService {
1321
_serviceBrand: any;
1422

15-
setTheme(themeName: string): void;
23+
setTheme(themeName: string): string;
24+
25+
defineTheme(themeName: string, themeData: ITheme): void;
1626

1727
getTheme(): Theme;
1828
}

src/vs/monaco.d.ts

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -867,6 +867,26 @@ declare module monaco.editor {
867867
*/
868868
export function tokenize(text: string, languageId: string): Token[][];
869869

870+
/**
871+
* Define a new theme.
872+
*/
873+
export function defineTheme(themeName: string, themeData: ITheme): void;
874+
875+
export type BuiltinTheme = 'vs' | 'vs-dark' | 'hc-black';
876+
877+
export interface ITheme {
878+
base: BuiltinTheme;
879+
inherit: boolean;
880+
rules: IThemeRule[];
881+
}
882+
883+
export interface IThemeRule {
884+
token: string;
885+
foreground?: string;
886+
background?: string;
887+
fontStyle?: string;
888+
}
889+
870890
/**
871891
* A web worker that can provide a proxy to an arbitrary file.
872892
*/

0 commit comments

Comments
 (0)