]> git.lizzy.rs Git - rust.git/blob - editors/code/src/highlighting.ts
removed `type.alias`
[rust.git] / editors / code / src / highlighting.ts
1 import seedrandom = require('seedrandom');
2 import * as vscode from 'vscode';
3 import * as lc from 'vscode-languageclient';
4
5 import { Server } from './server';
6
7 export interface Decoration {
8     range: lc.Range;
9     tag: string;
10     bindingHash?: string;
11 }
12
13 // Based on this HSL-based color generator: https://gist.github.com/bendc/76c48ce53299e6078a76
14 function fancify(seed: string, shade: 'light' | 'dark') {
15     const random = seedrandom(seed);
16     const randomInt = (min: number, max: number) => {
17         return Math.floor(random() * (max - min + 1)) + min;
18     };
19
20     const h = randomInt(0, 360);
21     const s = randomInt(42, 98);
22     const l = shade === 'light' ? randomInt(15, 40) : randomInt(40, 90);
23     return `hsl(${h},${s}%,${l}%)`;
24 }
25
26 export class Highlighter {
27     private static initDecorations(): Map<
28         string,
29         vscode.TextEditorDecorationType
30     > {
31         const decoration = (
32             tag: string,
33             textDecoration?: string,
34         ): [string, vscode.TextEditorDecorationType] => {
35             const color = new vscode.ThemeColor('ralsp.' + tag);
36             const decor = vscode.window.createTextEditorDecorationType({
37                 color,
38                 textDecoration,
39             });
40             return [tag, decor];
41         };
42
43         const decorations: Iterable<[
44             string,
45             vscode.TextEditorDecorationType,
46         ]> = [
47             decoration('comment'),
48             decoration('string'),
49             decoration('keyword'),
50             decoration('keyword.control'),
51             decoration('keyword.unsafe'),
52             decoration('function'),
53             decoration('parameter'),
54             decoration('constant'),
55             decoration('type'),
56             decoration('type.self'),
57             decoration('type.generic'),
58             decoration('type.param'),
59             decoration('type.lifetime'),
60             decoration('builtin'),
61             decoration('text'),
62             decoration('attribute'),
63             decoration('literal'),
64             decoration('literal.numeric'),
65             decoration('literal.char'),
66             decoration('literal.byte'),
67             decoration('macro'),
68             decoration('variable'),
69             decoration('variable.mut', 'underline'),
70             decoration('field'),
71             decoration('module'),
72         ];
73
74         return new Map<string, vscode.TextEditorDecorationType>(decorations);
75     }
76
77     private decorations: Map<
78         string,
79         vscode.TextEditorDecorationType
80     > | null = null;
81
82     public removeHighlights() {
83         if (this.decorations == null) {
84             return;
85         }
86
87         // Decorations are removed when the object is disposed
88         for (const decoration of this.decorations.values()) {
89             decoration.dispose();
90         }
91
92         this.decorations = null;
93     }
94
95     public setHighlights(editor: vscode.TextEditor, highlights: Decoration[]) {
96         // Initialize decorations if necessary
97         //
98         // Note: decoration objects need to be kept around so we can dispose them
99         // if the user disables syntax highlighting
100         if (this.decorations == null) {
101             this.decorations = Highlighter.initDecorations();
102         }
103
104         const byTag: Map<string, vscode.Range[]> = new Map();
105         const colorfulIdents: Map<
106             string,
107             [vscode.Range[], boolean]
108         > = new Map();
109         const rainbowTime = Server.config.rainbowHighlightingOn;
110
111         for (const tag of this.decorations.keys()) {
112             byTag.set(tag, []);
113         }
114
115         for (const d of highlights) {
116             if (!byTag.get(d.tag)) {
117                 continue;
118             }
119
120             if (rainbowTime && d.bindingHash) {
121                 if (!colorfulIdents.has(d.bindingHash)) {
122                     const mut = d.tag.endsWith('.mut');
123                     colorfulIdents.set(d.bindingHash, [[], mut]);
124                 }
125                 colorfulIdents
126                     .get(d.bindingHash)![0]
127                     .push(
128                         Server.client.protocol2CodeConverter.asRange(d.range),
129                     );
130             } else {
131                 byTag
132                     .get(d.tag)!
133                     .push(
134                         Server.client.protocol2CodeConverter.asRange(d.range),
135                     );
136             }
137         }
138
139         for (const tag of byTag.keys()) {
140             const dec = this.decorations.get(
141                 tag,
142             ) as vscode.TextEditorDecorationType;
143             const ranges = byTag.get(tag)!;
144             editor.setDecorations(dec, ranges);
145         }
146
147         for (const [hash, [ranges, mut]] of colorfulIdents.entries()) {
148             const textDecoration = mut ? 'underline' : undefined;
149             const dec = vscode.window.createTextEditorDecorationType({
150                 light: { color: fancify(hash, 'light'), textDecoration },
151                 dark: { color: fancify(hash, 'dark'), textDecoration },
152             });
153             editor.setDecorations(dec, ranges);
154         }
155     }
156 }