From 26bd7a896b4bbc4a2432df47dceff939aac921fa Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Tue, 31 Dec 2019 11:06:50 +0100 Subject: Drop support for legacy colorization --- editors/code/src/color_theme.ts | 123 ++++++++++++++++++++++++++++++++++ editors/code/src/config.ts | 4 -- editors/code/src/highlighting.ts | 106 ++++++++++++----------------- editors/code/src/load_theme_colors.ts | 108 ----------------------------- editors/code/src/scopes_mapper.ts | 78 --------------------- 5 files changed, 164 insertions(+), 255 deletions(-) create mode 100644 editors/code/src/color_theme.ts delete mode 100644 editors/code/src/load_theme_colors.ts delete mode 100644 editors/code/src/scopes_mapper.ts (limited to 'editors') diff --git a/editors/code/src/color_theme.ts b/editors/code/src/color_theme.ts new file mode 100644 index 000000000..1df7eba7a --- /dev/null +++ b/editors/code/src/color_theme.ts @@ -0,0 +1,123 @@ +import * as fs from 'fs'; +import * as jsonc from 'jsonc-parser'; +import * as path from 'path'; +import * as vscode from 'vscode'; + +export interface TextMateRuleSettings { + foreground?: string; + background?: string; + fontStyle?: string; +} + +export class ColorTheme { + private rules: Map = new Map(); + + static load(): ColorTheme { + // Find out current color theme + const themeName = vscode.workspace + .getConfiguration('workbench') + .get('colorTheme'); + + if (typeof themeName !== 'string') { + // console.warn('workbench.colorTheme is', themeName) + return new ColorTheme(); + } + return loadThemeNamed(themeName); + } + + static fromRules(rules: TextMateRule[]): ColorTheme { + const res = new ColorTheme(); + for (const rule of rules) { + const scopes = typeof rule.scope === 'string' + ? [rule.scope] + : rule.scope; + for (const scope of scopes) { + res.rules.set(scope, rule.settings) + } + } + return res + } + + lookup(scopes: string[]): TextMateRuleSettings { + let res: TextMateRuleSettings = {} + for (const scope of scopes) { + this.rules.forEach((value, key) => { + if (scope.startsWith(key)) { + res = mergeRuleSettings(res, value) + } + }) + } + return res + } + + mergeFrom(other: ColorTheme) { + other.rules.forEach((value, key) => { + const merged = mergeRuleSettings(this.rules.get(key), value) + this.rules.set(key, merged) + }) + } +} + +function loadThemeNamed(themeName: string): ColorTheme { + function isTheme(extension: vscode.Extension): boolean { + return ( + extension.extensionKind === vscode.ExtensionKind.UI && + extension.packageJSON.contributes && + extension.packageJSON.contributes.themes + ); + } + + let themePaths = vscode.extensions.all + .filter(isTheme) + .flatMap(ext => { + return ext.packageJSON.contributes.themes + .filter((it: any) => (it.id || it.label) === themeName) + .map((it: any) => path.join(ext.extensionPath, it.path)); + }) + + const res = new ColorTheme(); + for (const themePath of themePaths) { + res.mergeFrom(loadThemeFile(themePath)) + } + + const customizations: any = vscode.workspace.getConfiguration('editor').get('tokenColorCustomizations'); + res.mergeFrom(ColorTheme.fromRules(customizations?.textMateRules ?? [])) + + return res; +} + +function loadThemeFile(themePath: string): ColorTheme { + let text; + try { + text = fs.readFileSync(themePath, 'utf8') + } catch { + return new ColorTheme(); + } + const obj = jsonc.parse(text); + const tokenColors = obj?.tokenColors ?? []; + const res = ColorTheme.fromRules(tokenColors); + + for (const include in obj?.include ?? []) { + const includePath = path.join(path.dirname(themePath), include); + const tmp = loadThemeFile(includePath); + res.mergeFrom(tmp); + } + + return res; +} + +interface TextMateRule { + scope: string | string[]; + settings: TextMateRuleSettings; +} + +function mergeRuleSettings( + defaultSetting: TextMateRuleSettings | undefined, + override: TextMateRuleSettings, +): TextMateRuleSettings { + return { + foreground: override.foreground ?? defaultSetting?.foreground, + background: override.background ?? defaultSetting?.background, + fontStyle: override.fontStyle ?? defaultSetting?.fontStyle, + } +} diff --git a/editors/code/src/config.ts b/editors/code/src/config.ts index f63d1ddce..ccb0ee2b7 100644 --- a/editors/code/src/config.ts +++ b/editors/code/src/config.ts @@ -1,5 +1,4 @@ import * as vscode from 'vscode'; -import * as scopesMapper from './scopes_mapper'; const RA_LSP_DEBUG = process.env.__RA_LSP_SERVER_DEBUG; @@ -58,9 +57,6 @@ export class Config { if (config.has('highlightingOn')) { this.highlightingOn = config.get('highlightingOn') as boolean; - if (this.highlightingOn) { - scopesMapper.load(); - } } if (config.has('rainbowHighlightingOn')) { diff --git a/editors/code/src/highlighting.ts b/editors/code/src/highlighting.ts index e97eb086a..d383d87ef 100644 --- a/editors/code/src/highlighting.ts +++ b/editors/code/src/highlighting.ts @@ -3,8 +3,7 @@ import * as lc from 'vscode-languageclient'; import * as seedrandom_ from 'seedrandom'; const seedrandom = seedrandom_; // https://github.com/jvandemo/generator-angular2-library/issues/221#issuecomment-355945207 -import { loadThemeColors, TextMateRuleSettings } from './load_theme_colors'; -import * as scopesMapper from './scopes_mapper'; +import { ColorTheme, TextMateRuleSettings } from './color_theme'; import { Ctx } from './ctx'; @@ -168,69 +167,16 @@ class Highlighter { } } -function initDecorations(): Map< - string, - vscode.TextEditorDecorationType -> { - const themeColors = loadThemeColors(); - - const decoration = ( - tag: string, - textDecoration?: string, - ): [string, vscode.TextEditorDecorationType] => { - const rule = scopesMapper.toRule(tag, it => themeColors.get(it)); - - if (rule) { - const decor = createDecorationFromTextmate(rule); - return [tag, decor]; - } else { - const fallBackTag = 'ralsp.' + tag; - // console.log(' '); - // console.log('Missing theme for: <"' + tag + '"> for following mapped scopes:'); - // console.log(scopesMapper.find(tag)); - // console.log('Falling back to values defined in: ' + fallBackTag); - // console.log(' '); - const color = new vscode.ThemeColor(fallBackTag); - const decor = vscode.window.createTextEditorDecorationType({ - color, - textDecoration, - }); - return [tag, decor]; - } - }; - - const decorations: Iterable<[ - string, - vscode.TextEditorDecorationType, - ]> = [ - decoration('comment'), - decoration('string'), - decoration('keyword'), - decoration('keyword.control'), - decoration('keyword.unsafe'), - decoration('function'), - decoration('parameter'), - decoration('constant'), - decoration('type.builtin'), - decoration('type.generic'), - decoration('type.lifetime'), - decoration('type.param'), - decoration('type.self'), - decoration('type'), - decoration('text'), - decoration('attribute'), - decoration('literal'), - decoration('literal.numeric'), - decoration('literal.char'), - decoration('literal.byte'), - decoration('macro'), - decoration('variable'), - decoration('variable.mut', 'underline'), - decoration('field'), - decoration('module'), - ]; - - return new Map(decorations); +function initDecorations(): Map { + const theme = ColorTheme.load(); + const res = new Map() + TAG_TO_SCOPES.forEach((scopes, tag) => { + if (!scopes) throw `unmapped tag: ${tag}` + let rule = theme.lookup(scopes) + const decor = createDecorationFromTextmate(rule); + res.set(tag, decor) + }) + return res; } function createDecorationFromTextmate( @@ -267,3 +213,33 @@ function createDecorationFromTextmate( } return vscode.window.createTextEditorDecorationType(decorationOptions); } + +// sync with tags from `syntax_highlighting.rs`. +const TAG_TO_SCOPES = new Map([ + ["field", ["entity.name.field"]], + ["function", ["entity.name.function"]], + ["module", ["entity.name.module"]], + ["constant", ["entity.name.constant"]], + ["macro", ["entity.name.macro"]], + + ["variable", ["variable"]], + ["variable.mut", ["variable", "meta.mutable"]], + + ["type", ["entity.name.type"]], + ["type.builtin", ["entity.name.type", "support.type.primitive"]], + ["type.self", ["entity.name.type.parameter.self"]], + ["type.param", ["entity.name.type.parameter"]], + ["type.lifetime", ["entity.name.type.lifetime"]], + + ["literal.byte", ["constant.character.byte"]], + ["literal.char", ["constant.character"]], + ["literal.numeric", ["constant.numeric"]], + + ["comment", ["comment"]], + ["string", ["string.quoted"]], + ["attribute", ["meta.attribute"]], + + ["keyword", ["keyword"]], + ["keyword.unsafe", ["keyword.other.unsafe"]], + ["keyword.control", ["keyword.control"]], +]); diff --git a/editors/code/src/load_theme_colors.ts b/editors/code/src/load_theme_colors.ts deleted file mode 100644 index 73fabbf54..000000000 --- a/editors/code/src/load_theme_colors.ts +++ /dev/null @@ -1,108 +0,0 @@ -import * as fs from 'fs'; -import * as jsonc from 'jsonc-parser'; -import * as path from 'path'; -import * as vscode from 'vscode'; - -export interface TextMateRuleSettings { - foreground?: string; - background?: string; - fontStyle?: string; -} - -// Load all textmate scopes in the currently active theme -export function loadThemeColors(): Map { - // Find out current color theme - const themeName = vscode.workspace - .getConfiguration('workbench') - .get('colorTheme'); - - if (typeof themeName !== 'string') { - // console.warn('workbench.colorTheme is', themeName) - return new Map(); - } - return loadThemeNamed(themeName); -} - -function loadThemeNamed(themeName: string): Map { - function isTheme(extension: vscode.Extension): boolean { - return ( - extension.extensionKind === vscode.ExtensionKind.UI && - extension.packageJSON.contributes && - extension.packageJSON.contributes.themes - ); - } - - let themePaths = vscode.extensions.all - .filter(isTheme) - .flatMap(ext => { - return ext.packageJSON.contributes.themes - .filter((it: any) => (it.id || it.label) === themeName) - .map((it: any) => path.join(ext.extensionPath, it.path)); - }) - - const res = new Map(); - for (const themePath of themePaths) { - mergeInto(res, loadThemeFile(themePath)) - } - - const customizations: any = vscode.workspace.getConfiguration('editor').get('tokenColorCustomizations'); - mergeInto(res, loadColors(customizations?.textMateRules ?? [])) - - return res; -} - -function loadThemeFile(themePath: string): Map { - let text; - try { - text = fs.readFileSync(themePath, 'utf8') - } catch { - return new Map(); - } - const obj = jsonc.parse(text); - const tokenColors = obj?.tokenColors ?? []; - const res = loadColors(tokenColors); - - for (const include in obj?.include ?? []) { - const includePath = path.join(path.dirname(themePath), include); - const tmp = loadThemeFile(includePath); - mergeInto(res, tmp); - } - - return res; -} - -interface TextMateRule { - scope: string | string[]; - settings: TextMateRuleSettings; -} - -function loadColors(textMateRules: TextMateRule[]): Map { - const res = new Map(); - for (const rule of textMateRules) { - const scopes = typeof rule.scope === 'string' - ? [rule.scope] - : rule.scope; - for (const scope of scopes) { - res.set(scope, rule.settings) - } - } - return res -} - -function mergeRuleSettings( - defaultSetting: TextMateRuleSettings | undefined, - override: TextMateRuleSettings, -): TextMateRuleSettings { - return { - foreground: defaultSetting?.foreground ?? override.foreground, - background: defaultSetting?.background ?? override.background, - fontStyle: defaultSetting?.fontStyle ?? override.fontStyle, - } -} - -function mergeInto(dst: Map, addition: Map) { - addition.forEach((value, key) => { - const merged = mergeRuleSettings(dst.get(key), value) - dst.set(key, merged) - }) -} diff --git a/editors/code/src/scopes_mapper.ts b/editors/code/src/scopes_mapper.ts deleted file mode 100644 index 1295ab476..000000000 --- a/editors/code/src/scopes_mapper.ts +++ /dev/null @@ -1,78 +0,0 @@ -import * as vscode from 'vscode'; -import { TextMateRuleSettings } from './load_theme_colors'; - -let mappings = new Map(); - -const defaultMapping = new Map([ - [ - 'comment', - [ - 'comment', - 'comment.block', - 'comment.line', - 'comment.block.documentation', - ], - ], - ['string', ['string']], - ['keyword', ['keyword']], - ['keyword.control', ['keyword.control', 'keyword', 'keyword.other']], - [ - 'keyword.unsafe', - ['storage.modifier', 'keyword.other', 'keyword.control', 'keyword'], - ], - ['function', ['entity.name.function']], - ['parameter', ['variable.parameter']], - ['constant', ['constant', 'variable']], - ['type', ['entity.name.type']], - ['builtin', ['variable.language', 'support.type', 'support.type']], - ['text', ['string', 'string.quoted', 'string.regexp']], - ['attribute', ['keyword']], - ['literal', ['string', 'string.quoted', 'string.regexp']], - ['macro', ['entity.name.function', 'keyword.other', 'entity.name.macro']], - ['variable', ['variable']], - ['variable.mut', ['variable', 'storage.modifier']], - [ - 'field', - [ - 'variable.object.property', - 'meta.field.declaration', - 'meta.definition.property', - 'variable.other', - ], - ], - ['module', ['entity.name.section', 'entity.other']], -]); - -export function find(scope: string): string[] { - return mappings.get(scope) || []; -} - -export function toRule( - scope: string, - intoRule: (scope: string) => TextMateRuleSettings | undefined, -): TextMateRuleSettings | undefined { - return find(scope) - .map(intoRule) - .filter(rule => rule !== undefined)[0]; -} - -function isString(value: any): value is string { - return typeof value === 'string'; -} - -function isArrayOfString(value: any): value is string[] { - return Array.isArray(value) && value.every(item => isString(item)); -} - -export function load() { - const rawConfig: { [key: string]: any } = - vscode.workspace - .getConfiguration('rust-analyzer') - .get('scopeMappings') || {}; - - mappings = Object.entries(rawConfig) - .filter(([_, value]) => isString(value) || isArrayOfString(value)) - .reduce((list, [key, value]: [string, string | string[]]) => { - return list.set(key, isString(value) ? [value] : value); - }, defaultMapping); -} -- cgit v1.2.3