You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
/** * The default theme. If that is not applicable, returns with the fallback theme. */getdefaultTheme(): Theme{returnthis.themes[FrontendApplicationConfigProvider.get().defaultTheme]||this.themes[ApplicationProps.DEFAULT.frontend.config.defaultTheme];}
// packages/plugin-ext/src/main/browser/plugin-contribution-handler.ts
@injectable()exportclassPluginContributionHandler{
@inject(MonacoThemingService)protectedreadonlymonacoThemingService: MonacoThemingService;
@inject(ColorRegistry)protectedreadonlycolors: ColorRegistry;
@inject(PluginIconThemeService)protectedreadonlyiconThemeService: PluginIconThemeService;/** * Always synchronous in order to simplify handling disconnections. * @throws never, loading of each contribution should handle errors * in order to avoid preventing loading of other contributions or extensions */handleContributions(clientId: string,plugin: DeployedPlugin): Disposable{if(contributions.themes&&contributions.themes.length){constpending={};for(constthemeofcontributions.themes){pushContribution(`themes.${theme.uri}`,()=>this.monacoThemingService.register(theme,pending));}}if(contributions.iconThemes&&contributions.iconThemes.length){for(consticonThemeofcontributions.iconThemes){pushContribution(`iconThemes.${iconTheme.uri}`,()=>this.iconThemeService.register(iconTheme,plugin));}}if(contributions.colors){pushContribution('colors',()=>this.colors.register(...contributions.colors));}}}
// packages/monaco/src/browser/textmate/monaco-theme-registry.tsimport{IRawTheme,Registry,IRawThemeSetting}from'vscode-textmate';
@injectable()exportclassMonacoThemeRegistry{/** * Register VS Code compatible themes */register(json: any,includes?: {[includePath: string]: any},givenName?: string,monacoBase?: monaco.editor.BuiltinTheme): ThemeMix{
const name=givenName||json.name!;constresult: ThemeMix={
name,base: monacoBase||'vs',inherit: true,colors: {},rules: [],settings: []};if(typeofjson.include!=='undefined'){if(!includes||!includes[json.include]){console.error(`Couldn't resolve includes theme ${json.include}.`);}else{constparentTheme=this.register(includes[json.include],includes);Object.assign(result.colors,parentTheme.colors);result.rules.push(...parentTheme.rules);result.settings.push(...parentTheme.settings);}}consttokenColors: Array<IRawThemeSetting>=json.tokenColors;if(Array.isArray(tokenColors)){for(consttokenColoroftokenColors){if(tokenColor.scope&&tokenColor.settings){result.settings.push({scope: tokenColor.scope,settings: {foreground: this.normalizeColor(tokenColor.settings.foreground),background: this.normalizeColor(tokenColor.settings.background),fontStyle: tokenColor.settings.fontStyle}});}}}// colors 处理if(json.colors){Object.assign(result.colors,json.colors);result.encodedTokensColors=Object.keys(result.colors).map(key=>result.colors[key]);}if(monacoBase&&givenName){for(constsettingofresult.settings){this.transform(setting,rule=>result.rules.push(rule));}// the default rule (scope empty) is always the first rule. Ignore all other default rules.constdefaultTheme=monaco.services.StaticServices.standaloneThemeService.get()._knownThemes.get(result.base)!;constforeground=result.colors['editor.foreground']||defaultTheme.getColor('editor.foreground');constbackground=result.colors['editor.background']||defaultTheme.getColor('editor.background');result.settings.unshift({settings: {foreground: this.normalizeColor(foreground),background: this.normalizeColor(background)}});constreg=newRegistry();reg.setTheme(result);// 获取 encodedTokensColorsresult.encodedTokensColors=reg.getColorMap();// index 0 has to be set to null as it is 'undefined' by default, but monaco code expects it to be null// eslint-disable-next-line no-null/no-nullresult.encodedTokensColors[0]=null!;this.setTheme(givenName,result);}returnresult;}setTheme(name: string,data: ThemeMix): void{// monaco auto refreshes a theme with new data
monaco.editor.defineTheme(name,data);}}
ThemeService UI 主题注册
挂载在全局对象中。
// packages/core/src/browser/theming.tsexportclassThemeService{privatethemes: {[id: string]: Theme}={};private activeTheme: Theme|undefined;privatereadonlythemeChange=newEmitter<ThemeChangeEvent>();readonly onThemeChange: Event<ThemeChangeEvent>=this.themeChange.event;// onThemeChange 事件staticget(): ThemeService{constglobal=windowasany;// eslint-disable-line @typescript-eslint/no-explicit-anyreturnglobal[ThemeServiceSymbol]||newThemeService();}register(...themes: Theme[]): Disposable{for(constthemeofthemes){this.themes[theme.id]=theme;}this.validateActiveTheme();returnDisposable.create(()=>{for(constthemeofthemes){deletethis.themes[theme.id];}this.validateActiveTheme();});}/** * The default theme. If that is not applicable, returns with the fallback theme. */getdefaultTheme(): Theme{returnthis.themes[FrontendApplicationConfigProvider.get().defaultTheme]||this.themes[ApplicationProps.DEFAULT.frontend.config.defaultTheme];}}
// packages/terminal/src/browser/terminal-frontend-contribution.tsregisterColors(colors: ColorRegistry): void{colors.register({id: 'terminal.background',defaults: {dark: 'panel.background',light: 'panel.background',hc: 'panel.background'},description: 'The background color of the terminal, this allows coloring the terminal differently to the panel.'});}
ColorRegistry
注册主题颜色的配置。
/** * It should be implemented by an extension, e.g. by the monaco extension. */
@injectable()exportclassColorRegistry{protectedreadonlyonDidChangeEmitter=newEmitter<void>();readonlyonDidChange=this.onDidChangeEmitter.event;protectedfireDidChange(): void{this.onDidChangeEmitter.fire(undefined);}*getColors(): IterableIterator<string>{}getCurrentCssVariable(id: string): ColorCssVariable|undefined{constvalue=this.getCurrentColor(id);if(!value){returnundefined;}constname=this.toCssVariableName(id);return{ name, value };}toCssVariableName(id: string,prefix='theia'): string{// 将配置转换为 CSS Custom Propertyreturn`--${prefix}-${id.replace(/\./g,'-')}`;}getCurrentColor(id: string): string|undefined{returnundefined;}register(...definitions: ColorDefinition[]): Disposable{constresult=newDisposableCollection(...definitions.map(definition=>this.doRegister(definition)));this.fireDidChange();returnresult;}protecteddoRegister(definition: ColorDefinition): Disposable{returnDisposable.NULL;}}
Theming
在 Visual Studio Code 中,主题有三种类型:
从 Contributes Theme 配置来看:
自定义主题
可以参考:Create a new Color Theme
语法高亮
moanco-editor 和 VSCode 的高亮不太一样,比较简陋很不舒服,一番搜索发现 monaco-editor 的语言支持使用的是内置的 Monarch 这个语法高亮支持。
官方的解释 Why doesn't the editor support TextMate grammars?
主要就是因为 Textmate 语法解析依赖的 Oniguruma 是一个 C 语言下的解析功能,VSCode 可以使用 node 环境来调用原生的模块,但是在 web 环境下无法实现,即使通过 asm.js 转换后,性能依然会有 100-1000 倍的损失(16年9月的说明),而且 IE 不支持。
monaco-editor 语言的支持也只有通过 worker 的 js ts html css json 这些。但是业内更通用、生态更丰富的是 Textmate,包括 VSCode 也是用的 Textmate。
Theia 将
monaco-editor
,vscode-oniguruma
andvscode-textmate
整合到一起,在 Editor 中获取 TM grammar 支持。默认配置
在 Theia 应用入口的
package.json
文件的"theia": { }
字段中配置。如:examples/browser/package.json
。然后在 Theming 中有 defaultTheme :
通过 API 设置主题
可以在插件中通过 VSCode API 设置主题。
获取 settings 配置,并更新
workbench.colorTheme
字段。源码
Contributes 配置
PluginContributionHandler 负责插件 Contributes 配置的处理。
MonacoThemingService 处理
MonacoThemingService.loadTheme 读取 json 文件并解析。
MonacoThemingService.register 注册主题。
MonacoThemeRegistry Monaco主题注册
MonacoThemeRegistry 将主题与
monaco
关联,基于vscode-textmate
实现 Editor 代码高亮。通过
vscode-textmate
的 Registry 获取 encodedTokensColors。monaco
是全局引入的。ThemeService UI 主题注册
挂载在全局对象中。
ColorContribution
其他地方可以通过继承 ColorContribution 接口实现 registerColors 方法来注册主题颜色的配置。
如 TerminalFrontendContribution 的 terminal.background 实现:
ColorRegistry
注册主题颜色的配置。
ColorApplicationContribution
在 onStart 生命周期中,依次调用 registerColors 方法注册。
在切换主题时,通过
documentElement.style.setProperty(name, value)
依次设置 CSS Custom Property,从而变换主题。参考
The text was updated successfully, but these errors were encountered: