From f984ef26528eca686abbb946b3b363dfe6d74822 Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Tue, 31 Dec 2019 03:33:00 +0100 Subject: [PATCH] Switch impure functional style to pure imperative --- editors/code/src/config.ts | 2 - editors/code/src/highlighting.ts | 8 +- editors/code/src/scopes.ts | 148 +++++++++++++------------------ editors/code/tsconfig.json | 2 +- 4 files changed, 66 insertions(+), 94 deletions(-) diff --git a/editors/code/src/config.ts b/editors/code/src/config.ts index e323110a4b..f63d1ddcea 100644 --- a/editors/code/src/config.ts +++ b/editors/code/src/config.ts @@ -1,5 +1,4 @@ import * as vscode from 'vscode'; -import * as scopes from './scopes'; import * as scopesMapper from './scopes_mapper'; const RA_LSP_DEBUG = process.env.__RA_LSP_SERVER_DEBUG; @@ -60,7 +59,6 @@ export class Config { if (config.has('highlightingOn')) { this.highlightingOn = config.get('highlightingOn') as boolean; if (this.highlightingOn) { - scopes.load(); scopesMapper.load(); } } diff --git a/editors/code/src/highlighting.ts b/editors/code/src/highlighting.ts index 4c2e7f67be..5e9cbe0de7 100644 --- a/editors/code/src/highlighting.ts +++ b/editors/code/src/highlighting.ts @@ -3,7 +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 * as scopes from './scopes'; +import { loadThemeColors, TextMateRuleSettings } from './scopes'; import * as scopesMapper from './scopes_mapper'; import { Ctx } from './ctx'; @@ -172,11 +172,13 @@ function initDecorations(): Map< string, vscode.TextEditorDecorationType > { + const themeColors = loadThemeColors(); + const decoration = ( tag: string, textDecoration?: string, ): [string, vscode.TextEditorDecorationType] => { - const rule = scopesMapper.toRule(tag, scopes.find); + const rule = scopesMapper.toRule(tag, it => themeColors.get(it)); if (rule) { const decor = createDecorationFromTextmate(rule); @@ -232,7 +234,7 @@ function initDecorations(): Map< } function createDecorationFromTextmate( - themeStyle: scopes.TextMateRuleSettings, + themeStyle: TextMateRuleSettings, ): vscode.TextEditorDecorationType { const decorationOptions: vscode.DecorationRenderOptions = {}; decorationOptions.rangeBehavior = vscode.DecorationRangeBehavior.OpenOpen; diff --git a/editors/code/src/scopes.ts b/editors/code/src/scopes.ts index 1229f0fb9c..73fabbf549 100644 --- a/editors/code/src/scopes.ts +++ b/editors/code/src/scopes.ts @@ -3,28 +3,14 @@ import * as jsonc from 'jsonc-parser'; import * as path from 'path'; import * as vscode from 'vscode'; -export interface TextMateRule { - scope: string | string[]; - settings: TextMateRuleSettings; -} - export interface TextMateRuleSettings { foreground?: string; background?: string; fontStyle?: string; } -// Current theme colors -const rules = new Map(); - -export function find(scope: string): TextMateRuleSettings | undefined { - return rules.get(scope); -} - // Load all textmate scopes in the currently active theme -export function load() { - // Remove any previous theme - rules.clear(); +export function loadThemeColors(): Map { // Find out current color theme const themeName = vscode.workspace .getConfiguration('workbench') @@ -32,20 +18,12 @@ export function load() { if (typeof themeName !== 'string') { // console.warn('workbench.colorTheme is', themeName) - return; - } - // Try to load colors from that theme - try { - loadThemeNamed(themeName); - } catch (e) { - // console.warn('failed to load theme', themeName, e) + return new Map(); } + return loadThemeNamed(themeName); } - - -// Find current theme on disk -function loadThemeNamed(themeName: string) { +function loadThemeNamed(themeName: string): Map { function isTheme(extension: vscode.Extension): boolean { return ( extension.extensionKind === vscode.ExtensionKind.UI && @@ -54,83 +32,77 @@ function loadThemeNamed(themeName: string) { ); } - const themePaths = vscode.extensions.all + let themePaths = vscode.extensions.all .filter(isTheme) - .reduce((list, extension) => { - return extension.packageJSON.contributes.themes - .filter( - (element: any) => - (element.id || element.label) === themeName, - ) - .map((element: any) => - path.join(extension.extensionPath, element.path), - ) - .concat(list); - }, Array()); + .flatMap(ext => { + return ext.packageJSON.contributes.themes + .filter((it: any) => (it.id || it.label) === themeName) + .map((it: any) => path.join(ext.extensionPath, it.path)); + }) - themePaths.forEach(loadThemeFile); + const res = new Map(); + for (const themePath of themePaths) { + mergeInto(res, loadThemeFile(themePath)) + } - const tokenColorCustomizations: [any] = [ - vscode.workspace - .getConfiguration('editor') - .get('tokenColorCustomizations'), - ]; + const customizations: any = vscode.workspace.getConfiguration('editor').get('tokenColorCustomizations'); + mergeInto(res, loadColors(customizations?.textMateRules ?? [])) - tokenColorCustomizations - .filter(custom => custom && custom.textMateRules) - .map(custom => custom.textMateRules) - .forEach(loadColors); + return res; } -function loadThemeFile(themePath: string) { - const themeContent = [themePath] - .filter(it => fs.statSync(it).isFile()) - .map(it => fs.readFileSync(it, 'utf8')) - .map(it => jsonc.parse(it)) - .filter(theme => theme); +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); - themeContent - .filter(theme => theme.tokenColors) - .map(theme => theme.tokenColors) - .forEach(loadColors); + for (const include in obj?.include ?? []) { + const includePath = path.join(path.dirname(themePath), include); + const tmp = loadThemeFile(includePath); + mergeInto(res, tmp); + } - themeContent - .filter(theme => theme.include) - .map(theme => path.join(path.dirname(themePath), theme.include)) - .forEach(loadThemeFile); + 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 { - if (defaultSetting === undefined) { - return override; + return { + foreground: defaultSetting?.foreground ?? override.foreground, + background: defaultSetting?.background ?? override.background, + fontStyle: defaultSetting?.fontStyle ?? override.fontStyle, } - const mergedRule = defaultSetting; - - mergedRule.background = override.background || defaultSetting.background; - mergedRule.foreground = override.foreground || defaultSetting.foreground; - mergedRule.fontStyle = override.fontStyle || defaultSetting.foreground; - - return mergedRule; } -function updateRules( - scope: string, - updatedSettings: TextMateRuleSettings, -): void { - [rules.get(scope)] - .map(settings => mergeRuleSettings(settings, updatedSettings)) - .forEach(settings => rules.set(scope, settings)); -} - -function loadColors(textMateRules: TextMateRule[]): void { - textMateRules.forEach(rule => { - if (typeof rule.scope === 'string') { - updateRules(rule.scope, rule.settings); - } else if (rule.scope instanceof Array) { - rule.scope.forEach(scope => updateRules(scope, rule.settings)); - } - }); +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/tsconfig.json b/editors/code/tsconfig.json index fe3b40f347..e60eb8e5e5 100644 --- a/editors/code/tsconfig.json +++ b/editors/code/tsconfig.json @@ -4,7 +4,7 @@ "target": "es2018", "outDir": "out", "lib": [ - "es2018" + "es2019" ], "sourceMap": true, "rootDir": "src",