123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314 |
- /*---------------------------------------------------------------------------------------------
- * Copyright (c) Microsoft Corporation. All rights reserved.
- * Licensed under the MIT License. See License.txt in the project root for license information.
- *--------------------------------------------------------------------------------------------*/
- import * as dom from '../../../base/browser/dom.js';
- import { Color } from '../../../base/common/color.js';
- import { Emitter } from '../../../base/common/event.js';
- import { TokenizationRegistry, TokenMetadata } from '../../common/modes.js';
- import { TokenTheme, generateTokensCSSForColorMap } from '../../common/modes/supports/tokenization.js';
- import { hc_black, vs, vs_dark } from '../common/themes.js';
- import { Registry } from '../../../platform/registry/common/platform.js';
- import { asCssVariableName, Extensions } from '../../../platform/theme/common/colorRegistry.js';
- import { Extensions as ThemingExtensions } from '../../../platform/theme/common/themeService.js';
- import { Disposable } from '../../../base/common/lifecycle.js';
- import { ColorScheme } from '../../../platform/theme/common/theme.js';
- import { getIconsStyleSheet } from '../../../platform/theme/browser/iconsStyleSheet.js';
- const VS_THEME_NAME = 'vs';
- const VS_DARK_THEME_NAME = 'vs-dark';
- const HC_BLACK_THEME_NAME = 'hc-black';
- const colorRegistry = Registry.as(Extensions.ColorContribution);
- const themingRegistry = Registry.as(ThemingExtensions.ThemingContribution);
- class StandaloneTheme {
- constructor(name, standaloneThemeData) {
- this.semanticHighlighting = false;
- this.themeData = standaloneThemeData;
- let base = standaloneThemeData.base;
- if (name.length > 0) {
- if (isBuiltinTheme(name)) {
- this.id = name;
- }
- else {
- this.id = base + ' ' + name;
- }
- this.themeName = name;
- }
- else {
- this.id = base;
- this.themeName = base;
- }
- this.colors = null;
- this.defaultColors = Object.create(null);
- this._tokenTheme = null;
- }
- get base() {
- return this.themeData.base;
- }
- notifyBaseUpdated() {
- if (this.themeData.inherit) {
- this.colors = null;
- this._tokenTheme = null;
- }
- }
- getColors() {
- if (!this.colors) {
- const colors = new Map();
- for (let id in this.themeData.colors) {
- colors.set(id, Color.fromHex(this.themeData.colors[id]));
- }
- if (this.themeData.inherit) {
- let baseData = getBuiltinRules(this.themeData.base);
- for (let id in baseData.colors) {
- if (!colors.has(id)) {
- colors.set(id, Color.fromHex(baseData.colors[id]));
- }
- }
- }
- this.colors = colors;
- }
- return this.colors;
- }
- getColor(colorId, useDefault) {
- const color = this.getColors().get(colorId);
- if (color) {
- return color;
- }
- if (useDefault !== false) {
- return this.getDefault(colorId);
- }
- return undefined;
- }
- getDefault(colorId) {
- let color = this.defaultColors[colorId];
- if (color) {
- return color;
- }
- color = colorRegistry.resolveDefaultColor(colorId, this);
- this.defaultColors[colorId] = color;
- return color;
- }
- defines(colorId) {
- return Object.prototype.hasOwnProperty.call(this.getColors(), colorId);
- }
- get type() {
- switch (this.base) {
- case VS_THEME_NAME: return ColorScheme.LIGHT;
- case HC_BLACK_THEME_NAME: return ColorScheme.HIGH_CONTRAST;
- default: return ColorScheme.DARK;
- }
- }
- get tokenTheme() {
- if (!this._tokenTheme) {
- let rules = [];
- let encodedTokensColors = [];
- if (this.themeData.inherit) {
- let baseData = getBuiltinRules(this.themeData.base);
- rules = baseData.rules;
- if (baseData.encodedTokensColors) {
- encodedTokensColors = baseData.encodedTokensColors;
- }
- }
- // Pick up default colors from `editor.foreground` and `editor.background` if available
- const editorForeground = this.themeData.colors['editor.foreground'];
- const editorBackground = this.themeData.colors['editor.background'];
- if (editorForeground || editorBackground) {
- const rule = { token: '' };
- if (editorForeground) {
- rule.foreground = editorForeground;
- }
- if (editorBackground) {
- rule.background = editorBackground;
- }
- rules.push(rule);
- }
- rules = rules.concat(this.themeData.rules);
- if (this.themeData.encodedTokensColors) {
- encodedTokensColors = this.themeData.encodedTokensColors;
- }
- this._tokenTheme = TokenTheme.createFromRawTokenTheme(rules, encodedTokensColors);
- }
- return this._tokenTheme;
- }
- getTokenStyleMetadata(type, modifiers, modelLanguage) {
- // use theme rules match
- const style = this.tokenTheme._match([type].concat(modifiers).join('.'));
- const metadata = style.metadata;
- const foreground = TokenMetadata.getForeground(metadata);
- const fontStyle = TokenMetadata.getFontStyle(metadata);
- return {
- foreground: foreground,
- italic: Boolean(fontStyle & 1 /* Italic */),
- bold: Boolean(fontStyle & 2 /* Bold */),
- underline: Boolean(fontStyle & 4 /* Underline */)
- };
- }
- }
- function isBuiltinTheme(themeName) {
- return (themeName === VS_THEME_NAME
- || themeName === VS_DARK_THEME_NAME
- || themeName === HC_BLACK_THEME_NAME);
- }
- function getBuiltinRules(builtinTheme) {
- switch (builtinTheme) {
- case VS_THEME_NAME:
- return vs;
- case VS_DARK_THEME_NAME:
- return vs_dark;
- case HC_BLACK_THEME_NAME:
- return hc_black;
- }
- }
- function newBuiltInTheme(builtinTheme) {
- let themeData = getBuiltinRules(builtinTheme);
- return new StandaloneTheme(builtinTheme, themeData);
- }
- export class StandaloneThemeServiceImpl extends Disposable {
- constructor() {
- super();
- this._onColorThemeChange = this._register(new Emitter());
- this.onDidColorThemeChange = this._onColorThemeChange.event;
- this._environment = Object.create(null);
- this._autoDetectHighContrast = true;
- this._knownThemes = new Map();
- this._knownThemes.set(VS_THEME_NAME, newBuiltInTheme(VS_THEME_NAME));
- this._knownThemes.set(VS_DARK_THEME_NAME, newBuiltInTheme(VS_DARK_THEME_NAME));
- this._knownThemes.set(HC_BLACK_THEME_NAME, newBuiltInTheme(HC_BLACK_THEME_NAME));
- const iconsStyleSheet = getIconsStyleSheet();
- this._codiconCSS = iconsStyleSheet.getCSS();
- this._themeCSS = '';
- this._allCSS = `${this._codiconCSS}\n${this._themeCSS}`;
- this._globalStyleElement = null;
- this._styleElements = [];
- this._colorMapOverride = null;
- this.setTheme(VS_THEME_NAME);
- iconsStyleSheet.onDidChange(() => {
- this._codiconCSS = iconsStyleSheet.getCSS();
- this._updateCSS();
- });
- dom.addMatchMediaChangeListener('(forced-colors: active)', () => {
- this._updateActualTheme();
- });
- }
- registerEditorContainer(domNode) {
- if (dom.isInShadowDOM(domNode)) {
- return this._registerShadowDomContainer(domNode);
- }
- return this._registerRegularEditorContainer();
- }
- _registerRegularEditorContainer() {
- if (!this._globalStyleElement) {
- this._globalStyleElement = dom.createStyleSheet();
- this._globalStyleElement.className = 'monaco-colors';
- this._globalStyleElement.textContent = this._allCSS;
- this._styleElements.push(this._globalStyleElement);
- }
- return Disposable.None;
- }
- _registerShadowDomContainer(domNode) {
- const styleElement = dom.createStyleSheet(domNode);
- styleElement.className = 'monaco-colors';
- styleElement.textContent = this._allCSS;
- this._styleElements.push(styleElement);
- return {
- dispose: () => {
- for (let i = 0; i < this._styleElements.length; i++) {
- if (this._styleElements[i] === styleElement) {
- this._styleElements.splice(i, 1);
- return;
- }
- }
- }
- };
- }
- defineTheme(themeName, themeData) {
- if (!/^[a-z0-9\-]+$/i.test(themeName)) {
- throw new Error('Illegal theme name!');
- }
- if (!isBuiltinTheme(themeData.base) && !isBuiltinTheme(themeName)) {
- throw new Error('Illegal theme base!');
- }
- // set or replace theme
- this._knownThemes.set(themeName, new StandaloneTheme(themeName, themeData));
- if (isBuiltinTheme(themeName)) {
- this._knownThemes.forEach(theme => {
- if (theme.base === themeName) {
- theme.notifyBaseUpdated();
- }
- });
- }
- if (this._theme.themeName === themeName) {
- this.setTheme(themeName); // refresh theme
- }
- }
- getColorTheme() {
- return this._theme;
- }
- setColorMapOverride(colorMapOverride) {
- this._colorMapOverride = colorMapOverride;
- this._updateThemeOrColorMap();
- }
- setTheme(themeName) {
- let theme;
- if (this._knownThemes.has(themeName)) {
- theme = this._knownThemes.get(themeName);
- }
- else {
- theme = this._knownThemes.get(VS_THEME_NAME);
- }
- this._desiredTheme = theme;
- this._updateActualTheme();
- }
- _updateActualTheme() {
- const theme = (this._autoDetectHighContrast && window.matchMedia(`(forced-colors: active)`).matches
- ? this._knownThemes.get(HC_BLACK_THEME_NAME)
- : this._desiredTheme);
- if (this._theme === theme) {
- // Nothing to do
- return;
- }
- this._theme = theme;
- this._updateThemeOrColorMap();
- }
- setAutoDetectHighContrast(autoDetectHighContrast) {
- this._autoDetectHighContrast = autoDetectHighContrast;
- this._updateActualTheme();
- }
- _updateThemeOrColorMap() {
- let cssRules = [];
- let hasRule = {};
- let ruleCollector = {
- addRule: (rule) => {
- if (!hasRule[rule]) {
- cssRules.push(rule);
- hasRule[rule] = true;
- }
- }
- };
- themingRegistry.getThemingParticipants().forEach(p => p(this._theme, ruleCollector, this._environment));
- const colorVariables = [];
- for (const item of colorRegistry.getColors()) {
- const color = this._theme.getColor(item.id, true);
- if (color) {
- colorVariables.push(`${asCssVariableName(item.id)}: ${color.toString()};`);
- }
- }
- ruleCollector.addRule(`.monaco-editor { ${colorVariables.join('\n')} }`);
- const colorMap = this._colorMapOverride || this._theme.tokenTheme.getColorMap();
- ruleCollector.addRule(generateTokensCSSForColorMap(colorMap));
- this._themeCSS = cssRules.join('\n');
- this._updateCSS();
- TokenizationRegistry.setColorMap(colorMap);
- this._onColorThemeChange.fire(this._theme);
- }
- _updateCSS() {
- this._allCSS = `${this._codiconCSS}\n${this._themeCSS}`;
- this._styleElements.forEach(styleElement => styleElement.textContent = this._allCSS);
- }
- getFileIconTheme() {
- return {
- hasFileIcons: false,
- hasFolderIcons: false,
- hidesExplorerArrows: false
- };
- }
- }
|