Switch impure functional style to pure imperative

This commit is contained in:
Aleksey Kladov 2019-12-31 03:33:00 +01:00
parent cfb0865929
commit f984ef2652
4 changed files with 66 additions and 94 deletions

View file

@ -1,5 +1,4 @@
import * as vscode from 'vscode'; import * as vscode from 'vscode';
import * as scopes from './scopes';
import * as scopesMapper from './scopes_mapper'; import * as scopesMapper from './scopes_mapper';
const RA_LSP_DEBUG = process.env.__RA_LSP_SERVER_DEBUG; const RA_LSP_DEBUG = process.env.__RA_LSP_SERVER_DEBUG;
@ -60,7 +59,6 @@ export class Config {
if (config.has('highlightingOn')) { if (config.has('highlightingOn')) {
this.highlightingOn = config.get('highlightingOn') as boolean; this.highlightingOn = config.get('highlightingOn') as boolean;
if (this.highlightingOn) { if (this.highlightingOn) {
scopes.load();
scopesMapper.load(); scopesMapper.load();
} }
} }

View file

@ -3,7 +3,7 @@ import * as lc from 'vscode-languageclient';
import * as seedrandom_ from 'seedrandom'; import * as seedrandom_ from 'seedrandom';
const seedrandom = seedrandom_; // https://github.com/jvandemo/generator-angular2-library/issues/221#issuecomment-355945207 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 * as scopesMapper from './scopes_mapper';
import { Ctx } from './ctx'; import { Ctx } from './ctx';
@ -172,11 +172,13 @@ function initDecorations(): Map<
string, string,
vscode.TextEditorDecorationType vscode.TextEditorDecorationType
> { > {
const themeColors = loadThemeColors();
const decoration = ( const decoration = (
tag: string, tag: string,
textDecoration?: string, textDecoration?: string,
): [string, vscode.TextEditorDecorationType] => { ): [string, vscode.TextEditorDecorationType] => {
const rule = scopesMapper.toRule(tag, scopes.find); const rule = scopesMapper.toRule(tag, it => themeColors.get(it));
if (rule) { if (rule) {
const decor = createDecorationFromTextmate(rule); const decor = createDecorationFromTextmate(rule);
@ -232,7 +234,7 @@ function initDecorations(): Map<
} }
function createDecorationFromTextmate( function createDecorationFromTextmate(
themeStyle: scopes.TextMateRuleSettings, themeStyle: TextMateRuleSettings,
): vscode.TextEditorDecorationType { ): vscode.TextEditorDecorationType {
const decorationOptions: vscode.DecorationRenderOptions = {}; const decorationOptions: vscode.DecorationRenderOptions = {};
decorationOptions.rangeBehavior = vscode.DecorationRangeBehavior.OpenOpen; decorationOptions.rangeBehavior = vscode.DecorationRangeBehavior.OpenOpen;

View file

@ -3,28 +3,14 @@ import * as jsonc from 'jsonc-parser';
import * as path from 'path'; import * as path from 'path';
import * as vscode from 'vscode'; import * as vscode from 'vscode';
export interface TextMateRule {
scope: string | string[];
settings: TextMateRuleSettings;
}
export interface TextMateRuleSettings { export interface TextMateRuleSettings {
foreground?: string; foreground?: string;
background?: string; background?: string;
fontStyle?: string; fontStyle?: string;
} }
// Current theme colors
const rules = new Map<string, TextMateRuleSettings>();
export function find(scope: string): TextMateRuleSettings | undefined {
return rules.get(scope);
}
// Load all textmate scopes in the currently active theme // Load all textmate scopes in the currently active theme
export function load() { export function loadThemeColors(): Map<string, TextMateRuleSettings> {
// Remove any previous theme
rules.clear();
// Find out current color theme // Find out current color theme
const themeName = vscode.workspace const themeName = vscode.workspace
.getConfiguration('workbench') .getConfiguration('workbench')
@ -32,20 +18,12 @@ export function load() {
if (typeof themeName !== 'string') { if (typeof themeName !== 'string') {
// console.warn('workbench.colorTheme is', themeName) // console.warn('workbench.colorTheme is', themeName)
return; return new Map();
}
// Try to load colors from that theme
try {
loadThemeNamed(themeName);
} catch (e) {
// console.warn('failed to load theme', themeName, e)
} }
return loadThemeNamed(themeName);
} }
function loadThemeNamed(themeName: string): Map<string, TextMateRuleSettings> {
// Find current theme on disk
function loadThemeNamed(themeName: string) {
function isTheme(extension: vscode.Extension<any>): boolean { function isTheme(extension: vscode.Extension<any>): boolean {
return ( return (
extension.extensionKind === vscode.ExtensionKind.UI && 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) .filter(isTheme)
.reduce((list, extension) => { .flatMap(ext => {
return extension.packageJSON.contributes.themes return ext.packageJSON.contributes.themes
.filter( .filter((it: any) => (it.id || it.label) === themeName)
(element: any) => .map((it: any) => path.join(ext.extensionPath, it.path));
(element.id || element.label) === themeName, })
)
.map((element: any) =>
path.join(extension.extensionPath, element.path),
)
.concat(list);
}, Array<string>());
themePaths.forEach(loadThemeFile); const res = new Map();
for (const themePath of themePaths) {
mergeInto(res, loadThemeFile(themePath))
}
const tokenColorCustomizations: [any] = [ const customizations: any = vscode.workspace.getConfiguration('editor').get('tokenColorCustomizations');
vscode.workspace mergeInto(res, loadColors(customizations?.textMateRules ?? []))
.getConfiguration('editor')
.get('tokenColorCustomizations'),
];
tokenColorCustomizations return res;
.filter(custom => custom && custom.textMateRules)
.map(custom => custom.textMateRules)
.forEach(loadColors);
} }
function loadThemeFile(themePath: string) { function loadThemeFile(themePath: string): Map<string, TextMateRuleSettings> {
const themeContent = [themePath] let text;
.filter(it => fs.statSync(it).isFile()) try {
.map(it => fs.readFileSync(it, 'utf8')) text = fs.readFileSync(themePath, 'utf8')
.map(it => jsonc.parse(it)) } catch {
.filter(theme => theme); return new Map();
}
const obj = jsonc.parse(text);
const tokenColors = obj?.tokenColors ?? [];
const res = loadColors(tokenColors);
themeContent for (const include in obj?.include ?? []) {
.filter(theme => theme.tokenColors) const includePath = path.join(path.dirname(themePath), include);
.map(theme => theme.tokenColors) const tmp = loadThemeFile(includePath);
.forEach(loadColors); mergeInto(res, tmp);
}
themeContent return res;
.filter(theme => theme.include) }
.map(theme => path.join(path.dirname(themePath), theme.include))
.forEach(loadThemeFile); interface TextMateRule {
scope: string | string[];
settings: TextMateRuleSettings;
}
function loadColors(textMateRules: TextMateRule[]): Map<string, TextMateRuleSettings> {
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( function mergeRuleSettings(
defaultSetting: TextMateRuleSettings | undefined, defaultSetting: TextMateRuleSettings | undefined,
override: TextMateRuleSettings, override: TextMateRuleSettings,
): TextMateRuleSettings { ): TextMateRuleSettings {
if (defaultSetting === undefined) { return {
return override; 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( function mergeInto(dst: Map<string, TextMateRuleSettings>, addition: Map<string, TextMateRuleSettings>) {
scope: string, addition.forEach((value, key) => {
updatedSettings: TextMateRuleSettings, const merged = mergeRuleSettings(dst.get(key), value)
): void { dst.set(key, merged)
[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));
}
});
} }

View file

@ -4,7 +4,7 @@
"target": "es2018", "target": "es2018",
"outDir": "out", "outDir": "out",
"lib": [ "lib": [
"es2018" "es2019"
], ],
"sourceMap": true, "sourceMap": true,
"rootDir": "src", "rootDir": "src",