monaco-editor
Version:
A browser based code editor
285 lines (284 loc) • 10.8 kB
JavaScript
/*---------------------------------------------------------------------------------------------
* 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';
var ParsedTokenThemeRule = /** @class */ (function () {
function ParsedTokenThemeRule(token, index, fontStyle, foreground, background) {
this.token = token;
this.index = index;
this.fontStyle = fontStyle;
this.foreground = foreground;
this.background = background;
}
return ParsedTokenThemeRule;
}());
export { ParsedTokenThemeRule };
/**
* Parse a raw theme into rules.
*/
export function parseTokenTheme(source) {
if (!source || !Array.isArray(source)) {
return [];
}
var result = [], resultLen = 0;
for (var i = 0, len = source.length; i < len; i++) {
var entry = source[i];
var fontStyle = -1 /* NotSet */;
if (typeof entry.fontStyle === 'string') {
fontStyle = 0 /* None */;
var segments = entry.fontStyle.split(' ');
for (var j = 0, lenJ = segments.length; j < lenJ; j++) {
var segment = segments[j];
switch (segment) {
case 'italic':
fontStyle = fontStyle | 1 /* Italic */;
break;
case 'bold':
fontStyle = fontStyle | 2 /* Bold */;
break;
case 'underline':
fontStyle = fontStyle | 4 /* Underline */;
break;
}
}
}
var foreground = null;
if (typeof entry.foreground === 'string') {
foreground = entry.foreground;
}
var 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(function (a, b) {
var r = strcmp(a.token, b.token);
if (r !== 0) {
return r;
}
return a.index - b.index;
});
// Determine defaults
var defaultFontStyle = 0 /* None */;
var defaultForeground = '000000';
var defaultBackground = 'ffffff';
while (parsedThemeRules.length >= 1 && parsedThemeRules[0].token === '') {
var incomingDefaults = parsedThemeRules.shift();
if (incomingDefaults.fontStyle !== -1 /* NotSet */) {
defaultFontStyle = incomingDefaults.fontStyle;
}
if (incomingDefaults.foreground !== null) {
defaultForeground = incomingDefaults.foreground;
}
if (incomingDefaults.background !== null) {
defaultBackground = incomingDefaults.background;
}
}
var colorMap = new ColorMap();
// start with token colors from custom token themes
for (var _i = 0, customTokenColors_1 = customTokenColors; _i < customTokenColors_1.length; _i++) {
var color = customTokenColors_1[_i];
colorMap.getId(color);
}
var foregroundColorId = colorMap.getId(defaultForeground);
var backgroundColorId = colorMap.getId(defaultBackground);
var defaults = new ThemeTrieElementRule(defaultFontStyle, foregroundColorId, backgroundColorId);
var root = new ThemeTrieElement(defaults);
for (var i = 0, len = parsedThemeRules.length; i < len; i++) {
var rule = parsedThemeRules[i];
root.insert(rule.token, rule.fontStyle, colorMap.getId(rule.foreground), colorMap.getId(rule.background));
}
return new TokenTheme(colorMap, root);
}
var colorRegExp = /^#?([0-9A-Fa-f]{6})([0-9A-Fa-f]{2})?$/;
var ColorMap = /** @class */ (function () {
function ColorMap() {
this._lastColorId = 0;
this._id2color = [];
this._color2id = new Map();
}
ColorMap.prototype.getId = function (color) {
if (color === null) {
return 0;
}
var match = color.match(colorRegExp);
if (!match) {
throw new Error('Illegal value for token color: ' + color);
}
color = match[1].toUpperCase();
var 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;
};
ColorMap.prototype.getColorMap = function () {
return this._id2color.slice(0);
};
return ColorMap;
}());
export { ColorMap };
var TokenTheme = /** @class */ (function () {
function TokenTheme(colorMap, root) {
this._colorMap = colorMap;
this._root = root;
this._cache = new Map();
}
TokenTheme.createFromRawTokenTheme = function (source, customTokenColors) {
return this.createFromParsedTokenTheme(parseTokenTheme(source), customTokenColors);
};
TokenTheme.createFromParsedTokenTheme = function (source, customTokenColors) {
return resolveParsedTokenThemeRules(source, customTokenColors);
};
TokenTheme.prototype.getColorMap = function () {
return this._colorMap.getColorMap();
};
TokenTheme.prototype._match = function (token) {
return this._root.match(token);
};
TokenTheme.prototype.match = function (languageId, token) {
// The cache contains the metadata without the language bits set.
var result = this._cache.get(token);
if (typeof result === 'undefined') {
var rule = this._match(token);
var standardToken = toStandardTokenType(token);
result = (rule.metadata
| (standardToken << 8 /* TOKEN_TYPE_OFFSET */)) >>> 0;
this._cache.set(token, result);
}
return (result
| (languageId << 0 /* LANGUAGEID_OFFSET */)) >>> 0;
};
return TokenTheme;
}());
export { TokenTheme };
var STANDARD_TOKEN_TYPE_REGEXP = /\b(comment|string|regex)\b/;
export function toStandardTokenType(tokenType) {
var m = tokenType.match(STANDARD_TOKEN_TYPE_REGEXP);
if (!m) {
return 0 /* Other */;
}
switch (m[1]) {
case 'comment':
return 1 /* Comment */;
case 'string':
return 2 /* String */;
case 'regex':
return 4 /* 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;
}
var ThemeTrieElementRule = /** @class */ (function () {
function ThemeTrieElementRule(fontStyle, foreground, background) {
this._fontStyle = fontStyle;
this._foreground = foreground;
this._background = background;
this.metadata = ((this._fontStyle << 11 /* FONT_STYLE_OFFSET */)
| (this._foreground << 14 /* FOREGROUND_OFFSET */)
| (this._background << 23 /* BACKGROUND_OFFSET */)) >>> 0;
}
ThemeTrieElementRule.prototype.clone = function () {
return new ThemeTrieElementRule(this._fontStyle, this._foreground, this._background);
};
ThemeTrieElementRule.prototype.acceptOverwrite = function (fontStyle, foreground, background) {
if (fontStyle !== -1 /* NotSet */) {
this._fontStyle = fontStyle;
}
if (foreground !== 0 /* None */) {
this._foreground = foreground;
}
if (background !== 0 /* None */) {
this._background = background;
}
this.metadata = ((this._fontStyle << 11 /* FONT_STYLE_OFFSET */)
| (this._foreground << 14 /* FOREGROUND_OFFSET */)
| (this._background << 23 /* BACKGROUND_OFFSET */)) >>> 0;
};
return ThemeTrieElementRule;
}());
export { ThemeTrieElementRule };
var ThemeTrieElement = /** @class */ (function () {
function ThemeTrieElement(mainRule) {
this._mainRule = mainRule;
this._children = new Map();
}
ThemeTrieElement.prototype.match = function (token) {
if (token === '') {
return this._mainRule;
}
var dotIndex = token.indexOf('.');
var head;
var tail;
if (dotIndex === -1) {
head = token;
tail = '';
}
else {
head = token.substring(0, dotIndex);
tail = token.substring(dotIndex + 1);
}
var child = this._children.get(head);
if (typeof child !== 'undefined') {
return child.match(tail);
}
return this._mainRule;
};
ThemeTrieElement.prototype.insert = function (token, fontStyle, foreground, background) {
if (token === '') {
// Merge into the main rule
this._mainRule.acceptOverwrite(fontStyle, foreground, background);
return;
}
var dotIndex = token.indexOf('.');
var head;
var tail;
if (dotIndex === -1) {
head = token;
tail = '';
}
else {
head = token.substring(0, dotIndex);
tail = token.substring(dotIndex + 1);
}
var 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);
};
return ThemeTrieElement;
}());
export { ThemeTrieElement };
export function generateTokensCSSForColorMap(colorMap) {
var rules = [];
for (var i = 1, len = colorMap.length; i < len; i++) {
var 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; }');
return rules.join('\n');
}