aboutsummaryrefslogtreecommitdiff
path: root/editors/code
diff options
context:
space:
mode:
Diffstat (limited to 'editors/code')
-rw-r--r--editors/code/package-lock.json11
-rw-r--r--editors/code/package.json144
-rw-r--r--editors/code/src/client.ts16
-rw-r--r--editors/code/src/config.ts2
-rw-r--r--editors/code/src/inlay_hints.ts2
-rw-r--r--editors/code/src/installation/download_artifact.ts30
-rw-r--r--editors/code/src/installation/download_file.ts3
-rw-r--r--editors/code/src/installation/server.ts3
-rw-r--r--editors/code/src/main.ts4
-rw-r--r--editors/code/src/util.ts17
10 files changed, 183 insertions, 49 deletions
diff --git a/editors/code/package-lock.json b/editors/code/package-lock.json
index 0288a468e..6901363fc 100644
--- a/editors/code/package-lock.json
+++ b/editors/code/package-lock.json
@@ -112,12 +112,6 @@
112 "@types/node": "*" 112 "@types/node": "*"
113 } 113 }
114 }, 114 },
115 "@types/throttle-debounce": {
116 "version": "2.1.0",
117 "resolved": "https://registry.npmjs.org/@types/throttle-debounce/-/throttle-debounce-2.1.0.tgz",
118 "integrity": "sha512-5eQEtSCoESnh2FsiLTxE121IiE60hnMqcb435fShf4bpLRjEu1Eoekht23y6zXS9Ts3l+Szu3TARnTsA0GkOkQ==",
119 "dev": true
120 },
121 "@types/vscode": { 115 "@types/vscode": {
122 "version": "1.42.0", 116 "version": "1.42.0",
123 "resolved": "https://registry.npmjs.org/@types/vscode/-/vscode-1.42.0.tgz", 117 "resolved": "https://registry.npmjs.org/@types/vscode/-/vscode-1.42.0.tgz",
@@ -1517,11 +1511,6 @@
1517 "integrity": "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=", 1511 "integrity": "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=",
1518 "dev": true 1512 "dev": true
1519 }, 1513 },
1520 "throttle-debounce": {
1521 "version": "2.1.0",
1522 "resolved": "https://registry.npmjs.org/throttle-debounce/-/throttle-debounce-2.1.0.tgz",
1523 "integrity": "sha512-AOvyNahXQuU7NN+VVvOOX+uW6FPaWdAOdRP5HfwYxAfCzXTFKRMoIMk+n+po318+ktcChx+F1Dd91G3YHeMKyg=="
1524 },
1525 "through": { 1514 "through": {
1526 "version": "2.3.8", 1515 "version": "2.3.8",
1527 "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", 1516 "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz",
diff --git a/editors/code/package.json b/editors/code/package.json
index dff535fcd..862de3210 100644
--- a/editors/code/package.json
+++ b/editors/code/package.json
@@ -18,16 +18,17 @@
18 "engines": { 18 "engines": {
19 "vscode": "^1.42.0" 19 "vscode": "^1.42.0"
20 }, 20 },
21 "enableProposedApi": true,
21 "scripts": { 22 "scripts": {
22 "vscode:prepublish": "tsc && rollup -c", 23 "vscode:prepublish": "tsc && rollup -c",
23 "package": "vsce package -o rust-analyzer.vsix", 24 "package": "vsce package -o rust-analyzer.vsix",
24 "watch": "tsc --watch", 25 "watch": "tsc --watch",
25 "fmt": "tsfmt -r && eslint -c .eslintrc.js --ext ts ./src/ --fix" 26 "lint": "tsfmt --verify && eslint -c .eslintrc.js --ext ts ./src",
27 "fix": " tsfmt -r && eslint -c .eslintrc.js --ext ts ./src --fix"
26 }, 28 },
27 "dependencies": { 29 "dependencies": {
28 "jsonc-parser": "^2.1.0", 30 "jsonc-parser": "^2.1.0",
29 "node-fetch": "^2.6.0", 31 "node-fetch": "^2.6.0",
30 "throttle-debounce": "^2.1.0",
31 "vscode-languageclient": "^6.1.1" 32 "vscode-languageclient": "^6.1.1"
32 }, 33 },
33 "devDependencies": { 34 "devDependencies": {
@@ -35,7 +36,6 @@
35 "@rollup/plugin-node-resolve": "^7.1.1", 36 "@rollup/plugin-node-resolve": "^7.1.1",
36 "@types/node": "^12.12.27", 37 "@types/node": "^12.12.27",
37 "@types/node-fetch": "^2.5.4", 38 "@types/node-fetch": "^2.5.4",
38 "@types/throttle-debounce": "^2.1.0",
39 "@types/vscode": "^1.42.0", 39 "@types/vscode": "^1.42.0",
40 "@typescript-eslint/eslint-plugin": "^2.20.0", 40 "@typescript-eslint/eslint-plugin": "^2.20.0",
41 "@typescript-eslint/parser": "^2.20.0", 41 "@typescript-eslint/parser": "^2.20.0",
@@ -155,20 +155,20 @@
155 "when": "editorTextFocus && editorLangId == rust" 155 "when": "editorTextFocus && editorLangId == rust"
156 }, 156 },
157 { 157 {
158 "command": "rust-analyzer.run",
159 "key": "ctrl+r",
160 "when": "editorTextFocus && editorLangId == rust"
161 },
162 {
163 "command": "rust-analyzer.onEnter", 158 "command": "rust-analyzer.onEnter",
164 "key": "enter", 159 "key": "enter",
165 "when": "editorTextFocus && !suggestWidgetVisible && editorLangId == rust" 160 "when": "editorTextFocus && !suggestWidgetVisible && editorLangId == rust && !vim.active || vim.mode == 'Insert' && editorTextFocus && !suggestWidgetVisible && editorLangId == rust"
166 } 161 }
167 ], 162 ],
168 "configuration": { 163 "configuration": {
169 "type": "object", 164 "type": "object",
170 "title": "Rust Analyzer", 165 "title": "Rust Analyzer",
171 "properties": { 166 "properties": {
167 "rust-analyzer.highlighting.semanticTokens": {
168 "type": "boolean",
169 "default": false,
170 "description": "Use proposed semantic tokens API for syntax highlighting"
171 },
172 "rust-analyzer.highlightingOn": { 172 "rust-analyzer.highlightingOn": {
173 "type": "boolean", 173 "type": "boolean",
174 "default": false, 174 "default": false,
@@ -182,7 +182,29 @@
182 "rust-analyzer.featureFlags": { 182 "rust-analyzer.featureFlags": {
183 "type": "object", 183 "type": "object",
184 "default": {}, 184 "default": {},
185 "description": "Fine grained feature flags to disable annoying features" 185 "description": "Fine grained feature flags to disable annoying features",
186 "properties": {
187 "lsp.diagnostics": {
188 "type": "boolean",
189 "description": "Whether to show diagnostics from `cargo check`"
190 },
191 "completion.insertion.add-call-parenthesis": {
192 "type": "boolean",
193 "description": "Whether to add parenthesis when completing functions"
194 },
195 "completion.enable-postfix": {
196 "type": "boolean",
197 "description": "Whether to show postfix snippets like `dbg`, `if`, `not`, etc."
198 },
199 "notifications.workspace-loaded": {
200 "type": "boolean",
201 "description": "Whether to show `workspace loaded` message"
202 },
203 "notifications.cargo-toml-not-found": {
204 "type": "boolean",
205 "description": "Whether to show `can't find Cargo.toml` error message"
206 }
207 }
186 }, 208 },
187 "rust-analyzer.serverPath": { 209 "rust-analyzer.serverPath": {
188 "type": [ 210 "type": [
@@ -375,6 +397,108 @@
375 "highContrast": "#BEBEBE" 397 "highContrast": "#BEBEBE"
376 } 398 }
377 } 399 }
400 ],
401 "semanticTokenTypes": [
402 {
403 "id": "attribute",
404 "description": "Style for attributes"
405 },
406 {
407 "id": "builtinType",
408 "description": "Style for builtin types"
409 },
410 {
411 "id": "lifetime",
412 "description": "Style for lifetimes"
413 },
414 {
415 "id": "typeAlias",
416 "description": "Style for type aliases"
417 },
418 {
419 "id": "union",
420 "description": "Style for C-style untagged unions"
421 }
422 ],
423 "semanticTokenModifiers": [
424 {
425 "id": "constant",
426 "description": "Style for compile-time constants"
427 },
428 {
429 "id": "control",
430 "description": "Style for control flow keywords"
431 },
432 {
433 "id": "mutable",
434 "description": "Style for mutable bindings"
435 },
436 {
437 "id": "unsafe",
438 "description": "Style for unsafe operations"
439 }
440 ],
441 "semanticTokenStyleDefaults": [
442 {
443 "selector": "attribute",
444 "scope": [
445 "meta.attribute"
446 ]
447 },
448 {
449 "selector": "builtinType",
450 "scope": [
451 "support.type.primitive"
452 ]
453 },
454 {
455 "selector": "lifetime",
456 "scope": [
457 "entity.name.lifetime.rust"
458 ]
459 },
460 {
461 "selector": "typeAlias",
462 "scope": [
463 "entity.name.typeAlias"
464 ]
465 },
466 {
467 "selector": "union",
468 "scope": [
469 "entity.name.union"
470 ]
471 },
472 {
473 "selector": "keyword.unsafe",
474 "scope": [
475 "keyword.other.unsafe"
476 ]
477 },
478 {
479 "selector": "keyword.control",
480 "scope": [
481 "keyword.control"
482 ]
483 },
484 {
485 "selector": "variable.constant",
486 "scope": [
487 "entity.name.constant"
488 ]
489 },
490 {
491 "selector": "*.mutable",
492 "light": {
493 "fontStyle": "underline"
494 },
495 "dark": {
496 "fontStyle": "underline"
497 },
498 "highContrast": {
499 "fontStyle": "underline"
500 }
501 }
378 ] 502 ]
379 } 503 }
380} 504}
diff --git a/editors/code/src/client.ts b/editors/code/src/client.ts
index aaf2ef40e..540f7c9ea 100644
--- a/editors/code/src/client.ts
+++ b/editors/code/src/client.ts
@@ -3,6 +3,7 @@ import * as vscode from 'vscode';
3 3
4import { Config } from './config'; 4import { Config } from './config';
5import { CallHierarchyFeature } from 'vscode-languageclient/lib/callHierarchy.proposed'; 5import { CallHierarchyFeature } from 'vscode-languageclient/lib/callHierarchy.proposed';
6import { SemanticTokensFeature, DocumentSemanticsTokensSignature } from 'vscode-languageclient/lib/semanticTokens.proposed';
6 7
7export async function createClient(config: Config, serverPath: string): Promise<lc.LanguageClient> { 8export async function createClient(config: Config, serverPath: string): Promise<lc.LanguageClient> {
8 // '.' Is the fallback if no folder is open 9 // '.' Is the fallback if no folder is open
@@ -26,7 +27,7 @@ export async function createClient(config: Config, serverPath: string): Promise<
26 const clientOptions: lc.LanguageClientOptions = { 27 const clientOptions: lc.LanguageClientOptions = {
27 documentSelector: [{ scheme: 'file', language: 'rust' }], 28 documentSelector: [{ scheme: 'file', language: 'rust' }],
28 initializationOptions: { 29 initializationOptions: {
29 publishDecorations: true, 30 publishDecorations: !config.highlightingSemanticTokens,
30 lruCapacity: config.lruCapacity, 31 lruCapacity: config.lruCapacity,
31 maxInlayHintLength: config.maxInlayHintLength, 32 maxInlayHintLength: config.maxInlayHintLength,
32 cargoWatchEnable: cargoWatchOpts.enable, 33 cargoWatchEnable: cargoWatchOpts.enable,
@@ -41,6 +42,14 @@ export async function createClient(config: Config, serverPath: string): Promise<
41 rustfmtArgs: config.rustfmtArgs, 42 rustfmtArgs: config.rustfmtArgs,
42 }, 43 },
43 traceOutputChannel, 44 traceOutputChannel,
45 middleware: {
46 // Workaround for https://github.com/microsoft/vscode-languageserver-node/issues/576
47 async provideDocumentSemanticTokens(document: vscode.TextDocument, token: vscode.CancellationToken, next: DocumentSemanticsTokensSignature) {
48 const res = await next(document, token);
49 if (res === undefined) throw new Error('busy');
50 return res;
51 }
52 } as any
44 }; 53 };
45 54
46 const res = new lc.LanguageClient( 55 const res = new lc.LanguageClient(
@@ -83,5 +92,10 @@ export async function createClient(config: Config, serverPath: string): Promise<
83 // Here we want to just enable CallHierarchyFeature since it is available on stable. 92 // Here we want to just enable CallHierarchyFeature since it is available on stable.
84 // Note that while the CallHierarchyFeature is stable the LSP protocol is not. 93 // Note that while the CallHierarchyFeature is stable the LSP protocol is not.
85 res.registerFeature(new CallHierarchyFeature(res)); 94 res.registerFeature(new CallHierarchyFeature(res));
95
96 if (config.highlightingSemanticTokens) {
97 res.registerFeature(new SemanticTokensFeature(res));
98 }
99
86 return res; 100 return res;
87} 101}
diff --git a/editors/code/src/config.ts b/editors/code/src/config.ts
index 47e8cd45d..bf915102c 100644
--- a/editors/code/src/config.ts
+++ b/editors/code/src/config.ts
@@ -22,6 +22,7 @@ export class Config {
22 private static readonly requiresReloadOpts = [ 22 private static readonly requiresReloadOpts = [
23 "cargoFeatures", 23 "cargoFeatures",
24 "cargo-watch", 24 "cargo-watch",
25 "highlighting.semanticTokens"
25 ] 26 ]
26 .map(opt => `${Config.rootSection}.${opt}`); 27 .map(opt => `${Config.rootSection}.${opt}`);
27 28
@@ -143,6 +144,7 @@ export class Config {
143 // We don't do runtime config validation here for simplicity. More on stackoverflow: 144 // We don't do runtime config validation here for simplicity. More on stackoverflow:
144 // https://stackoverflow.com/questions/60135780/what-is-the-best-way-to-type-check-the-configuration-for-vscode-extension 145 // https://stackoverflow.com/questions/60135780/what-is-the-best-way-to-type-check-the-configuration-for-vscode-extension
145 146
147 get highlightingSemanticTokens() { return this.cfg.get("highlighting.semanticTokens") as boolean; }
146 get highlightingOn() { return this.cfg.get("highlightingOn") as boolean; } 148 get highlightingOn() { return this.cfg.get("highlightingOn") as boolean; }
147 get rainbowHighlightingOn() { return this.cfg.get("rainbowHighlightingOn") as boolean; } 149 get rainbowHighlightingOn() { return this.cfg.get("rainbowHighlightingOn") as boolean; }
148 get lruCapacity() { return this.cfg.get("lruCapacity") as null | number; } 150 get lruCapacity() { return this.cfg.get("lruCapacity") as null | number; }
diff --git a/editors/code/src/inlay_hints.ts b/editors/code/src/inlay_hints.ts
index 5951cf1b4..6871bc111 100644
--- a/editors/code/src/inlay_hints.ts
+++ b/editors/code/src/inlay_hints.ts
@@ -42,12 +42,14 @@ export function activateInlayHints(ctx: Ctx) {
42const typeHintDecorationType = vscode.window.createTextEditorDecorationType({ 42const typeHintDecorationType = vscode.window.createTextEditorDecorationType({
43 after: { 43 after: {
44 color: new vscode.ThemeColor('rust_analyzer.inlayHint'), 44 color: new vscode.ThemeColor('rust_analyzer.inlayHint'),
45 fontStyle: "normal",
45 }, 46 },
46}); 47});
47 48
48const parameterHintDecorationType = vscode.window.createTextEditorDecorationType({ 49const parameterHintDecorationType = vscode.window.createTextEditorDecorationType({
49 before: { 50 before: {
50 color: new vscode.ThemeColor('rust_analyzer.inlayHint'), 51 color: new vscode.ThemeColor('rust_analyzer.inlayHint'),
52 fontStyle: "normal",
51 }, 53 },
52}); 54});
53 55
diff --git a/editors/code/src/installation/download_artifact.ts b/editors/code/src/installation/download_artifact.ts
index 356723aba..97e4d67c2 100644
--- a/editors/code/src/installation/download_artifact.ts
+++ b/editors/code/src/installation/download_artifact.ts
@@ -1,11 +1,10 @@
1import * as vscode from "vscode"; 1import * as vscode from "vscode";
2import * as path from "path"; 2import * as path from "path";
3import { promises as fs } from "fs"; 3import { promises as fs } from "fs";
4import { strict as assert } from "assert";
5 4
6import { ArtifactReleaseInfo } from "./interfaces"; 5import { ArtifactReleaseInfo } from "./interfaces";
7import { downloadFile } from "./download_file"; 6import { downloadFile } from "./download_file";
8import { throttle } from "throttle-debounce"; 7import { assert } from "../util";
9 8
10/** 9/**
11 * Downloads artifact from given `downloadUrl`. 10 * Downloads artifact from given `downloadUrl`.
@@ -20,11 +19,10 @@ export async function downloadArtifact(
20 installationDir: string, 19 installationDir: string,
21 displayName: string, 20 displayName: string,
22) { 21) {
23 await fs.mkdir(installationDir).catch(err => assert.strictEqual( 22 await fs.mkdir(installationDir).catch(err => assert(
24 err?.code, 23 err?.code === "EEXIST",
25 "EEXIST",
26 `Couldn't create directory "${installationDir}" to download ` + 24 `Couldn't create directory "${installationDir}" to download ` +
27 `${artifactFileName} artifact: ${err.message}` 25 `${artifactFileName} artifact: ${err?.message}`
28 )); 26 ));
29 27
30 const installationPath = path.join(installationDir, artifactFileName); 28 const installationPath = path.join(installationDir, artifactFileName);
@@ -38,19 +36,15 @@ export async function downloadArtifact(
38 async (progress, _cancellationToken) => { 36 async (progress, _cancellationToken) => {
39 let lastPrecentage = 0; 37 let lastPrecentage = 0;
40 const filePermissions = 0o755; // (rwx, r_x, r_x) 38 const filePermissions = 0o755; // (rwx, r_x, r_x)
41 await downloadFile(downloadUrl, installationPath, filePermissions, throttle( 39 await downloadFile(downloadUrl, installationPath, filePermissions, (readBytes, totalBytes) => {
42 200, 40 const newPercentage = (readBytes / totalBytes) * 100;
43 /* noTrailing: */ true, 41 progress.report({
44 (readBytes, totalBytes) => { 42 message: newPercentage.toFixed(0) + "%",
45 const newPercentage = (readBytes / totalBytes) * 100; 43 increment: newPercentage - lastPrecentage
46 progress.report({ 44 });
47 message: newPercentage.toFixed(0) + "%",
48 increment: newPercentage - lastPrecentage
49 });
50 45
51 lastPrecentage = newPercentage; 46 lastPrecentage = newPercentage;
52 }) 47 });
53 );
54 } 48 }
55 ); 49 );
56} 50}
diff --git a/editors/code/src/installation/download_file.ts b/editors/code/src/installation/download_file.ts
index 319cb995c..ee8949d61 100644
--- a/editors/code/src/installation/download_file.ts
+++ b/editors/code/src/installation/download_file.ts
@@ -2,8 +2,7 @@ import fetch from "node-fetch";
2import * as fs from "fs"; 2import * as fs from "fs";
3import * as stream from "stream"; 3import * as stream from "stream";
4import * as util from "util"; 4import * as util from "util";
5import { strict as assert } from "assert"; 5import { log, assert } from "../util";
6import { log } from "../util";
7 6
8const pipeline = util.promisify(stream.pipeline); 7const pipeline = util.promisify(stream.pipeline);
9 8
diff --git a/editors/code/src/installation/server.ts b/editors/code/src/installation/server.ts
index cb5e56844..6a6cf4f8c 100644
--- a/editors/code/src/installation/server.ts
+++ b/editors/code/src/installation/server.ts
@@ -1,13 +1,12 @@
1import * as vscode from "vscode"; 1import * as vscode from "vscode";
2import * as path from "path"; 2import * as path from "path";
3import { strict as assert } from "assert";
4import { promises as dns } from "dns"; 3import { promises as dns } from "dns";
5import { spawnSync } from "child_process"; 4import { spawnSync } from "child_process";
6 5
7import { BinarySource } from "./interfaces"; 6import { BinarySource } from "./interfaces";
8import { fetchArtifactReleaseInfo } from "./fetch_artifact_release_info"; 7import { fetchArtifactReleaseInfo } from "./fetch_artifact_release_info";
9import { downloadArtifact } from "./download_artifact"; 8import { downloadArtifact } from "./download_artifact";
10import { log } from "../util"; 9import { log, assert } from "../util";
11 10
12export async function ensureServerBinary(source: null | BinarySource): Promise<null | string> { 11export async function ensureServerBinary(source: null | BinarySource): Promise<null | string> {
13 if (!source) { 12 if (!source) {
diff --git a/editors/code/src/main.ts b/editors/code/src/main.ts
index 424ff1ac3..ecf53cf77 100644
--- a/editors/code/src/main.ts
+++ b/editors/code/src/main.ts
@@ -89,7 +89,9 @@ export async function activate(context: vscode.ExtensionContext) {
89 89
90 activateStatusDisplay(ctx); 90 activateStatusDisplay(ctx);
91 91
92 activateHighlighting(ctx); 92 if (!ctx.config.highlightingSemanticTokens) {
93 activateHighlighting(ctx);
94 }
93 activateInlayHints(ctx); 95 activateInlayHints(ctx);
94} 96}
95 97
diff --git a/editors/code/src/util.ts b/editors/code/src/util.ts
index 68c2a94d0..f56c6bada 100644
--- a/editors/code/src/util.ts
+++ b/editors/code/src/util.ts
@@ -1,22 +1,31 @@
1import * as lc from "vscode-languageclient"; 1import * as lc from "vscode-languageclient";
2import * as vscode from "vscode"; 2import * as vscode from "vscode";
3import { strict as nativeAssert } from "assert";
3 4
4let enabled: boolean = false; 5export function assert(condition: boolean, explanation: string): asserts condition {
6 try {
7 nativeAssert(condition, explanation);
8 } catch (err) {
9 log.error(`Assertion failed:`, explanation);
10 throw err;
11 }
12}
5 13
6export const log = { 14export const log = {
15 enabled: true,
7 debug(message?: any, ...optionalParams: any[]): void { 16 debug(message?: any, ...optionalParams: any[]): void {
8 if (!enabled) return; 17 if (!log.enabled) return;
9 // eslint-disable-next-line no-console 18 // eslint-disable-next-line no-console
10 console.log(message, ...optionalParams); 19 console.log(message, ...optionalParams);
11 }, 20 },
12 error(message?: any, ...optionalParams: any[]): void { 21 error(message?: any, ...optionalParams: any[]): void {
13 if (!enabled) return; 22 if (!log.enabled) return;
14 debugger; 23 debugger;
15 // eslint-disable-next-line no-console 24 // eslint-disable-next-line no-console
16 console.error(message, ...optionalParams); 25 console.error(message, ...optionalParams);
17 }, 26 },
18 setEnabled(yes: boolean): void { 27 setEnabled(yes: boolean): void {
19 enabled = yes; 28 log.enabled = yes;
20 } 29 }
21}; 30};
22 31