From 26bd7a896b4bbc4a2432df47dceff939aac921fa Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Tue, 31 Dec 2019 11:06:50 +0100 Subject: [PATCH] Drop support for legacy colorization --- crates/ra_ide/src/snapshots/highlighting.html | 6 +- .../src/snapshots/rainbow_highlighting.html | 6 +- crates/ra_ide/src/syntax_highlighting.rs | 27 ++-- 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 ----------- 8 files changed, 187 insertions(+), 271 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 diff --git a/crates/ra_ide/src/snapshots/highlighting.html b/crates/ra_ide/src/snapshots/highlighting.html index a097cf8e84d..1d130544fdc 100644 --- a/crates/ra_ide/src/snapshots/highlighting.html +++ b/crates/ra_ide/src/snapshots/highlighting.html @@ -38,12 +38,12 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd fn main() { println!("Hello, {}!", 92); - let mut vec = Vec::new(); + let mut vec = Vec::new(); if true { let x = 92; - vec.push(Foo { x, y: 1 }); + vec.push(Foo { x, y: 1 }); } - unsafe { vec.set_len(0); } + unsafe { vec.set_len(0); } let mut x = 42; let y = &mut x; diff --git a/crates/ra_ide/src/snapshots/rainbow_highlighting.html b/crates/ra_ide/src/snapshots/rainbow_highlighting.html index 110556c0921..d90ee85404f 100644 --- a/crates/ra_ide/src/snapshots/rainbow_highlighting.html +++ b/crates/ra_ide/src/snapshots/rainbow_highlighting.html @@ -25,11 +25,11 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
fn main() {
     let hello = "hello";
-    let x = hello.to_string();
-    let y = hello.to_string();
+    let x = hello.to_string();
+    let y = hello.to_string();
 
     let x = "other color please!";
-    let y = x.to_string();
+    let y = x.to_string();
 }
 
 fn bar() {
diff --git a/crates/ra_ide/src/syntax_highlighting.rs b/crates/ra_ide/src/syntax_highlighting.rs
index 0228ee7e90f..56a36f58739 100644
--- a/crates/ra_ide/src/syntax_highlighting.rs
+++ b/crates/ra_ide/src/syntax_highlighting.rs
@@ -20,13 +20,13 @@ pub mod tags {
     pub(crate) const FIELD: &str = "field";
     pub(crate) const FUNCTION: &str = "function";
     pub(crate) const MODULE: &str = "module";
-    pub(crate) const TYPE: &str = "type";
     pub(crate) const CONSTANT: &str = "constant";
     pub(crate) const MACRO: &str = "macro";
+
     pub(crate) const VARIABLE: &str = "variable";
     pub(crate) const VARIABLE_MUT: &str = "variable.mut";
-    pub(crate) const TEXT: &str = "text";
 
+    pub(crate) const TYPE: &str = "type";
     pub(crate) const TYPE_BUILTIN: &str = "type.builtin";
     pub(crate) const TYPE_SELF: &str = "type.self";
     pub(crate) const TYPE_PARAM: &str = "type.param";
@@ -35,13 +35,14 @@ pub mod tags {
     pub(crate) const LITERAL_BYTE: &str = "literal.byte";
     pub(crate) const LITERAL_NUMERIC: &str = "literal.numeric";
     pub(crate) const LITERAL_CHAR: &str = "literal.char";
+
     pub(crate) const LITERAL_COMMENT: &str = "comment";
     pub(crate) const LITERAL_STRING: &str = "string";
     pub(crate) const LITERAL_ATTRIBUTE: &str = "attribute";
 
+    pub(crate) const KEYWORD: &str = "keyword";
     pub(crate) const KEYWORD_UNSAFE: &str = "keyword.unsafe";
     pub(crate) const KEYWORD_CONTROL: &str = "keyword.control";
-    pub(crate) const KEYWORD: &str = "keyword";
 }
 
 #[derive(Debug)]
@@ -109,15 +110,21 @@ fn hash(x: T) -> u64 {
                 let name_ref = node.as_node().cloned().and_then(ast::NameRef::cast).unwrap();
                 let name_kind =
                     classify_name_ref(db, InFile::new(file_id.into(), &name_ref)).map(|d| d.kind);
+                match name_kind {
+                    Some(name_kind) => {
+                        if let Local(local) = &name_kind {
+                            if let Some(name) = local.name(db) {
+                                let shadow_count =
+                                    bindings_shadow_count.entry(name.clone()).or_default();
+                                binding_hash =
+                                    Some(calc_binding_hash(file_id, &name, *shadow_count))
+                            }
+                        };
 
-                if let Some(Local(local)) = &name_kind {
-                    if let Some(name) = local.name(db) {
-                        let shadow_count = bindings_shadow_count.entry(name.clone()).or_default();
-                        binding_hash = Some(calc_binding_hash(file_id, &name, *shadow_count))
+                        highlight_name(db, name_kind)
                     }
-                };
-
-                name_kind.map_or(tags::TEXT, |it| highlight_name(db, it))
+                    _ => continue,
+                }
             }
             NAME => {
                 let name = node.as_node().cloned().and_then(ast::Name::cast).unwrap();
diff --git a/editors/code/src/color_theme.ts b/editors/code/src/color_theme.ts
new file mode 100644
index 00000000000..1df7eba7a4a
--- /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 f63d1ddceaa..ccb0ee2b7ec 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 e97eb086a7c..d383d87ef93 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 73fabbf549a..00000000000
--- 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 1295ab47681..00000000000
--- 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);
-}
-- 
2.44.0