| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284 |
- /*---------------------------------------------------------------------------------------------
- * Copyright (c) Microsoft Corporation. All rights reserved.
- * Licensed under the MIT License. See License.txt in the project root for license information.
- *--------------------------------------------------------------------------------------------*/
- import { Color } from '../../../../base/common/color.js';
- export class ParsedTokenThemeRule {
- constructor(token, index, fontStyle, foreground, background) {
- this._parsedThemeRuleBrand = undefined;
- this.token = token;
- this.index = index;
- this.fontStyle = fontStyle;
- this.foreground = foreground;
- this.background = background;
- }
- }
- /**
- * Parse a raw theme into rules.
- */
- export function parseTokenTheme(source) {
- if (!source || !Array.isArray(source)) {
- return [];
- }
- const result = [];
- let resultLen = 0;
- for (let i = 0, len = source.length; i < len; i++) {
- const entry = source[i];
- let fontStyle = -1 /* FontStyle.NotSet */;
- if (typeof entry.fontStyle === 'string') {
- fontStyle = 0 /* FontStyle.None */;
- const segments = entry.fontStyle.split(' ');
- for (let j = 0, lenJ = segments.length; j < lenJ; j++) {
- const segment = segments[j];
- switch (segment) {
- case 'italic':
- fontStyle = fontStyle | 1 /* FontStyle.Italic */;
- break;
- case 'bold':
- fontStyle = fontStyle | 2 /* FontStyle.Bold */;
- break;
- case 'underline':
- fontStyle = fontStyle | 4 /* FontStyle.Underline */;
- break;
- case 'strikethrough':
- fontStyle = fontStyle | 8 /* FontStyle.Strikethrough */;
- break;
- }
- }
- }
- let foreground = null;
- if (typeof entry.foreground === 'string') {
- foreground = entry.foreground;
- }
- let background = null;
- if (typeof entry.background === 'string') {
- background = entry.background;
- }
- result[resultLen++] = new ParsedTokenThemeRule(entry.token || '', i, fontStyle, foreground, background);
- }
- return result;
- }
- /**
- * Resolve rules (i.e. inheritance).
- */
- function resolveParsedTokenThemeRules(parsedThemeRules, customTokenColors) {
- // Sort rules lexicographically, and then by index if necessary
- parsedThemeRules.sort((a, b) => {
- const r = strcmp(a.token, b.token);
- if (r !== 0) {
- return r;
- }
- return a.index - b.index;
- });
- // Determine defaults
- let defaultFontStyle = 0 /* FontStyle.None */;
- let defaultForeground = '000000';
- let defaultBackground = 'ffffff';
- while (parsedThemeRules.length >= 1 && parsedThemeRules[0].token === '') {
- const incomingDefaults = parsedThemeRules.shift();
- if (incomingDefaults.fontStyle !== -1 /* FontStyle.NotSet */) {
- defaultFontStyle = incomingDefaults.fontStyle;
- }
- if (incomingDefaults.foreground !== null) {
- defaultForeground = incomingDefaults.foreground;
- }
- if (incomingDefaults.background !== null) {
- defaultBackground = incomingDefaults.background;
- }
- }
- const colorMap = new ColorMap();
- // start with token colors from custom token themes
- for (const color of customTokenColors) {
- colorMap.getId(color);
- }
- const foregroundColorId = colorMap.getId(defaultForeground);
- const backgroundColorId = colorMap.getId(defaultBackground);
- const defaults = new ThemeTrieElementRule(defaultFontStyle, foregroundColorId, backgroundColorId);
- const root = new ThemeTrieElement(defaults);
- for (let i = 0, len = parsedThemeRules.length; i < len; i++) {
- const rule = parsedThemeRules[i];
- root.insert(rule.token, rule.fontStyle, colorMap.getId(rule.foreground), colorMap.getId(rule.background));
- }
- return new TokenTheme(colorMap, root);
- }
- const colorRegExp = /^#?([0-9A-Fa-f]{6})([0-9A-Fa-f]{2})?$/;
- export class ColorMap {
- constructor() {
- this._lastColorId = 0;
- this._id2color = [];
- this._color2id = new Map();
- }
- getId(color) {
- if (color === null) {
- return 0;
- }
- const match = color.match(colorRegExp);
- if (!match) {
- throw new Error('Illegal value for token color: ' + color);
- }
- color = match[1].toUpperCase();
- let value = this._color2id.get(color);
- if (value) {
- return value;
- }
- value = ++this._lastColorId;
- this._color2id.set(color, value);
- this._id2color[value] = Color.fromHex('#' + color);
- return value;
- }
- getColorMap() {
- return this._id2color.slice(0);
- }
- }
- export class TokenTheme {
- constructor(colorMap, root) {
- this._colorMap = colorMap;
- this._root = root;
- this._cache = new Map();
- }
- static createFromRawTokenTheme(source, customTokenColors) {
- return this.createFromParsedTokenTheme(parseTokenTheme(source), customTokenColors);
- }
- static createFromParsedTokenTheme(source, customTokenColors) {
- return resolveParsedTokenThemeRules(source, customTokenColors);
- }
- getColorMap() {
- return this._colorMap.getColorMap();
- }
- _match(token) {
- return this._root.match(token);
- }
- match(languageId, token) {
- // The cache contains the metadata without the language bits set.
- let result = this._cache.get(token);
- if (typeof result === 'undefined') {
- const rule = this._match(token);
- const standardToken = toStandardTokenType(token);
- result = (rule.metadata
- | (standardToken << 8 /* MetadataConsts.TOKEN_TYPE_OFFSET */)) >>> 0;
- this._cache.set(token, result);
- }
- return (result
- | (languageId << 0 /* MetadataConsts.LANGUAGEID_OFFSET */)) >>> 0;
- }
- }
- const STANDARD_TOKEN_TYPE_REGEXP = /\b(comment|string|regex|regexp)\b/;
- export function toStandardTokenType(tokenType) {
- const m = tokenType.match(STANDARD_TOKEN_TYPE_REGEXP);
- if (!m) {
- return 0 /* StandardTokenType.Other */;
- }
- switch (m[1]) {
- case 'comment':
- return 1 /* StandardTokenType.Comment */;
- case 'string':
- return 2 /* StandardTokenType.String */;
- case 'regex':
- return 3 /* StandardTokenType.RegEx */;
- case 'regexp':
- return 3 /* StandardTokenType.RegEx */;
- }
- throw new Error('Unexpected match for standard token type!');
- }
- export function strcmp(a, b) {
- if (a < b) {
- return -1;
- }
- if (a > b) {
- return 1;
- }
- return 0;
- }
- export class ThemeTrieElementRule {
- constructor(fontStyle, foreground, background) {
- this._themeTrieElementRuleBrand = undefined;
- this._fontStyle = fontStyle;
- this._foreground = foreground;
- this._background = background;
- this.metadata = ((this._fontStyle << 11 /* MetadataConsts.FONT_STYLE_OFFSET */)
- | (this._foreground << 15 /* MetadataConsts.FOREGROUND_OFFSET */)
- | (this._background << 24 /* MetadataConsts.BACKGROUND_OFFSET */)) >>> 0;
- }
- clone() {
- return new ThemeTrieElementRule(this._fontStyle, this._foreground, this._background);
- }
- acceptOverwrite(fontStyle, foreground, background) {
- if (fontStyle !== -1 /* FontStyle.NotSet */) {
- this._fontStyle = fontStyle;
- }
- if (foreground !== 0 /* ColorId.None */) {
- this._foreground = foreground;
- }
- if (background !== 0 /* ColorId.None */) {
- this._background = background;
- }
- this.metadata = ((this._fontStyle << 11 /* MetadataConsts.FONT_STYLE_OFFSET */)
- | (this._foreground << 15 /* MetadataConsts.FOREGROUND_OFFSET */)
- | (this._background << 24 /* MetadataConsts.BACKGROUND_OFFSET */)) >>> 0;
- }
- }
- export class ThemeTrieElement {
- constructor(mainRule) {
- this._themeTrieElementBrand = undefined;
- this._mainRule = mainRule;
- this._children = new Map();
- }
- match(token) {
- if (token === '') {
- return this._mainRule;
- }
- const dotIndex = token.indexOf('.');
- let head;
- let tail;
- if (dotIndex === -1) {
- head = token;
- tail = '';
- }
- else {
- head = token.substring(0, dotIndex);
- tail = token.substring(dotIndex + 1);
- }
- const child = this._children.get(head);
- if (typeof child !== 'undefined') {
- return child.match(tail);
- }
- return this._mainRule;
- }
- insert(token, fontStyle, foreground, background) {
- if (token === '') {
- // Merge into the main rule
- this._mainRule.acceptOverwrite(fontStyle, foreground, background);
- return;
- }
- const dotIndex = token.indexOf('.');
- let head;
- let tail;
- if (dotIndex === -1) {
- head = token;
- tail = '';
- }
- else {
- head = token.substring(0, dotIndex);
- tail = token.substring(dotIndex + 1);
- }
- let child = this._children.get(head);
- if (typeof child === 'undefined') {
- child = new ThemeTrieElement(this._mainRule.clone());
- this._children.set(head, child);
- }
- child.insert(tail, fontStyle, foreground, background);
- }
- }
- export function generateTokensCSSForColorMap(colorMap) {
- const rules = [];
- for (let i = 1, len = colorMap.length; i < len; i++) {
- const color = colorMap[i];
- rules[i] = `.mtk${i} { color: ${color}; }`;
- }
- rules.push('.mtki { font-style: italic; }');
- rules.push('.mtkb { font-weight: bold; }');
- rules.push('.mtku { text-decoration: underline; text-underline-position: under; }');
- rules.push('.mtks { text-decoration: line-through; }');
- rules.push('.mtks.mtku { text-decoration: underline line-through; text-underline-position: under; }');
- return rules.join('\n');
- }
|