aboutsummaryrefslogtreecommitdiff
path: root/editors/code/src
diff options
context:
space:
mode:
authorSeivan Heidari <[email protected]>2019-12-23 14:35:31 +0000
committerSeivan Heidari <[email protected]>2019-12-23 14:35:31 +0000
commitb21d9337d9200e2cfdc90b386591c72c302dc03e (patch)
treef81f5c08f821115cee26fa4d3ceaae88c7807fd5 /editors/code/src
parent18a0937585b836ec5ed054b9ae48e0156ab6d9ef (diff)
parentce07a2daa9e53aa86a769f8641b14c2878444fbc (diff)
Merge branch 'master' into feature/themes
Diffstat (limited to 'editors/code/src')
-rw-r--r--editors/code/src/commands/analyzer_status.ts14
-rw-r--r--editors/code/src/commands/apply_source_change.ts8
-rw-r--r--editors/code/src/commands/cargo_watch.ts49
-rw-r--r--editors/code/src/commands/expand_macro.ts10
-rw-r--r--editors/code/src/commands/index.ts2
-rw-r--r--editors/code/src/commands/inlay_hints.ts34
-rw-r--r--editors/code/src/commands/join_lines.ts6
-rw-r--r--editors/code/src/commands/matching_brace.ts6
-rw-r--r--editors/code/src/commands/on_enter.ts8
-rw-r--r--editors/code/src/commands/parent_module.ts6
-rw-r--r--editors/code/src/commands/runnables.ts52
-rw-r--r--editors/code/src/commands/syntaxTree.ts10
-rw-r--r--editors/code/src/commands/watch_status.ts2
-rw-r--r--editors/code/src/config.ts113
-rw-r--r--editors/code/src/events/change_active_text_editor.ts6
-rw-r--r--editors/code/src/events/change_text_document.ts2
-rw-r--r--editors/code/src/extension.ts73
-rw-r--r--editors/code/src/highlighting.ts30
-rw-r--r--editors/code/src/notifications/publish_decorations.ts11
-rw-r--r--editors/code/src/server.ts39
-rw-r--r--editors/code/src/test/fixtures/rust-diagnostics/error/E0277.json261
-rw-r--r--editors/code/src/test/utils/diagnotics/SuggestedFix.test.ts29
-rw-r--r--editors/code/src/test/utils/diagnotics/SuggestedFixCollection.test.ts26
-rw-r--r--editors/code/src/test/utils/diagnotics/rust.test.ts92
-rw-r--r--editors/code/src/test/utils/diagnotics/vscode.test.ts24
-rw-r--r--editors/code/src/test/utils/index.ts2
-rw-r--r--editors/code/src/utils/diagnostics/SuggestedFix.ts4
-rw-r--r--editors/code/src/utils/diagnostics/SuggestedFixCollection.ts6
-rw-r--r--editors/code/src/utils/diagnostics/rust.ts58
-rw-r--r--editors/code/src/utils/diagnostics/vscode.ts2
-rw-r--r--editors/code/src/utils/processes.ts4
31 files changed, 715 insertions, 274 deletions
diff --git a/editors/code/src/commands/analyzer_status.ts b/editors/code/src/commands/analyzer_status.ts
index 63f82c92d..2777ced24 100644
--- a/editors/code/src/commands/analyzer_status.ts
+++ b/editors/code/src/commands/analyzer_status.ts
@@ -9,7 +9,7 @@ export class TextDocumentContentProvider
9 public syntaxTree: string = 'Not available'; 9 public syntaxTree: string = 'Not available';
10 10
11 public provideTextDocumentContent( 11 public provideTextDocumentContent(
12 uri: vscode.Uri 12 _uri: vscode.Uri,
13 ): vscode.ProviderResult<string> { 13 ): vscode.ProviderResult<string> {
14 const editor = vscode.window.activeTextEditor; 14 const editor = vscode.window.activeTextEditor;
15 if (editor == null) { 15 if (editor == null) {
@@ -17,7 +17,7 @@ export class TextDocumentContentProvider
17 } 17 }
18 return Server.client.sendRequest<string>( 18 return Server.client.sendRequest<string>(
19 'rust-analyzer/analyzerStatus', 19 'rust-analyzer/analyzerStatus',
20 null 20 null,
21 ); 21 );
22 } 22 }
23 23
@@ -35,8 +35,8 @@ export function makeCommand(context: vscode.ExtensionContext) {
35 context.subscriptions.push( 35 context.subscriptions.push(
36 vscode.workspace.registerTextDocumentContentProvider( 36 vscode.workspace.registerTextDocumentContentProvider(
37 'rust-analyzer-status', 37 'rust-analyzer-status',
38 textDocumentContentProvider 38 textDocumentContentProvider,
39 ) 39 ),
40 ); 40 );
41 41
42 context.subscriptions.push({ 42 context.subscriptions.push({
@@ -44,21 +44,21 @@ export function makeCommand(context: vscode.ExtensionContext) {
44 if (poller != null) { 44 if (poller != null) {
45 clearInterval(poller); 45 clearInterval(poller);
46 } 46 }
47 } 47 },
48 }); 48 });
49 49
50 return async function handle() { 50 return async function handle() {
51 if (poller == null) { 51 if (poller == null) {
52 poller = setInterval( 52 poller = setInterval(
53 () => textDocumentContentProvider.eventEmitter.fire(statusUri), 53 () => textDocumentContentProvider.eventEmitter.fire(statusUri),
54 1000 54 1000,
55 ); 55 );
56 } 56 }
57 const document = await vscode.workspace.openTextDocument(statusUri); 57 const document = await vscode.workspace.openTextDocument(statusUri);
58 return vscode.window.showTextDocument( 58 return vscode.window.showTextDocument(
59 document, 59 document,
60 vscode.ViewColumn.Two, 60 vscode.ViewColumn.Two,
61 true 61 true,
62 ); 62 );
63 }; 63 };
64} 64}
diff --git a/editors/code/src/commands/apply_source_change.ts b/editors/code/src/commands/apply_source_change.ts
index dcd074b8b..8167398b1 100644
--- a/editors/code/src/commands/apply_source_change.ts
+++ b/editors/code/src/commands/apply_source_change.ts
@@ -11,7 +11,7 @@ export interface SourceChange {
11 11
12export async function handle(change: SourceChange) { 12export async function handle(change: SourceChange) {
13 const wsEdit = Server.client.protocol2CodeConverter.asWorkspaceEdit( 13 const wsEdit = Server.client.protocol2CodeConverter.asWorkspaceEdit(
14 change.workspaceEdit 14 change.workspaceEdit,
15 ); 15 );
16 let created; 16 let created;
17 let moved; 17 let moved;
@@ -33,10 +33,10 @@ export async function handle(change: SourceChange) {
33 await vscode.window.showTextDocument(doc); 33 await vscode.window.showTextDocument(doc);
34 } else if (toReveal) { 34 } else if (toReveal) {
35 const uri = Server.client.protocol2CodeConverter.asUri( 35 const uri = Server.client.protocol2CodeConverter.asUri(
36 toReveal.textDocument.uri 36 toReveal.textDocument.uri,
37 ); 37 );
38 const position = Server.client.protocol2CodeConverter.asPosition( 38 const position = Server.client.protocol2CodeConverter.asPosition(
39 toReveal.position 39 toReveal.position,
40 ); 40 );
41 const editor = vscode.window.activeTextEditor; 41 const editor = vscode.window.activeTextEditor;
42 if (!editor || editor.document.uri.toString() !== uri.toString()) { 42 if (!editor || editor.document.uri.toString() !== uri.toString()) {
@@ -48,7 +48,7 @@ export async function handle(change: SourceChange) {
48 editor.selection = new vscode.Selection(position, position); 48 editor.selection = new vscode.Selection(position, position);
49 editor.revealRange( 49 editor.revealRange(
50 new vscode.Range(position, position), 50 new vscode.Range(position, position),
51 vscode.TextEditorRevealType.Default 51 vscode.TextEditorRevealType.Default,
52 ); 52 );
53 } 53 }
54} 54}
diff --git a/editors/code/src/commands/cargo_watch.ts b/editors/code/src/commands/cargo_watch.ts
index 59d4ba97a..ac62bdd48 100644
--- a/editors/code/src/commands/cargo_watch.ts
+++ b/editors/code/src/commands/cargo_watch.ts
@@ -9,13 +9,13 @@ import { StatusDisplay } from './watch_status';
9 9
10import { 10import {
11 mapRustDiagnosticToVsCode, 11 mapRustDiagnosticToVsCode,
12 RustDiagnostic 12 RustDiagnostic,
13} from '../utils/diagnostics/rust'; 13} from '../utils/diagnostics/rust';
14import SuggestedFixCollection from '../utils/diagnostics/SuggestedFixCollection'; 14import SuggestedFixCollection from '../utils/diagnostics/SuggestedFixCollection';
15import { areDiagnosticsEqual } from '../utils/diagnostics/vscode'; 15import { areDiagnosticsEqual } from '../utils/diagnostics/vscode';
16 16
17export async function registerCargoWatchProvider( 17export async function registerCargoWatchProvider(
18 subscriptions: vscode.Disposable[] 18 subscriptions: vscode.Disposable[],
19): Promise<CargoWatchProvider | undefined> { 19): Promise<CargoWatchProvider | undefined> {
20 let cargoExists = false; 20 let cargoExists = false;
21 21
@@ -30,7 +30,7 @@ export async function registerCargoWatchProvider(
30 30
31 if (!cargoExists) { 31 if (!cargoExists) {
32 vscode.window.showErrorMessage( 32 vscode.window.showErrorMessage(
33 `Couldn\'t find \'Cargo.toml\' at ${cargoTomlPath}` 33 `Couldn\'t find \'Cargo.toml\' at ${cargoTomlPath}`,
34 ); 34 );
35 return; 35 return;
36 } 36 }
@@ -52,13 +52,13 @@ export class CargoWatchProvider implements vscode.Disposable {
52 52
53 constructor() { 53 constructor() {
54 this.diagnosticCollection = vscode.languages.createDiagnosticCollection( 54 this.diagnosticCollection = vscode.languages.createDiagnosticCollection(
55 'rustc' 55 'rustc',
56 ); 56 );
57 this.statusDisplay = new StatusDisplay( 57 this.statusDisplay = new StatusDisplay(
58 Server.config.cargoWatchOptions.command 58 Server.config.cargoWatchOptions.command,
59 ); 59 );
60 this.outputChannel = vscode.window.createOutputChannel( 60 this.outputChannel = vscode.window.createOutputChannel(
61 'Cargo Watch Trace' 61 'Cargo Watch Trace',
62 ); 62 );
63 63
64 // Track `rustc`'s suggested fixes so we can convert them to code actions 64 // Track `rustc`'s suggested fixes so we can convert them to code actions
@@ -68,22 +68,24 @@ export class CargoWatchProvider implements vscode.Disposable {
68 this.suggestedFixCollection, 68 this.suggestedFixCollection,
69 { 69 {
70 providedCodeActionKinds: 70 providedCodeActionKinds:
71 SuggestedFixCollection.PROVIDED_CODE_ACTION_KINDS 71 SuggestedFixCollection.PROVIDED_CODE_ACTION_KINDS,
72 } 72 },
73 ); 73 );
74 } 74 }
75 75
76 public start() { 76 public start() {
77 if (this.cargoProcess) { 77 if (this.cargoProcess) {
78 vscode.window.showInformationMessage( 78 vscode.window.showInformationMessage(
79 'Cargo Watch is already running' 79 'Cargo Watch is already running',
80 ); 80 );
81 return; 81 return;
82 } 82 }
83 83
84 let args = 84 let args =
85 Server.config.cargoWatchOptions.command + 85 Server.config.cargoWatchOptions.command + ' --message-format json';
86 ' --all-targets --message-format json'; 86 if (Server.config.cargoWatchOptions.allTargets) {
87 args += ' --all-targets';
88 }
87 if (Server.config.cargoWatchOptions.command.length > 0) { 89 if (Server.config.cargoWatchOptions.command.length > 0) {
88 // Excape the double quote string: 90 // Excape the double quote string:
89 args += ' ' + Server.config.cargoWatchOptions.arguments; 91 args += ' ' + Server.config.cargoWatchOptions.arguments;
@@ -95,7 +97,7 @@ export class CargoWatchProvider implements vscode.Disposable {
95 97
96 const ignoreFlags = Server.config.cargoWatchOptions.ignore.reduce( 98 const ignoreFlags = Server.config.cargoWatchOptions.ignore.reduce(
97 (flags, pattern) => [...flags, '--ignore', pattern], 99 (flags, pattern) => [...flags, '--ignore', pattern],
98 [] as string[] 100 [] as string[],
99 ); 101 );
100 102
101 // Start the cargo watch with json message 103 // Start the cargo watch with json message
@@ -105,12 +107,17 @@ export class CargoWatchProvider implements vscode.Disposable {
105 { 107 {
106 stdio: ['ignore', 'pipe', 'pipe'], 108 stdio: ['ignore', 'pipe', 'pipe'],
107 cwd: vscode.workspace.rootPath, 109 cwd: vscode.workspace.rootPath,
108 windowsVerbatimArguments: true 110 windowsVerbatimArguments: true,
109 } 111 },
110 ); 112 );
111 113
114 if (!this.cargoProcess) {
115 vscode.window.showErrorMessage('Cargo Watch failed to start');
116 return;
117 }
118
112 const stdoutData = new LineBuffer(); 119 const stdoutData = new LineBuffer();
113 this.cargoProcess.stdout.on('data', (s: string) => { 120 this.cargoProcess.stdout?.on('data', (s: string) => {
114 stdoutData.processOutput(s, line => { 121 stdoutData.processOutput(s, line => {
115 this.logInfo(line); 122 this.logInfo(line);
116 try { 123 try {
@@ -122,7 +129,7 @@ export class CargoWatchProvider implements vscode.Disposable {
122 }); 129 });
123 130
124 const stderrData = new LineBuffer(); 131 const stderrData = new LineBuffer();
125 this.cargoProcess.stderr.on('data', (s: string) => { 132 this.cargoProcess.stderr?.on('data', (s: string) => {
126 stderrData.processOutput(s, line => { 133 stderrData.processOutput(s, line => {
127 this.logError('Error on cargo-watch : {\n' + line + '}\n'); 134 this.logError('Error on cargo-watch : {\n' + line + '}\n');
128 }); 135 });
@@ -130,7 +137,7 @@ export class CargoWatchProvider implements vscode.Disposable {
130 137
131 this.cargoProcess.on('error', (err: Error) => { 138 this.cargoProcess.on('error', (err: Error) => {
132 this.logError( 139 this.logError(
133 'Error on cargo-watch process : {\n' + err.message + '}\n' 140 'Error on cargo-watch process : {\n' + err.message + '}\n',
134 ); 141 );
135 }); 142 });
136 143
@@ -223,12 +230,12 @@ export class CargoWatchProvider implements vscode.Disposable {
223 const fileUri = location.uri; 230 const fileUri = location.uri;
224 231
225 const diagnostics: vscode.Diagnostic[] = [ 232 const diagnostics: vscode.Diagnostic[] = [
226 ...(this.diagnosticCollection!.get(fileUri) || []) 233 ...(this.diagnosticCollection!.get(fileUri) || []),
227 ]; 234 ];
228 235
229 // If we're building multiple targets it's possible we've already seen this diagnostic 236 // If we're building multiple targets it's possible we've already seen this diagnostic
230 const isDuplicate = diagnostics.some(d => 237 const isDuplicate = diagnostics.some(d =>
231 areDiagnosticsEqual(d, diagnostic) 238 areDiagnosticsEqual(d, diagnostic),
232 ); 239 );
233 if (isDuplicate) { 240 if (isDuplicate) {
234 return; 241 return;
@@ -241,7 +248,7 @@ export class CargoWatchProvider implements vscode.Disposable {
241 for (const suggestedFix of suggestedFixes) { 248 for (const suggestedFix of suggestedFixes) {
242 this.suggestedFixCollection.addSuggestedFixForDiagnostic( 249 this.suggestedFixCollection.addSuggestedFixForDiagnostic(
243 suggestedFix, 250 suggestedFix,
244 diagnostic 251 diagnostic,
245 ); 252 );
246 } 253 }
247 254
@@ -249,7 +256,7 @@ export class CargoWatchProvider implements vscode.Disposable {
249 vscode.commands.executeCommand( 256 vscode.commands.executeCommand(
250 'vscode.executeCodeActionProvider', 257 'vscode.executeCodeActionProvider',
251 fileUri, 258 fileUri,
252 diagnostic.range 259 diagnostic.range,
253 ); 260 );
254 } 261 }
255 } 262 }
diff --git a/editors/code/src/commands/expand_macro.ts b/editors/code/src/commands/expand_macro.ts
index 34e0c8fb3..17c78280a 100644
--- a/editors/code/src/commands/expand_macro.ts
+++ b/editors/code/src/commands/expand_macro.ts
@@ -3,7 +3,7 @@ import { Position, TextDocumentIdentifier } from 'vscode-languageclient';
3import { Server } from '../server'; 3import { Server } from '../server';
4 4
5export const expandMacroUri = vscode.Uri.parse( 5export const expandMacroUri = vscode.Uri.parse(
6 'rust-analyzer://expandMacro/[EXPANSION].rs' 6 'rust-analyzer://expandMacro/[EXPANSION].rs',
7); 7);
8 8
9export class ExpandMacroContentProvider 9export class ExpandMacroContentProvider
@@ -11,7 +11,7 @@ export class ExpandMacroContentProvider
11 public eventEmitter = new vscode.EventEmitter<vscode.Uri>(); 11 public eventEmitter = new vscode.EventEmitter<vscode.Uri>();
12 12
13 public provideTextDocumentContent( 13 public provideTextDocumentContent(
14 uri: vscode.Uri 14 _uri: vscode.Uri,
15 ): vscode.ProviderResult<string> { 15 ): vscode.ProviderResult<string> {
16 async function handle() { 16 async function handle() {
17 const editor = vscode.window.activeTextEditor; 17 const editor = vscode.window.activeTextEditor;
@@ -22,11 +22,11 @@ export class ExpandMacroContentProvider
22 const position = editor.selection.active; 22 const position = editor.selection.active;
23 const request: MacroExpandParams = { 23 const request: MacroExpandParams = {
24 textDocument: { uri: editor.document.uri.toString() }, 24 textDocument: { uri: editor.document.uri.toString() },
25 position 25 position,
26 }; 26 };
27 const expanded = await Server.client.sendRequest<ExpandedMacro>( 27 const expanded = await Server.client.sendRequest<ExpandedMacro>(
28 'rust-analyzer/expandMacro', 28 'rust-analyzer/expandMacro',
29 request 29 request,
30 ); 30 );
31 31
32 if (expanded == null) { 32 if (expanded == null) {
@@ -58,7 +58,7 @@ export function createHandle(provider: ExpandMacroContentProvider) {
58 return vscode.window.showTextDocument( 58 return vscode.window.showTextDocument(
59 document, 59 document,
60 vscode.ViewColumn.Two, 60 vscode.ViewColumn.Two,
61 true 61 true,
62 ); 62 );
63 }; 63 };
64} 64}
diff --git a/editors/code/src/commands/index.ts b/editors/code/src/commands/index.ts
index 2ade6d331..13a696758 100644
--- a/editors/code/src/commands/index.ts
+++ b/editors/code/src/commands/index.ts
@@ -19,5 +19,5 @@ export {
19 runnables, 19 runnables,
20 syntaxTree, 20 syntaxTree,
21 onEnter, 21 onEnter,
22 inlayHints 22 inlayHints,
23}; 23};
diff --git a/editors/code/src/commands/inlay_hints.ts b/editors/code/src/commands/inlay_hints.ts
index 0dbdd94fb..ac7dcce60 100644
--- a/editors/code/src/commands/inlay_hints.ts
+++ b/editors/code/src/commands/inlay_hints.ts
@@ -15,8 +15,8 @@ interface InlayHint {
15 15
16const typeHintDecorationType = vscode.window.createTextEditorDecorationType({ 16const typeHintDecorationType = vscode.window.createTextEditorDecorationType({
17 after: { 17 after: {
18 color: new vscode.ThemeColor('ralsp.inlayHint') 18 color: new vscode.ThemeColor('ralsp.inlayHint'),
19 } 19 },
20}); 20});
21 21
22export class HintsUpdater { 22export class HintsUpdater {
@@ -26,13 +26,13 @@ export class HintsUpdater {
26 if (this.displayHints !== displayHints) { 26 if (this.displayHints !== displayHints) {
27 this.displayHints = displayHints; 27 this.displayHints = displayHints;
28 return this.refreshVisibleEditorsHints( 28 return this.refreshVisibleEditorsHints(
29 displayHints ? undefined : [] 29 displayHints ? undefined : [],
30 ); 30 );
31 } 31 }
32 } 32 }
33 33
34 public async refreshHintsForVisibleEditors( 34 public async refreshHintsForVisibleEditors(
35 cause?: TextDocumentChangeEvent 35 cause?: TextDocumentChangeEvent,
36 ): Promise<void> { 36 ): Promise<void> {
37 if (!this.displayHints) { 37 if (!this.displayHints) {
38 return; 38 return;
@@ -48,21 +48,21 @@ export class HintsUpdater {
48 } 48 }
49 49
50 private async refreshVisibleEditorsHints( 50 private async refreshVisibleEditorsHints(
51 newDecorations?: vscode.DecorationOptions[] 51 newDecorations?: vscode.DecorationOptions[],
52 ) { 52 ) {
53 const promises: Array<Promise<void>> = []; 53 const promises: Array<Promise<void>> = [];
54 54
55 for (const rustEditor of vscode.window.visibleTextEditors.filter( 55 for (const rustEditor of vscode.window.visibleTextEditors.filter(
56 editor => this.isRustDocument(editor.document) 56 editor => this.isRustDocument(editor.document),
57 )) { 57 )) {
58 if (newDecorations !== undefined) { 58 if (newDecorations !== undefined) {
59 promises.push( 59 promises.push(
60 Promise.resolve( 60 Promise.resolve(
61 rustEditor.setDecorations( 61 rustEditor.setDecorations(
62 typeHintDecorationType, 62 typeHintDecorationType,
63 newDecorations 63 newDecorations,
64 ) 64 ),
65 ) 65 ),
66 ); 66 );
67 } else { 67 } else {
68 promises.push(this.updateDecorationsFromServer(rustEditor)); 68 promises.push(this.updateDecorationsFromServer(rustEditor));
@@ -79,7 +79,7 @@ export class HintsUpdater {
79 } 79 }
80 80
81 private async updateDecorationsFromServer( 81 private async updateDecorationsFromServer(
82 editor: TextEditor 82 editor: TextEditor,
83 ): Promise<void> { 83 ): Promise<void> {
84 const newHints = await this.queryHints(editor.document.uri.toString()); 84 const newHints = await this.queryHints(editor.document.uri.toString());
85 if (newHints !== null) { 85 if (newHints !== null) {
@@ -87,20 +87,20 @@ export class HintsUpdater {
87 range: hint.range, 87 range: hint.range,
88 renderOptions: { 88 renderOptions: {
89 after: { 89 after: {
90 contentText: `: ${hint.label}` 90 contentText: `: ${hint.label}`,
91 } 91 },
92 } 92 },
93 })); 93 }));
94 return editor.setDecorations( 94 return editor.setDecorations(
95 typeHintDecorationType, 95 typeHintDecorationType,
96 newDecorations 96 newDecorations,
97 ); 97 );
98 } 98 }
99 } 99 }
100 100
101 private async queryHints(documentUri: string): Promise<InlayHint[] | null> { 101 private async queryHints(documentUri: string): Promise<InlayHint[] | null> {
102 const request: InlayHintsParams = { 102 const request: InlayHintsParams = {
103 textDocument: { uri: documentUri } 103 textDocument: { uri: documentUri },
104 }; 104 };
105 const client = Server.client; 105 const client = Server.client;
106 return client 106 return client
@@ -108,8 +108,8 @@ export class HintsUpdater {
108 .then(() => 108 .then(() =>
109 client.sendRequest<InlayHint[] | null>( 109 client.sendRequest<InlayHint[] | null>(
110 'rust-analyzer/inlayHints', 110 'rust-analyzer/inlayHints',
111 request 111 request,
112 ) 112 ),
113 ); 113 );
114 } 114 }
115} 115}
diff --git a/editors/code/src/commands/join_lines.ts b/editors/code/src/commands/join_lines.ts
index 0d4b12f4d..134ddc801 100644
--- a/editors/code/src/commands/join_lines.ts
+++ b/editors/code/src/commands/join_lines.ts
@@ -4,7 +4,7 @@ import { Range, TextDocumentIdentifier } from 'vscode-languageclient';
4import { Server } from '../server'; 4import { Server } from '../server';
5import { 5import {
6 handle as applySourceChange, 6 handle as applySourceChange,
7 SourceChange 7 SourceChange,
8} from './apply_source_change'; 8} from './apply_source_change';
9 9
10interface JoinLinesParams { 10interface JoinLinesParams {
@@ -19,11 +19,11 @@ export async function handle() {
19 } 19 }
20 const request: JoinLinesParams = { 20 const request: JoinLinesParams = {
21 range: Server.client.code2ProtocolConverter.asRange(editor.selection), 21 range: Server.client.code2ProtocolConverter.asRange(editor.selection),
22 textDocument: { uri: editor.document.uri.toString() } 22 textDocument: { uri: editor.document.uri.toString() },
23 }; 23 };
24 const change = await Server.client.sendRequest<SourceChange>( 24 const change = await Server.client.sendRequest<SourceChange>(
25 'rust-analyzer/joinLines', 25 'rust-analyzer/joinLines',
26 request 26 request,
27 ); 27 );
28 await applySourceChange(change); 28 await applySourceChange(change);
29} 29}
diff --git a/editors/code/src/commands/matching_brace.ts b/editors/code/src/commands/matching_brace.ts
index d86faf405..364208cc7 100644
--- a/editors/code/src/commands/matching_brace.ts
+++ b/editors/code/src/commands/matching_brace.ts
@@ -17,15 +17,15 @@ export async function handle() {
17 textDocument: { uri: editor.document.uri.toString() }, 17 textDocument: { uri: editor.document.uri.toString() },
18 offsets: editor.selections.map(s => { 18 offsets: editor.selections.map(s => {
19 return Server.client.code2ProtocolConverter.asPosition(s.active); 19 return Server.client.code2ProtocolConverter.asPosition(s.active);
20 }) 20 }),
21 }; 21 };
22 const response = await Server.client.sendRequest<Position[]>( 22 const response = await Server.client.sendRequest<Position[]>(
23 'rust-analyzer/findMatchingBrace', 23 'rust-analyzer/findMatchingBrace',
24 request 24 request,
25 ); 25 );
26 editor.selections = editor.selections.map((sel, idx) => { 26 editor.selections = editor.selections.map((sel, idx) => {
27 const active = Server.client.protocol2CodeConverter.asPosition( 27 const active = Server.client.protocol2CodeConverter.asPosition(
28 response[idx] 28 response[idx],
29 ); 29 );
30 const anchor = sel.isEmpty ? active : sel.anchor; 30 const anchor = sel.isEmpty ? active : sel.anchor;
31 return new vscode.Selection(anchor, active); 31 return new vscode.Selection(anchor, active);
diff --git a/editors/code/src/commands/on_enter.ts b/editors/code/src/commands/on_enter.ts
index 16dcb70c8..772c64b3c 100644
--- a/editors/code/src/commands/on_enter.ts
+++ b/editors/code/src/commands/on_enter.ts
@@ -3,7 +3,7 @@ import * as lc from 'vscode-languageclient';
3import { Server } from '../server'; 3import { Server } from '../server';
4import { 4import {
5 handle as applySourceChange, 5 handle as applySourceChange,
6 SourceChange 6 SourceChange,
7} from './apply_source_change'; 7} from './apply_source_change';
8 8
9export async function handle(event: { text: string }): Promise<boolean> { 9export async function handle(event: { text: string }): Promise<boolean> {
@@ -18,12 +18,12 @@ export async function handle(event: { text: string }): Promise<boolean> {
18 const request: lc.TextDocumentPositionParams = { 18 const request: lc.TextDocumentPositionParams = {
19 textDocument: { uri: editor.document.uri.toString() }, 19 textDocument: { uri: editor.document.uri.toString() },
20 position: Server.client.code2ProtocolConverter.asPosition( 20 position: Server.client.code2ProtocolConverter.asPosition(
21 editor.selection.active 21 editor.selection.active,
22 ) 22 ),
23 }; 23 };
24 const change = await Server.client.sendRequest<undefined | SourceChange>( 24 const change = await Server.client.sendRequest<undefined | SourceChange>(
25 'rust-analyzer/onEnter', 25 'rust-analyzer/onEnter',
26 request 26 request,
27 ); 27 );
28 if (!change) { 28 if (!change) {
29 return false; 29 return false;
diff --git a/editors/code/src/commands/parent_module.ts b/editors/code/src/commands/parent_module.ts
index 9d30b7b59..ad49e1bdb 100644
--- a/editors/code/src/commands/parent_module.ts
+++ b/editors/code/src/commands/parent_module.ts
@@ -11,12 +11,12 @@ export async function handle() {
11 const request: lc.TextDocumentPositionParams = { 11 const request: lc.TextDocumentPositionParams = {
12 textDocument: { uri: editor.document.uri.toString() }, 12 textDocument: { uri: editor.document.uri.toString() },
13 position: Server.client.code2ProtocolConverter.asPosition( 13 position: Server.client.code2ProtocolConverter.asPosition(
14 editor.selection.active 14 editor.selection.active,
15 ) 15 ),
16 }; 16 };
17 const response = await Server.client.sendRequest<lc.Location[]>( 17 const response = await Server.client.sendRequest<lc.Location[]>(
18 'rust-analyzer/parentModule', 18 'rust-analyzer/parentModule',
19 request 19 request,
20 ); 20 );
21 const loc = response[0]; 21 const loc = response[0];
22 if (loc == null) { 22 if (loc == null) {
diff --git a/editors/code/src/commands/runnables.ts b/editors/code/src/commands/runnables.ts
index ac59bf60d..cf980e257 100644
--- a/editors/code/src/commands/runnables.ts
+++ b/editors/code/src/commands/runnables.ts
@@ -46,17 +46,17 @@ function createTask(spec: Runnable): vscode.Task {
46 label: spec.label, 46 label: spec.label,
47 command: spec.bin, 47 command: spec.bin,
48 args: spec.args, 48 args: spec.args,
49 env: spec.env 49 env: spec.env,
50 }; 50 };
51 51
52 const execOption: vscode.ShellExecutionOptions = { 52 const execOption: vscode.ShellExecutionOptions = {
53 cwd: spec.cwd || '.', 53 cwd: spec.cwd || '.',
54 env: definition.env 54 env: definition.env,
55 }; 55 };
56 const exec = new vscode.ShellExecution( 56 const exec = new vscode.ShellExecution(
57 definition.command, 57 definition.command,
58 definition.args, 58 definition.args,
59 execOption 59 execOption,
60 ); 60 );
61 61
62 const f = vscode.workspace.workspaceFolders![0]; 62 const f = vscode.workspace.workspaceFolders![0];
@@ -66,30 +66,30 @@ function createTask(spec: Runnable): vscode.Task {
66 definition.label, 66 definition.label,
67 TASK_SOURCE, 67 TASK_SOURCE,
68 exec, 68 exec,
69 ['$rustc'] 69 ['$rustc'],
70 ); 70 );
71 t.presentationOptions.clear = true; 71 t.presentationOptions.clear = true;
72 return t; 72 return t;
73} 73}
74 74
75let prevRunnable: RunnableQuickPick | undefined; 75let prevRunnable: RunnableQuickPick | undefined;
76export async function handle() { 76export async function handle(): Promise<vscode.TaskExecution | undefined> {
77 const editor = vscode.window.activeTextEditor; 77 const editor = vscode.window.activeTextEditor;
78 if (editor == null || editor.document.languageId !== 'rust') { 78 if (editor == null || editor.document.languageId !== 'rust') {
79 return; 79 return;
80 } 80 }
81 const textDocument: lc.TextDocumentIdentifier = { 81 const textDocument: lc.TextDocumentIdentifier = {
82 uri: editor.document.uri.toString() 82 uri: editor.document.uri.toString(),
83 }; 83 };
84 const params: RunnablesParams = { 84 const params: RunnablesParams = {
85 textDocument, 85 textDocument,
86 position: Server.client.code2ProtocolConverter.asPosition( 86 position: Server.client.code2ProtocolConverter.asPosition(
87 editor.selection.active 87 editor.selection.active,
88 ) 88 ),
89 }; 89 };
90 const runnables = await Server.client.sendRequest<Runnable[]>( 90 const runnables = await Server.client.sendRequest<Runnable[]>(
91 'rust-analyzer/runnables', 91 'rust-analyzer/runnables',
92 params 92 params,
93 ); 93 );
94 const items: RunnableQuickPick[] = []; 94 const items: RunnableQuickPick[] = [];
95 if (prevRunnable) { 95 if (prevRunnable) {
@@ -105,12 +105,14 @@ export async function handle() {
105 items.push(new RunnableQuickPick(r)); 105 items.push(new RunnableQuickPick(r));
106 } 106 }
107 const item = await vscode.window.showQuickPick(items); 107 const item = await vscode.window.showQuickPick(items);
108 if (item) { 108 if (!item) {
109 item.detail = 'rerun'; 109 return;
110 prevRunnable = item;
111 const task = createTask(item.runnable);
112 return await vscode.tasks.executeTask(task);
113 } 110 }
111
112 item.detail = 'rerun';
113 prevRunnable = item;
114 const task = createTask(item.runnable);
115 return await vscode.tasks.executeTask(task);
114} 116}
115 117
116export async function handleSingle(runnable: Runnable) { 118export async function handleSingle(runnable: Runnable) {
@@ -124,7 +126,7 @@ export async function handleSingle(runnable: Runnable) {
124 task.presentationOptions = { 126 task.presentationOptions = {
125 reveal: vscode.TaskRevealKind.Always, 127 reveal: vscode.TaskRevealKind.Always,
126 panel: vscode.TaskPanelKind.Dedicated, 128 panel: vscode.TaskPanelKind.Dedicated,
127 clear: true 129 clear: true,
128 }; 130 };
129 131
130 return vscode.tasks.executeTask(task); 132 return vscode.tasks.executeTask(task);
@@ -136,7 +138,7 @@ export async function handleSingle(runnable: Runnable) {
136 * that, when accepted, allow us to `cargo install cargo-watch` and then run it. 138 * that, when accepted, allow us to `cargo install cargo-watch` and then run it.
137 */ 139 */
138export async function interactivelyStartCargoWatch( 140export async function interactivelyStartCargoWatch(
139 context: vscode.ExtensionContext 141 context: vscode.ExtensionContext,
140): Promise<CargoWatchProvider | undefined> { 142): Promise<CargoWatchProvider | undefined> {
141 if (Server.config.cargoWatchOptions.enableOnStartup === 'disabled') { 143 if (Server.config.cargoWatchOptions.enableOnStartup === 'disabled') {
142 return; 144 return;
@@ -146,7 +148,7 @@ export async function interactivelyStartCargoWatch(
146 const watch = await vscode.window.showInformationMessage( 148 const watch = await vscode.window.showInformationMessage(
147 'Start watching changes with cargo? (Executes `cargo watch`, provides inline diagnostics)', 149 'Start watching changes with cargo? (Executes `cargo watch`, provides inline diagnostics)',
148 'yes', 150 'yes',
149 'no' 151 'no',
150 ); 152 );
151 if (watch !== 'yes') { 153 if (watch !== 'yes') {
152 return; 154 return;
@@ -157,12 +159,12 @@ export async function interactivelyStartCargoWatch(
157} 159}
158 160
159export async function startCargoWatch( 161export async function startCargoWatch(
160 context: vscode.ExtensionContext 162 context: vscode.ExtensionContext,
161): Promise<CargoWatchProvider | undefined> { 163): Promise<CargoWatchProvider | undefined> {
162 const execPromise = util.promisify(child_process.exec); 164 const execPromise = util.promisify(child_process.exec);
163 165
164 const { stderr, code = 0 } = await execPromise( 166 const { stderr, code = 0 } = await execPromise(
165 'cargo watch --version' 167 'cargo watch --version',
166 ).catch(e => e); 168 ).catch(e => e);
167 169
168 if (stderr.includes('no such subcommand: `watch`')) { 170 if (stderr.includes('no such subcommand: `watch`')) {
@@ -171,14 +173,14 @@ export async function startCargoWatch(
171 const install = await vscode.window.showInformationMessage( 173 const install = await vscode.window.showInformationMessage(
172 msg, 174 msg,
173 'yes', 175 'yes',
174 'no' 176 'no',
175 ); 177 );
176 if (install !== 'yes') { 178 if (install !== 'yes') {
177 return; 179 return;
178 } 180 }
179 181
180 const label = 'install-cargo-watch'; 182 const label = 'install-cargo-watch';
181 const taskFinished = new Promise((resolve, reject) => { 183 const taskFinished = new Promise((resolve, _reject) => {
182 const disposable = vscode.tasks.onDidEndTask(({ execution }) => { 184 const disposable = vscode.tasks.onDidEndTask(({ execution }) => {
183 if (execution.task.name === label) { 185 if (execution.task.name === label) {
184 disposable.dispose(); 186 disposable.dispose();
@@ -192,20 +194,20 @@ export async function startCargoWatch(
192 label, 194 label,
193 bin: 'cargo', 195 bin: 'cargo',
194 args: ['install', 'cargo-watch'], 196 args: ['install', 'cargo-watch'],
195 env: {} 197 env: {},
196 }) 198 }),
197 ); 199 );
198 await taskFinished; 200 await taskFinished;
199 const output = await execPromise('cargo watch --version').catch(e => e); 201 const output = await execPromise('cargo watch --version').catch(e => e);
200 if (output.stderr !== '') { 202 if (output.stderr !== '') {
201 vscode.window.showErrorMessage( 203 vscode.window.showErrorMessage(
202 `Couldn't install \`cargo-\`watch: ${output.stderr}` 204 `Couldn't install \`cargo-\`watch: ${output.stderr}`,
203 ); 205 );
204 return; 206 return;
205 } 207 }
206 } else if (code !== 0) { 208 } else if (code !== 0) {
207 vscode.window.showErrorMessage( 209 vscode.window.showErrorMessage(
208 `\`cargo watch\` failed with ${code}: ${stderr}` 210 `\`cargo watch\` failed with ${code}: ${stderr}`,
209 ); 211 );
210 return; 212 return;
211 } 213 }
diff --git a/editors/code/src/commands/syntaxTree.ts b/editors/code/src/commands/syntaxTree.ts
index 2f50fe14b..89a80550c 100644
--- a/editors/code/src/commands/syntaxTree.ts
+++ b/editors/code/src/commands/syntaxTree.ts
@@ -11,7 +11,7 @@ export class SyntaxTreeContentProvider
11 public syntaxTree: string = 'Not available'; 11 public syntaxTree: string = 'Not available';
12 12
13 public provideTextDocumentContent( 13 public provideTextDocumentContent(
14 uri: vscode.Uri 14 uri: vscode.Uri,
15 ): vscode.ProviderResult<string> { 15 ): vscode.ProviderResult<string> {
16 const editor = vscode.window.activeTextEditor; 16 const editor = vscode.window.activeTextEditor;
17 if (editor == null) { 17 if (editor == null) {
@@ -25,17 +25,17 @@ export class SyntaxTreeContentProvider
25 range = editor.selection.isEmpty 25 range = editor.selection.isEmpty
26 ? undefined 26 ? undefined
27 : Server.client.code2ProtocolConverter.asRange( 27 : Server.client.code2ProtocolConverter.asRange(
28 editor.selection 28 editor.selection,
29 ); 29 );
30 } 30 }
31 31
32 const request: SyntaxTreeParams = { 32 const request: SyntaxTreeParams = {
33 textDocument: { uri: editor.document.uri.toString() }, 33 textDocument: { uri: editor.document.uri.toString() },
34 range 34 range,
35 }; 35 };
36 return Server.client.sendRequest<SyntaxTreeResult>( 36 return Server.client.sendRequest<SyntaxTreeResult>(
37 'rust-analyzer/syntaxTree', 37 'rust-analyzer/syntaxTree',
38 request 38 request,
39 ); 39 );
40 } 40 }
41 41
@@ -70,7 +70,7 @@ export function createHandle(provider: SyntaxTreeContentProvider) {
70 return vscode.window.showTextDocument( 70 return vscode.window.showTextDocument(
71 document, 71 document,
72 vscode.ViewColumn.Two, 72 vscode.ViewColumn.Two,
73 true 73 true,
74 ); 74 );
75 }; 75 };
76} 76}
diff --git a/editors/code/src/commands/watch_status.ts b/editors/code/src/commands/watch_status.ts
index 6c1f9041b..8d64394c7 100644
--- a/editors/code/src/commands/watch_status.ts
+++ b/editors/code/src/commands/watch_status.ts
@@ -13,7 +13,7 @@ export class StatusDisplay implements vscode.Disposable {
13 constructor(command: string) { 13 constructor(command: string) {
14 this.statusBarItem = vscode.window.createStatusBarItem( 14 this.statusBarItem = vscode.window.createStatusBarItem(
15 vscode.StatusBarAlignment.Left, 15 vscode.StatusBarAlignment.Left,
16 10 16 10,
17 ); 17 );
18 this.command = command; 18 this.command = command;
19 this.statusBarItem.hide(); 19 this.statusBarItem.hide();
diff --git a/editors/code/src/config.ts b/editors/code/src/config.ts
index 4cedbea46..c06dddb1c 100644
--- a/editors/code/src/config.ts
+++ b/editors/code/src/config.ts
@@ -14,6 +14,13 @@ export interface CargoWatchOptions {
14 command: string; 14 command: string;
15 trace: CargoWatchTraceOptions; 15 trace: CargoWatchTraceOptions;
16 ignore: string[]; 16 ignore: string[];
17 allTargets: boolean;
18}
19
20export interface CargoFeatures {
21 noDefaultFeatures: boolean;
22 allFeatures: boolean;
23 features: string[];
17} 24}
18 25
19export class Config { 26export class Config {
@@ -25,21 +32,30 @@ export class Config {
25 public displayInlayHints = true; 32 public displayInlayHints = true;
26 public maxInlayHintLength: null | number = null; 33 public maxInlayHintLength: null | number = null;
27 public excludeGlobs = []; 34 public excludeGlobs = [];
28 public useClientWatching = false; 35 public useClientWatching = true;
29 public featureFlags = {}; 36 public featureFlags = {};
37 // for internal use
38 public withSysroot: null | boolean = null;
30 public cargoWatchOptions: CargoWatchOptions = { 39 public cargoWatchOptions: CargoWatchOptions = {
31 enableOnStartup: 'ask', 40 enableOnStartup: 'ask',
32 trace: 'off', 41 trace: 'off',
33 arguments: '', 42 arguments: '',
34 command: '', 43 command: '',
35 ignore: [] 44 ignore: [],
45 allTargets: true,
46 };
47 public cargoFeatures: CargoFeatures = {
48 noDefaultFeatures: false,
49 allFeatures: true,
50 features: [],
36 }; 51 };
37 52
38 private prevEnhancedTyping: null | boolean = null; 53 private prevEnhancedTyping: null | boolean = null;
54 private prevCargoFeatures: null | CargoFeatures = null;
39 55
40 constructor() { 56 constructor() {
41 vscode.workspace.onDidChangeConfiguration(_ => 57 vscode.workspace.onDidChangeConfiguration(_ =>
42 this.userConfigChanged() 58 this.userConfigChanged(),
43 ); 59 );
44 this.userConfigChanged(); 60 this.userConfigChanged();
45 } 61 }
@@ -49,6 +65,8 @@ export class Config {
49 65
50 Server.highlighter.removeHighlights(); 66 Server.highlighter.removeHighlights();
51 67
68 let requireReloadMessage = null;
69
52 if (config.has('highlightingOn')) { 70 if (config.has('highlightingOn')) {
53 this.highlightingOn = config.get('highlightingOn') as boolean; 71 this.highlightingOn = config.get('highlightingOn') as boolean;
54 if (this.highlightingOn) { 72 if (this.highlightingOn) {
@@ -59,13 +77,13 @@ export class Config {
59 77
60 if (config.has('rainbowHighlightingOn')) { 78 if (config.has('rainbowHighlightingOn')) {
61 this.rainbowHighlightingOn = config.get( 79 this.rainbowHighlightingOn = config.get(
62 'rainbowHighlightingOn' 80 'rainbowHighlightingOn',
63 ) as boolean; 81 ) as boolean;
64 } 82 }
65 83
66 if (config.has('enableEnhancedTyping')) { 84 if (config.has('enableEnhancedTyping')) {
67 this.enableEnhancedTyping = config.get( 85 this.enableEnhancedTyping = config.get(
68 'enableEnhancedTyping' 86 'enableEnhancedTyping',
69 ) as boolean; 87 ) as boolean;
70 88
71 if (this.prevEnhancedTyping === null) { 89 if (this.prevEnhancedTyping === null) {
@@ -76,19 +94,8 @@ export class Config {
76 } 94 }
77 95
78 if (this.prevEnhancedTyping !== this.enableEnhancedTyping) { 96 if (this.prevEnhancedTyping !== this.enableEnhancedTyping) {
79 const reloadAction = 'Reload now'; 97 requireReloadMessage =
80 vscode.window 98 'Changing enhanced typing setting requires a reload';
81 .showInformationMessage(
82 'Changing enhanced typing setting requires a reload',
83 reloadAction
84 )
85 .then(selectedAction => {
86 if (selectedAction === reloadAction) {
87 vscode.commands.executeCommand(
88 'workbench.action.reloadWindow'
89 );
90 }
91 });
92 this.prevEnhancedTyping = this.enableEnhancedTyping; 99 this.prevEnhancedTyping = this.enableEnhancedTyping;
93 } 100 }
94 101
@@ -106,28 +113,35 @@ export class Config {
106 if (config.has('trace.cargo-watch')) { 113 if (config.has('trace.cargo-watch')) {
107 this.cargoWatchOptions.trace = config.get<CargoWatchTraceOptions>( 114 this.cargoWatchOptions.trace = config.get<CargoWatchTraceOptions>(
108 'trace.cargo-watch', 115 'trace.cargo-watch',
109 'off' 116 'off',
110 ); 117 );
111 } 118 }
112 119
113 if (config.has('cargo-watch.arguments')) { 120 if (config.has('cargo-watch.arguments')) {
114 this.cargoWatchOptions.arguments = config.get<string>( 121 this.cargoWatchOptions.arguments = config.get<string>(
115 'cargo-watch.arguments', 122 'cargo-watch.arguments',
116 '' 123 '',
117 ); 124 );
118 } 125 }
119 126
120 if (config.has('cargo-watch.command')) { 127 if (config.has('cargo-watch.command')) {
121 this.cargoWatchOptions.command = config.get<string>( 128 this.cargoWatchOptions.command = config.get<string>(
122 'cargo-watch.command', 129 'cargo-watch.command',
123 '' 130 '',
124 ); 131 );
125 } 132 }
126 133
127 if (config.has('cargo-watch.ignore')) { 134 if (config.has('cargo-watch.ignore')) {
128 this.cargoWatchOptions.ignore = config.get<string[]>( 135 this.cargoWatchOptions.ignore = config.get<string[]>(
129 'cargo-watch.ignore', 136 'cargo-watch.ignore',
130 [] 137 [],
138 );
139 }
140
141 if (config.has('cargo-watch.allTargets')) {
142 this.cargoWatchOptions.allTargets = config.get<boolean>(
143 'cargo-watch.allTargets',
144 true,
131 ); 145 );
132 } 146 }
133 147
@@ -140,17 +154,68 @@ export class Config {
140 } 154 }
141 if (config.has('maxInlayHintLength')) { 155 if (config.has('maxInlayHintLength')) {
142 this.maxInlayHintLength = config.get( 156 this.maxInlayHintLength = config.get(
143 'maxInlayHintLength' 157 'maxInlayHintLength',
144 ) as number; 158 ) as number;
145 } 159 }
146 if (config.has('excludeGlobs')) { 160 if (config.has('excludeGlobs')) {
147 this.excludeGlobs = config.get('excludeGlobs') || []; 161 this.excludeGlobs = config.get('excludeGlobs') || [];
148 } 162 }
149 if (config.has('useClientWatching')) { 163 if (config.has('useClientWatching')) {
150 this.useClientWatching = config.get('useClientWatching') || false; 164 this.useClientWatching = config.get('useClientWatching') || true;
151 } 165 }
152 if (config.has('featureFlags')) { 166 if (config.has('featureFlags')) {
153 this.featureFlags = config.get('featureFlags') || {}; 167 this.featureFlags = config.get('featureFlags') || {};
154 } 168 }
169 if (config.has('withSysroot')) {
170 this.withSysroot = config.get('withSysroot') || false;
171 }
172
173 if (config.has('cargoFeatures.noDefaultFeatures')) {
174 this.cargoFeatures.noDefaultFeatures = config.get(
175 'cargoFeatures.noDefaultFeatures',
176 false,
177 );
178 }
179 if (config.has('cargoFeatures.allFeatures')) {
180 this.cargoFeatures.allFeatures = config.get(
181 'cargoFeatures.allFeatures',
182 true,
183 );
184 }
185 if (config.has('cargoFeatures.features')) {
186 this.cargoFeatures.features = config.get(
187 'cargoFeatures.features',
188 [],
189 );
190 }
191
192 if (
193 this.prevCargoFeatures !== null &&
194 (this.cargoFeatures.allFeatures !==
195 this.prevCargoFeatures.allFeatures ||
196 this.cargoFeatures.noDefaultFeatures !==
197 this.prevCargoFeatures.noDefaultFeatures ||
198 this.cargoFeatures.features.length !==
199 this.prevCargoFeatures.features.length ||
200 this.cargoFeatures.features.some(
201 (v, i) => v !== this.prevCargoFeatures!.features[i],
202 ))
203 ) {
204 requireReloadMessage = 'Changing cargo features requires a reload';
205 }
206 this.prevCargoFeatures = { ...this.cargoFeatures };
207
208 if (requireReloadMessage !== null) {
209 const reloadAction = 'Reload now';
210 vscode.window
211 .showInformationMessage(requireReloadMessage, reloadAction)
212 .then(selectedAction => {
213 if (selectedAction === reloadAction) {
214 vscode.commands.executeCommand(
215 'workbench.action.reloadWindow',
216 );
217 }
218 });
219 }
155 } 220 }
156} 221}
diff --git a/editors/code/src/events/change_active_text_editor.ts b/editors/code/src/events/change_active_text_editor.ts
index 64be56225..74b91bd48 100644
--- a/editors/code/src/events/change_active_text_editor.ts
+++ b/editors/code/src/events/change_active_text_editor.ts
@@ -3,7 +3,7 @@ import { TextDocumentIdentifier } from 'vscode-languageclient';
3 3
4import { 4import {
5 SyntaxTreeContentProvider, 5 SyntaxTreeContentProvider,
6 syntaxTreeUri 6 syntaxTreeUri,
7} from '../commands/syntaxTree'; 7} from '../commands/syntaxTree';
8import { Decoration } from '../highlighting'; 8import { Decoration } from '../highlighting';
9import { Server } from '../server'; 9import { Server } from '../server';
@@ -21,11 +21,11 @@ export function makeHandler(syntaxTreeProvider: SyntaxTreeContentProvider) {
21 } 21 }
22 22
23 const params: TextDocumentIdentifier = { 23 const params: TextDocumentIdentifier = {
24 uri: editor.document.uri.toString() 24 uri: editor.document.uri.toString(),
25 }; 25 };
26 const decorations = await Server.client.sendRequest<Decoration[]>( 26 const decorations = await Server.client.sendRequest<Decoration[]>(
27 'rust-analyzer/decorationsRequest', 27 'rust-analyzer/decorationsRequest',
28 params 28 params,
29 ); 29 );
30 Server.highlighter.setHighlights(editor, decorations); 30 Server.highlighter.setHighlights(editor, decorations);
31 }; 31 };
diff --git a/editors/code/src/events/change_text_document.ts b/editors/code/src/events/change_text_document.ts
index 89488bc61..2e998e889 100644
--- a/editors/code/src/events/change_text_document.ts
+++ b/editors/code/src/events/change_text_document.ts
@@ -2,7 +2,7 @@ import * as vscode from 'vscode';
2 2
3import { 3import {
4 SyntaxTreeContentProvider, 4 SyntaxTreeContentProvider,
5 syntaxTreeUri 5 syntaxTreeUri,
6} from '../commands/syntaxTree'; 6} from '../commands/syntaxTree';
7 7
8export function createHandler(syntaxTreeProvider: SyntaxTreeContentProvider) { 8export function createHandler(syntaxTreeProvider: SyntaxTreeContentProvider) {
diff --git a/editors/code/src/extension.ts b/editors/code/src/extension.ts
index 683497dfd..815f3692c 100644
--- a/editors/code/src/extension.ts
+++ b/editors/code/src/extension.ts
@@ -7,14 +7,14 @@ import { ExpandMacroContentProvider } from './commands/expand_macro';
7import { HintsUpdater } from './commands/inlay_hints'; 7import { HintsUpdater } from './commands/inlay_hints';
8import { 8import {
9 interactivelyStartCargoWatch, 9 interactivelyStartCargoWatch,
10 startCargoWatch 10 startCargoWatch,
11} from './commands/runnables'; 11} from './commands/runnables';
12import { SyntaxTreeContentProvider } from './commands/syntaxTree'; 12import { SyntaxTreeContentProvider } from './commands/syntaxTree';
13import * as events from './events'; 13import * as events from './events';
14import * as notifications from './notifications'; 14import * as notifications from './notifications';
15import { Server } from './server'; 15import { Server } from './server';
16 16
17export function activate(context: vscode.ExtensionContext) { 17export async function activate(context: vscode.ExtensionContext) {
18 function disposeOnDeactivation(disposable: vscode.Disposable) { 18 function disposeOnDeactivation(disposable: vscode.Disposable) {
19 context.subscriptions.push(disposable); 19 context.subscriptions.push(disposable);
20 } 20 }
@@ -24,7 +24,7 @@ export function activate(context: vscode.ExtensionContext) {
24 } 24 }
25 function overrideCommand( 25 function overrideCommand(
26 name: string, 26 name: string,
27 f: (...args: any[]) => Promise<boolean> 27 f: (...args: any[]) => Promise<boolean>,
28 ) { 28 ) {
29 const defaultCmd = `default:${name}`; 29 const defaultCmd = `default:${name}`;
30 const original = (...args: any[]) => 30 const original = (...args: any[]) =>
@@ -46,7 +46,7 @@ export function activate(context: vscode.ExtensionContext) {
46 }); 46 });
47 } catch (_) { 47 } catch (_) {
48 vscode.window.showWarningMessage( 48 vscode.window.showWarningMessage(
49 'Enhanced typing feature is disabled because of incompatibility with VIM extension, consider turning off rust-analyzer.enableEnhancedTyping: https://github.com/rust-analyzer/rust-analyzer/blob/master/docs/user/README.md#settings' 49 'Enhanced typing feature is disabled because of incompatibility with VIM extension, consider turning off rust-analyzer.enableEnhancedTyping: https://github.com/rust-analyzer/rust-analyzer/blob/master/docs/user/README.md#settings',
50 ); 50 );
51 } 51 }
52 } 52 }
@@ -54,14 +54,14 @@ export function activate(context: vscode.ExtensionContext) {
54 // Commands are requests from vscode to the language server 54 // Commands are requests from vscode to the language server
55 registerCommand( 55 registerCommand(
56 'rust-analyzer.analyzerStatus', 56 'rust-analyzer.analyzerStatus',
57 commands.analyzerStatus.makeCommand(context) 57 commands.analyzerStatus.makeCommand(context),
58 ); 58 );
59 registerCommand('rust-analyzer.collectGarbage', () => 59 registerCommand('rust-analyzer.collectGarbage', () =>
60 Server.client.sendRequest<null>('rust-analyzer/collectGarbage', null) 60 Server.client.sendRequest<null>('rust-analyzer/collectGarbage', null),
61 ); 61 );
62 registerCommand( 62 registerCommand(
63 'rust-analyzer.matchingBrace', 63 'rust-analyzer.matchingBrace',
64 commands.matchingBrace.handle 64 commands.matchingBrace.handle,
65 ); 65 );
66 registerCommand('rust-analyzer.joinLines', commands.joinLines.handle); 66 registerCommand('rust-analyzer.joinLines', commands.joinLines.handle);
67 registerCommand('rust-analyzer.parentModule', commands.parentModule.handle); 67 registerCommand('rust-analyzer.parentModule', commands.parentModule.handle);
@@ -70,7 +70,7 @@ export function activate(context: vscode.ExtensionContext) {
70 registerCommand('rust-analyzer.runSingle', commands.runnables.handleSingle); 70 registerCommand('rust-analyzer.runSingle', commands.runnables.handleSingle);
71 registerCommand( 71 registerCommand(
72 'rust-analyzer.applySourceChange', 72 'rust-analyzer.applySourceChange',
73 commands.applySourceChange.handle 73 commands.applySourceChange.handle,
74 ); 74 );
75 registerCommand( 75 registerCommand(
76 'rust-analyzer.showReferences', 76 'rust-analyzer.showReferences',
@@ -79,9 +79,9 @@ export function activate(context: vscode.ExtensionContext) {
79 'editor.action.showReferences', 79 'editor.action.showReferences',
80 vscode.Uri.parse(uri), 80 vscode.Uri.parse(uri),
81 Server.client.protocol2CodeConverter.asPosition(position), 81 Server.client.protocol2CodeConverter.asPosition(position),
82 locations.map(Server.client.protocol2CodeConverter.asLocation) 82 locations.map(Server.client.protocol2CodeConverter.asLocation),
83 ); 83 );
84 } 84 },
85 ); 85 );
86 86
87 if (Server.config.enableEnhancedTyping) { 87 if (Server.config.enableEnhancedTyping) {
@@ -89,48 +89,49 @@ export function activate(context: vscode.ExtensionContext) {
89 } 89 }
90 90
91 // Notifications are events triggered by the language server 91 // Notifications are events triggered by the language server
92 const allNotifications: Iterable< 92 const allNotifications: Iterable<[
93 [string, lc.GenericNotificationHandler] 93 string,
94 > = [ 94 lc.GenericNotificationHandler,
95 ]> = [
95 [ 96 [
96 'rust-analyzer/publishDecorations', 97 'rust-analyzer/publishDecorations',
97 notifications.publishDecorations.handle 98 notifications.publishDecorations.handle,
98 ] 99 ],
99 ]; 100 ];
100 const syntaxTreeContentProvider = new SyntaxTreeContentProvider(); 101 const syntaxTreeContentProvider = new SyntaxTreeContentProvider();
101 const expandMacroContentProvider = new ExpandMacroContentProvider(); 102 const expandMacroContentProvider = new ExpandMacroContentProvider();
102 103
103 // The events below are plain old javascript events, triggered and handled by vscode 104 // The events below are plain old javascript events, triggered and handled by vscode
104 vscode.window.onDidChangeActiveTextEditor( 105 vscode.window.onDidChangeActiveTextEditor(
105 events.changeActiveTextEditor.makeHandler(syntaxTreeContentProvider) 106 events.changeActiveTextEditor.makeHandler(syntaxTreeContentProvider),
106 ); 107 );
107 108
108 disposeOnDeactivation( 109 disposeOnDeactivation(
109 vscode.workspace.registerTextDocumentContentProvider( 110 vscode.workspace.registerTextDocumentContentProvider(
110 'rust-analyzer', 111 'rust-analyzer',
111 syntaxTreeContentProvider 112 syntaxTreeContentProvider,
112 ) 113 ),
113 ); 114 );
114 disposeOnDeactivation( 115 disposeOnDeactivation(
115 vscode.workspace.registerTextDocumentContentProvider( 116 vscode.workspace.registerTextDocumentContentProvider(
116 'rust-analyzer', 117 'rust-analyzer',
117 expandMacroContentProvider 118 expandMacroContentProvider,
118 ) 119 ),
119 ); 120 );
120 121
121 registerCommand( 122 registerCommand(
122 'rust-analyzer.syntaxTree', 123 'rust-analyzer.syntaxTree',
123 commands.syntaxTree.createHandle(syntaxTreeContentProvider) 124 commands.syntaxTree.createHandle(syntaxTreeContentProvider),
124 ); 125 );
125 registerCommand( 126 registerCommand(
126 'rust-analyzer.expandMacro', 127 'rust-analyzer.expandMacro',
127 commands.expandMacro.createHandle(expandMacroContentProvider) 128 commands.expandMacro.createHandle(expandMacroContentProvider),
128 ); 129 );
129 130
130 vscode.workspace.onDidChangeTextDocument( 131 vscode.workspace.onDidChangeTextDocument(
131 events.changeTextDocument.createHandler(syntaxTreeContentProvider), 132 events.changeTextDocument.createHandler(syntaxTreeContentProvider),
132 null, 133 null,
133 context.subscriptions 134 context.subscriptions,
134 ); 135 );
135 136
136 const startServer = () => Server.start(allNotifications); 137 const startServer = () => Server.start(allNotifications);
@@ -159,7 +160,11 @@ export function activate(context: vscode.ExtensionContext) {
159 }); 160 });
160 161
161 // Start the language server, finally! 162 // Start the language server, finally!
162 startServer(); 163 try {
164 await startServer();
165 } catch (e) {
166 vscode.window.showErrorMessage(e.message);
167 }
163 168
164 if (Server.config.displayInlayHints) { 169 if (Server.config.displayInlayHints) {
165 const hintsUpdater = new HintsUpdater(); 170 const hintsUpdater = new HintsUpdater();
@@ -173,25 +178,25 @@ export function activate(context: vscode.ExtensionContext) {
173 editorChangeDisposable.dispose(); 178 editorChangeDisposable.dispose();
174 } 179 }
175 return hintsUpdater.refreshHintsForVisibleEditors(); 180 return hintsUpdater.refreshHintsForVisibleEditors();
176 } 181 },
177 ); 182 );
178 183
179 disposeOnDeactivation( 184 disposeOnDeactivation(
180 vscode.window.onDidChangeVisibleTextEditors(_ => 185 vscode.window.onDidChangeVisibleTextEditors(_ =>
181 hintsUpdater.refreshHintsForVisibleEditors() 186 hintsUpdater.refreshHintsForVisibleEditors(),
182 ) 187 ),
183 ); 188 );
184 disposeOnDeactivation( 189 disposeOnDeactivation(
185 vscode.workspace.onDidChangeTextDocument(e => 190 vscode.workspace.onDidChangeTextDocument(e =>
186 hintsUpdater.refreshHintsForVisibleEditors(e) 191 hintsUpdater.refreshHintsForVisibleEditors(e),
187 ) 192 ),
188 ); 193 );
189 disposeOnDeactivation( 194 disposeOnDeactivation(
190 vscode.workspace.onDidChangeConfiguration(_ => 195 vscode.workspace.onDidChangeConfiguration(_ =>
191 hintsUpdater.toggleHintsDisplay( 196 hintsUpdater.toggleHintsDisplay(
192 Server.config.displayInlayHints 197 Server.config.displayInlayHints,
193 ) 198 ),
194 ) 199 ),
195 ); 200 );
196 }); 201 });
197 } 202 }
@@ -204,10 +209,10 @@ export function deactivate(): Thenable<void> {
204 return Server.client.stop(); 209 return Server.client.stop();
205} 210}
206 211
207async function reloadServer(startServer: () => void) { 212async function reloadServer(startServer: () => Promise<void>) {
208 if (Server.client != null) { 213 if (Server.client != null) {
209 vscode.window.showInformationMessage('Reloading rust-analyzer...'); 214 vscode.window.showInformationMessage('Reloading rust-analyzer...');
210 await Server.client.stop(); 215 await Server.client.stop();
211 startServer(); 216 await startServer();
212 } 217 }
213} 218}
diff --git a/editors/code/src/highlighting.ts b/editors/code/src/highlighting.ts
index 0a38c9ef6..68eae0941 100644
--- a/editors/code/src/highlighting.ts
+++ b/editors/code/src/highlighting.ts
@@ -67,7 +67,7 @@ export class Highlighter {
67 > { 67 > {
68 const decoration = ( 68 const decoration = (
69 tag: string, 69 tag: string,
70 textDecoration?: string 70 textDecoration?: string,
71 ): [string, vscode.TextEditorDecorationType] => { 71 ): [string, vscode.TextEditorDecorationType] => {
72 const rule = scopesMapper.toRule(tag, scopes.find); 72 const rule = scopesMapper.toRule(tag, scopes.find);
73 73
@@ -90,9 +90,10 @@ export class Highlighter {
90 } 90 }
91 }; 91 };
92 92
93 const decorations: Iterable< 93 const decorations: Iterable<[
94 [string, vscode.TextEditorDecorationType] 94 string,
95 > = [ 95 vscode.TextEditorDecorationType,
96 ]> = [
96 decoration('comment'), 97 decoration('comment'),
97 decoration('string'), 98 decoration('string'),
98 decoration('keyword'), 99 decoration('keyword'),
@@ -101,16 +102,23 @@ export class Highlighter {
101 decoration('function'), 102 decoration('function'),
102 decoration('parameter'), 103 decoration('parameter'),
103 decoration('constant'), 104 decoration('constant'),
105 decoration('type.builtin'),
106 decoration('type.generic'),
107 decoration('type.lifetime'),
108 decoration('type.param'),
109 decoration('type.self'),
104 decoration('type'), 110 decoration('type'),
105 decoration('builtin'),
106 decoration('text'), 111 decoration('text'),
107 decoration('attribute'), 112 decoration('attribute'),
108 decoration('literal'), 113 decoration('literal'),
114 decoration('literal.numeric'),
115 decoration('literal.char'),
116 decoration('literal.byte'),
109 decoration('macro'), 117 decoration('macro'),
110 decoration('variable'), 118 decoration('variable'),
111 decoration('variable.mut', 'underline'), 119 decoration('variable.mut', 'underline'),
112 decoration('field'), 120 decoration('field'),
113 decoration('module') 121 decoration('module'),
114 ]; 122 ];
115 123
116 return new Map<string, vscode.TextEditorDecorationType>(decorations); 124 return new Map<string, vscode.TextEditorDecorationType>(decorations);
@@ -139,7 +147,6 @@ export class Highlighter {
139 // 147 //
140 // Note: decoration objects need to be kept around so we can dispose them 148 // Note: decoration objects need to be kept around so we can dispose them
141 // if the user disables syntax highlighting 149 // if the user disables syntax highlighting
142
143 if (this.decorations == null) { 150 if (this.decorations == null) {
144 this.decorations = Highlighter.initDecorations(); 151 this.decorations = Highlighter.initDecorations();
145 } 152 }
@@ -168,23 +175,22 @@ export class Highlighter {
168 colorfulIdents 175 colorfulIdents
169 .get(d.bindingHash)![0] 176 .get(d.bindingHash)![0]
170 .push( 177 .push(
171 Server.client.protocol2CodeConverter.asRange(d.range) 178 Server.client.protocol2CodeConverter.asRange(d.range),
172 ); 179 );
173 } else { 180 } else {
174 byTag 181 byTag
175 .get(d.tag)! 182 .get(d.tag)!
176 .push( 183 .push(
177 Server.client.protocol2CodeConverter.asRange(d.range) 184 Server.client.protocol2CodeConverter.asRange(d.range),
178 ); 185 );
179 } 186 }
180 } 187 }
181 188
182 for (const tag of byTag.keys()) { 189 for (const tag of byTag.keys()) {
183 const dec = this.decorations.get( 190 const dec = this.decorations.get(
184 tag 191 tag,
185 ) as vscode.TextEditorDecorationType; 192 ) as vscode.TextEditorDecorationType;
186 const ranges = byTag.get(tag)!; 193 const ranges = byTag.get(tag)!;
187
188 editor.setDecorations(dec, ranges); 194 editor.setDecorations(dec, ranges);
189 } 195 }
190 196
@@ -192,7 +198,7 @@ export class Highlighter {
192 const textDecoration = mut ? 'underline' : undefined; 198 const textDecoration = mut ? 'underline' : undefined;
193 const dec = vscode.window.createTextEditorDecorationType({ 199 const dec = vscode.window.createTextEditorDecorationType({
194 light: { color: fancify(hash, 'light'), textDecoration }, 200 light: { color: fancify(hash, 'light'), textDecoration },
195 dark: { color: fancify(hash, 'dark'), textDecoration } 201 dark: { color: fancify(hash, 'dark'), textDecoration },
196 }); 202 });
197 editor.setDecorations(dec, ranges); 203 editor.setDecorations(dec, ranges);
198 } 204 }
diff --git a/editors/code/src/notifications/publish_decorations.ts b/editors/code/src/notifications/publish_decorations.ts
index 3180019b7..f23e286ad 100644
--- a/editors/code/src/notifications/publish_decorations.ts
+++ b/editors/code/src/notifications/publish_decorations.ts
@@ -9,11 +9,16 @@ export interface PublishDecorationsParams {
9} 9}
10 10
11export function handle(params: PublishDecorationsParams) { 11export function handle(params: PublishDecorationsParams) {
12 const targetEditor = vscode.window.visibleTextEditors.find( 12 const targetEditor = vscode.window.visibleTextEditors.find(editor => {
13 editor => editor.document.uri.toString() === params.uri 13 const unescapedUri = unescape(editor.document.uri.toString());
14 ); 14 // Unescaped URI looks like:
15 // file:///c:/Workspace/ra-test/src/main.rs
16 return unescapedUri === params.uri;
17 });
18
15 if (!Server.config.highlightingOn || !targetEditor) { 19 if (!Server.config.highlightingOn || !targetEditor) {
16 return; 20 return;
17 } 21 }
22
18 Server.highlighter.setHighlights(targetEditor, params.decorations); 23 Server.highlighter.setHighlights(targetEditor, params.decorations);
19} 24}
diff --git a/editors/code/src/server.ts b/editors/code/src/server.ts
index 7907b70bc..5ace1d0fa 100644
--- a/editors/code/src/server.ts
+++ b/editors/code/src/server.ts
@@ -1,4 +1,5 @@
1import { homedir } from 'os'; 1import { lookpath } from 'lookpath';
2import { homedir, platform } from 'os';
2import * as lc from 'vscode-languageclient'; 3import * as lc from 'vscode-languageclient';
3 4
4import { window, workspace } from 'vscode'; 5import { window, workspace } from 'vscode';
@@ -17,8 +18,8 @@ export class Server {
17 public static config = new Config(); 18 public static config = new Config();
18 public static client: lc.LanguageClient; 19 public static client: lc.LanguageClient;
19 20
20 public static start( 21 public static async start(
21 notificationHandlers: Iterable<[string, lc.GenericNotificationHandler]> 22 notificationHandlers: Iterable<[string, lc.GenericNotificationHandler]>,
22 ) { 23 ) {
23 // '.' Is the fallback if no folder is open 24 // '.' Is the fallback if no folder is open
24 // TODO?: Workspace folders support Uri's (eg: file://test.txt). It might be a good idea to test if the uri points to a file. 25 // TODO?: Workspace folders support Uri's (eg: file://test.txt). It might be a good idea to test if the uri points to a file.
@@ -27,16 +28,26 @@ export class Server {
27 folder = workspace.workspaceFolders[0].uri.fsPath.toString(); 28 folder = workspace.workspaceFolders[0].uri.fsPath.toString();
28 } 29 }
29 30
31 const command = expandPathResolving(this.config.raLspServerPath);
32 // FIXME: remove check when the following issue is fixed:
33 // https://github.com/otiai10/lookpath/issues/4
34 if (platform() !== 'win32') {
35 if (!(await lookpath(command))) {
36 throw new Error(
37 `Cannot find rust-analyzer server \`${command}\` in PATH.`,
38 );
39 }
40 }
30 const run: lc.Executable = { 41 const run: lc.Executable = {
31 command: expandPathResolving(this.config.raLspServerPath), 42 command,
32 options: { cwd: folder } 43 options: { cwd: folder },
33 }; 44 };
34 const serverOptions: lc.ServerOptions = { 45 const serverOptions: lc.ServerOptions = {
35 run, 46 run,
36 debug: run 47 debug: run,
37 }; 48 };
38 const traceOutputChannel = window.createOutputChannel( 49 const traceOutputChannel = window.createOutputChannel(
39 'Rust Analyzer Language Server Trace' 50 'Rust Analyzer Language Server Trace',
40 ); 51 );
41 const clientOptions: lc.LanguageClientOptions = { 52 const clientOptions: lc.LanguageClientOptions = {
42 documentSelector: [{ scheme: 'file', language: 'rust' }], 53 documentSelector: [{ scheme: 'file', language: 'rust' }],
@@ -46,16 +57,18 @@ export class Server {
46 maxInlayHintLength: Server.config.maxInlayHintLength, 57 maxInlayHintLength: Server.config.maxInlayHintLength,
47 excludeGlobs: Server.config.excludeGlobs, 58 excludeGlobs: Server.config.excludeGlobs,
48 useClientWatching: Server.config.useClientWatching, 59 useClientWatching: Server.config.useClientWatching,
49 featureFlags: Server.config.featureFlags 60 featureFlags: Server.config.featureFlags,
61 withSysroot: Server.config.withSysroot,
62 cargoFeatures: Server.config.cargoFeatures,
50 }, 63 },
51 traceOutputChannel 64 traceOutputChannel,
52 }; 65 };
53 66
54 Server.client = new lc.LanguageClient( 67 Server.client = new lc.LanguageClient(
55 'rust-analyzer', 68 'rust-analyzer',
56 'Rust Analyzer Language Server', 69 'Rust Analyzer Language Server',
57 serverOptions, 70 serverOptions,
58 clientOptions 71 clientOptions,
59 ); 72 );
60 // HACK: This is an awful way of filtering out the decorations notifications 73 // HACK: This is an awful way of filtering out the decorations notifications
61 // However, pending proper support, this is the most effecitve approach 74 // However, pending proper support, this is the most effecitve approach
@@ -68,10 +81,10 @@ export class Server {
68 if (typeof messageOrDataObject === 'string') { 81 if (typeof messageOrDataObject === 'string') {
69 if ( 82 if (
70 messageOrDataObject.includes( 83 messageOrDataObject.includes(
71 'rust-analyzer/publishDecorations' 84 'rust-analyzer/publishDecorations',
72 ) || 85 ) ||
73 messageOrDataObject.includes( 86 messageOrDataObject.includes(
74 'rust-analyzer/decorationsRequest' 87 'rust-analyzer/decorationsRequest',
75 ) 88 )
76 ) { 89 ) {
77 // Don't log publish decorations requests 90 // Don't log publish decorations requests
@@ -83,7 +96,7 @@ export class Server {
83 // @ts-ignore 96 // @ts-ignore
84 Server.client.logObjectTrace(messageOrDataObject); 97 Server.client.logObjectTrace(messageOrDataObject);
85 } 98 }
86 } 99 },
87 }; 100 };
88 Server.client.registerProposedFeatures(); 101 Server.client.registerProposedFeatures();
89 Server.client.onReady().then(() => { 102 Server.client.onReady().then(() => {
diff --git a/editors/code/src/test/fixtures/rust-diagnostics/error/E0277.json b/editors/code/src/test/fixtures/rust-diagnostics/error/E0277.json
new file mode 100644
index 000000000..bfef33c7d
--- /dev/null
+++ b/editors/code/src/test/fixtures/rust-diagnostics/error/E0277.json
@@ -0,0 +1,261 @@
1{
2 "rendered": "error[E0277]: can't compare `{integer}` with `&str`\n --> src/main.rs:2:5\n |\n2 | assert_eq!(1, \"love\");\n | ^^^^^^^^^^^^^^^^^^^^^^ no implementation for `{integer} == &str`\n |\n = help: the trait `std::cmp::PartialEq<&str>` is not implemented for `{integer}`\n = note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info)\n\n",
3 "children": [
4 {
5 "children": [],
6 "code": null,
7 "level": "help",
8 "message": "the trait `std::cmp::PartialEq<&str>` is not implemented for `{integer}`",
9 "rendered": null,
10 "spans": []
11 }
12 ],
13 "code": {
14 "code": "E0277",
15 "explanation": "\nYou tried to use a type which doesn't implement some trait in a place which\nexpected that trait. Erroneous code example:\n\n```compile_fail,E0277\n// here we declare the Foo trait with a bar method\ntrait Foo {\n fn bar(&self);\n}\n\n// we now declare a function which takes an object implementing the Foo trait\nfn some_func<T: Foo>(foo: T) {\n foo.bar();\n}\n\nfn main() {\n // we now call the method with the i32 type, which doesn't implement\n // the Foo trait\n some_func(5i32); // error: the trait bound `i32 : Foo` is not satisfied\n}\n```\n\nIn order to fix this error, verify that the type you're using does implement\nthe trait. Example:\n\n```\ntrait Foo {\n fn bar(&self);\n}\n\nfn some_func<T: Foo>(foo: T) {\n foo.bar(); // we can now use this method since i32 implements the\n // Foo trait\n}\n\n// we implement the trait on the i32 type\nimpl Foo for i32 {\n fn bar(&self) {}\n}\n\nfn main() {\n some_func(5i32); // ok!\n}\n```\n\nOr in a generic context, an erroneous code example would look like:\n\n```compile_fail,E0277\nfn some_func<T>(foo: T) {\n println!(\"{:?}\", foo); // error: the trait `core::fmt::Debug` is not\n // implemented for the type `T`\n}\n\nfn main() {\n // We now call the method with the i32 type,\n // which *does* implement the Debug trait.\n some_func(5i32);\n}\n```\n\nNote that the error here is in the definition of the generic function: Although\nwe only call it with a parameter that does implement `Debug`, the compiler\nstill rejects the function: It must work with all possible input types. In\norder to make this example compile, we need to restrict the generic type we're\naccepting:\n\n```\nuse std::fmt;\n\n// Restrict the input type to types that implement Debug.\nfn some_func<T: fmt::Debug>(foo: T) {\n println!(\"{:?}\", foo);\n}\n\nfn main() {\n // Calling the method is still fine, as i32 implements Debug.\n some_func(5i32);\n\n // This would fail to compile now:\n // struct WithoutDebug;\n // some_func(WithoutDebug);\n}\n```\n\nRust only looks at the signature of the called function, as such it must\nalready specify all requirements that will be used for every type parameter.\n"
16 },
17 "level": "error",
18 "message": "can't compare `{integer}` with `&str`",
19 "spans": [
20 {
21 "byte_end": 155,
22 "byte_start": 153,
23 "column_end": 33,
24 "column_start": 31,
25 "expansion": {
26 "def_site_span": {
27 "byte_end": 940,
28 "byte_start": 0,
29 "column_end": 6,
30 "column_start": 1,
31 "expansion": null,
32 "file_name": "<::core::macros::assert_eq macros>",
33 "is_primary": false,
34 "label": null,
35 "line_end": 36,
36 "line_start": 1,
37 "suggested_replacement": null,
38 "suggestion_applicability": null,
39 "text": [
40 {
41 "highlight_end": 35,
42 "highlight_start": 1,
43 "text": "($ left : expr, $ right : expr) =>"
44 },
45 {
46 "highlight_end": 3,
47 "highlight_start": 1,
48 "text": "({"
49 },
50 {
51 "highlight_end": 33,
52 "highlight_start": 1,
53 "text": " match (& $ left, & $ right)"
54 },
55 {
56 "highlight_end": 7,
57 "highlight_start": 1,
58 "text": " {"
59 },
60 {
61 "highlight_end": 34,
62 "highlight_start": 1,
63 "text": " (left_val, right_val) =>"
64 },
65 {
66 "highlight_end": 11,
67 "highlight_start": 1,
68 "text": " {"
69 },
70 {
71 "highlight_end": 46,
72 "highlight_start": 1,
73 "text": " if ! (* left_val == * right_val)"
74 },
75 {
76 "highlight_end": 15,
77 "highlight_start": 1,
78 "text": " {"
79 },
80 {
81 "highlight_end": 25,
82 "highlight_start": 1,
83 "text": " panic !"
84 },
85 {
86 "highlight_end": 57,
87 "highlight_start": 1,
88 "text": " (r#\"assertion failed: `(left == right)`"
89 },
90 {
91 "highlight_end": 16,
92 "highlight_start": 1,
93 "text": " left: `{:?}`,"
94 },
95 {
96 "highlight_end": 18,
97 "highlight_start": 1,
98 "text": " right: `{:?}`\"#,"
99 },
100 {
101 "highlight_end": 47,
102 "highlight_start": 1,
103 "text": " & * left_val, & * right_val)"
104 },
105 {
106 "highlight_end": 15,
107 "highlight_start": 1,
108 "text": " }"
109 },
110 {
111 "highlight_end": 11,
112 "highlight_start": 1,
113 "text": " }"
114 },
115 {
116 "highlight_end": 7,
117 "highlight_start": 1,
118 "text": " }"
119 },
120 {
121 "highlight_end": 42,
122 "highlight_start": 1,
123 "text": " }) ; ($ left : expr, $ right : expr,) =>"
124 },
125 {
126 "highlight_end": 49,
127 "highlight_start": 1,
128 "text": "({ $ crate :: assert_eq ! ($ left, $ right) }) ;"
129 },
130 {
131 "highlight_end": 53,
132 "highlight_start": 1,
133 "text": "($ left : expr, $ right : expr, $ ($ arg : tt) +) =>"
134 },
135 {
136 "highlight_end": 3,
137 "highlight_start": 1,
138 "text": "({"
139 },
140 {
141 "highlight_end": 37,
142 "highlight_start": 1,
143 "text": " match (& ($ left), & ($ right))"
144 },
145 {
146 "highlight_end": 7,
147 "highlight_start": 1,
148 "text": " {"
149 },
150 {
151 "highlight_end": 34,
152 "highlight_start": 1,
153 "text": " (left_val, right_val) =>"
154 },
155 {
156 "highlight_end": 11,
157 "highlight_start": 1,
158 "text": " {"
159 },
160 {
161 "highlight_end": 46,
162 "highlight_start": 1,
163 "text": " if ! (* left_val == * right_val)"
164 },
165 {
166 "highlight_end": 15,
167 "highlight_start": 1,
168 "text": " {"
169 },
170 {
171 "highlight_end": 25,
172 "highlight_start": 1,
173 "text": " panic !"
174 },
175 {
176 "highlight_end": 57,
177 "highlight_start": 1,
178 "text": " (r#\"assertion failed: `(left == right)`"
179 },
180 {
181 "highlight_end": 16,
182 "highlight_start": 1,
183 "text": " left: `{:?}`,"
184 },
185 {
186 "highlight_end": 22,
187 "highlight_start": 1,
188 "text": " right: `{:?}`: {}\"#,"
189 },
190 {
191 "highlight_end": 72,
192 "highlight_start": 1,
193 "text": " & * left_val, & * right_val, $ crate :: format_args !"
194 },
195 {
196 "highlight_end": 33,
197 "highlight_start": 1,
198 "text": " ($ ($ arg) +))"
199 },
200 {
201 "highlight_end": 15,
202 "highlight_start": 1,
203 "text": " }"
204 },
205 {
206 "highlight_end": 11,
207 "highlight_start": 1,
208 "text": " }"
209 },
210 {
211 "highlight_end": 7,
212 "highlight_start": 1,
213 "text": " }"
214 },
215 {
216 "highlight_end": 6,
217 "highlight_start": 1,
218 "text": " }) ;"
219 }
220 ]
221 },
222 "macro_decl_name": "assert_eq!",
223 "span": {
224 "byte_end": 38,
225 "byte_start": 16,
226 "column_end": 27,
227 "column_start": 5,
228 "expansion": null,
229 "file_name": "src/main.rs",
230 "is_primary": false,
231 "label": null,
232 "line_end": 2,
233 "line_start": 2,
234 "suggested_replacement": null,
235 "suggestion_applicability": null,
236 "text": [
237 {
238 "highlight_end": 27,
239 "highlight_start": 5,
240 "text": " assert_eq!(1, \"love\");"
241 }
242 ]
243 }
244 },
245 "file_name": "<::core::macros::assert_eq macros>",
246 "is_primary": true,
247 "label": "no implementation for `{integer} == &str`",
248 "line_end": 7,
249 "line_start": 7,
250 "suggested_replacement": null,
251 "suggestion_applicability": null,
252 "text": [
253 {
254 "highlight_end": 33,
255 "highlight_start": 31,
256 "text": " if ! (* left_val == * right_val)"
257 }
258 ]
259 }
260 ]
261}
diff --git a/editors/code/src/test/utils/diagnotics/SuggestedFix.test.ts b/editors/code/src/test/utils/diagnotics/SuggestedFix.test.ts
index 6c7f436f3..2b25eb705 100644
--- a/editors/code/src/test/utils/diagnotics/SuggestedFix.test.ts
+++ b/editors/code/src/test/utils/diagnotics/SuggestedFix.test.ts
@@ -6,12 +6,12 @@ import SuggestedFix from '../../../utils/diagnostics/SuggestedFix';
6 6
7const location1 = new vscode.Location( 7const location1 = new vscode.Location(
8 vscode.Uri.file('/file/1'), 8 vscode.Uri.file('/file/1'),
9 new vscode.Range(new vscode.Position(1, 2), new vscode.Position(3, 4)) 9 new vscode.Range(new vscode.Position(1, 2), new vscode.Position(3, 4)),
10); 10);
11 11
12const location2 = new vscode.Location( 12const location2 = new vscode.Location(
13 vscode.Uri.file('/file/2'), 13 vscode.Uri.file('/file/2'),
14 new vscode.Range(new vscode.Position(5, 6), new vscode.Position(7, 8)) 14 new vscode.Range(new vscode.Position(5, 6), new vscode.Position(7, 8)),
15); 15);
16 16
17describe('SuggestedFix', () => { 17describe('SuggestedFix', () => {
@@ -20,13 +20,13 @@ describe('SuggestedFix', () => {
20 const suggestion1 = new SuggestedFix( 20 const suggestion1 = new SuggestedFix(
21 'Replace me!', 21 'Replace me!',
22 location1, 22 location1,
23 'With this!' 23 'With this!',
24 ); 24 );
25 25
26 const suggestion2 = new SuggestedFix( 26 const suggestion2 = new SuggestedFix(
27 'Replace me!', 27 'Replace me!',
28 location1, 28 location1,
29 'With this!' 29 'With this!',
30 ); 30 );
31 31
32 assert(suggestion1.isEqual(suggestion2)); 32 assert(suggestion1.isEqual(suggestion2));
@@ -36,13 +36,13 @@ describe('SuggestedFix', () => {
36 const suggestion1 = new SuggestedFix( 36 const suggestion1 = new SuggestedFix(
37 'Replace me!', 37 'Replace me!',
38 location1, 38 location1,
39 'With this!' 39 'With this!',
40 ); 40 );
41 41
42 const suggestion2 = new SuggestedFix( 42 const suggestion2 = new SuggestedFix(
43 'Not the same title!', 43 'Not the same title!',
44 location1, 44 location1,
45 'With this!' 45 'With this!',
46 ); 46 );
47 47
48 assert(!suggestion1.isEqual(suggestion2)); 48 assert(!suggestion1.isEqual(suggestion2));
@@ -52,13 +52,13 @@ describe('SuggestedFix', () => {
52 const suggestion1 = new SuggestedFix( 52 const suggestion1 = new SuggestedFix(
53 'Replace me!', 53 'Replace me!',
54 location1, 54 location1,
55 'With this!' 55 'With this!',
56 ); 56 );
57 57
58 const suggestion2 = new SuggestedFix( 58 const suggestion2 = new SuggestedFix(
59 'Replace me!', 59 'Replace me!',
60 location1, 60 location1,
61 'With something else!' 61 'With something else!',
62 ); 62 );
63 63
64 assert(!suggestion1.isEqual(suggestion2)); 64 assert(!suggestion1.isEqual(suggestion2));
@@ -68,13 +68,13 @@ describe('SuggestedFix', () => {
68 const suggestion1 = new SuggestedFix( 68 const suggestion1 = new SuggestedFix(
69 'Replace me!', 69 'Replace me!',
70 location1, 70 location1,
71 'With this!' 71 'With this!',
72 ); 72 );
73 73
74 const suggestion2 = new SuggestedFix( 74 const suggestion2 = new SuggestedFix(
75 'Replace me!', 75 'Replace me!',
76 location2, 76 location2,
77 'With this!' 77 'With this!',
78 ); 78 );
79 79
80 assert(!suggestion1.isEqual(suggestion2)); 80 assert(!suggestion1.isEqual(suggestion2));
@@ -85,14 +85,14 @@ describe('SuggestedFix', () => {
85 'Replace me!', 85 'Replace me!',
86 location1, 86 location1,
87 'With this!', 87 'With this!',
88 SuggestionApplicability.MachineApplicable 88 SuggestionApplicability.MachineApplicable,
89 ); 89 );
90 90
91 const suggestion2 = new SuggestedFix( 91 const suggestion2 = new SuggestedFix(
92 'Replace me!', 92 'Replace me!',
93 location2, 93 location2,
94 'With this!', 94 'With this!',
95 SuggestionApplicability.HasPlaceholders 95 SuggestionApplicability.HasPlaceholders,
96 ); 96 );
97 97
98 assert(!suggestion1.isEqual(suggestion2)); 98 assert(!suggestion1.isEqual(suggestion2));
@@ -104,7 +104,7 @@ describe('SuggestedFix', () => {
104 const suggestion = new SuggestedFix( 104 const suggestion = new SuggestedFix(
105 'Replace me!', 105 'Replace me!',
106 location1, 106 location1,
107 'With this!' 107 'With this!',
108 ); 108 );
109 109
110 const codeAction = suggestion.toCodeAction(); 110 const codeAction = suggestion.toCodeAction();
@@ -114,7 +114,8 @@ describe('SuggestedFix', () => {
114 114
115 const edit = codeAction.edit; 115 const edit = codeAction.edit;
116 if (!edit) { 116 if (!edit) {
117 return assert.fail('Code Action edit unexpectedly missing'); 117 assert.fail('Code Action edit unexpectedly missing');
118 return;
118 } 119 }
119 120
120 const editEntries = edit.entries(); 121 const editEntries = edit.entries();
diff --git a/editors/code/src/test/utils/diagnotics/SuggestedFixCollection.test.ts b/editors/code/src/test/utils/diagnotics/SuggestedFixCollection.test.ts
index f0328893e..ef09013f4 100644
--- a/editors/code/src/test/utils/diagnotics/SuggestedFixCollection.test.ts
+++ b/editors/code/src/test/utils/diagnotics/SuggestedFixCollection.test.ts
@@ -8,20 +8,20 @@ const uri1 = vscode.Uri.file('/file/1');
8const uri2 = vscode.Uri.file('/file/2'); 8const uri2 = vscode.Uri.file('/file/2');
9 9
10const mockDocument1 = ({ 10const mockDocument1 = ({
11 uri: uri1 11 uri: uri1,
12} as unknown) as vscode.TextDocument; 12} as unknown) as vscode.TextDocument;
13 13
14const mockDocument2 = ({ 14const mockDocument2 = ({
15 uri: uri2 15 uri: uri2,
16} as unknown) as vscode.TextDocument; 16} as unknown) as vscode.TextDocument;
17 17
18const range1 = new vscode.Range( 18const range1 = new vscode.Range(
19 new vscode.Position(1, 2), 19 new vscode.Position(1, 2),
20 new vscode.Position(3, 4) 20 new vscode.Position(3, 4),
21); 21);
22const range2 = new vscode.Range( 22const range2 = new vscode.Range(
23 new vscode.Position(5, 6), 23 new vscode.Position(5, 6),
24 new vscode.Position(7, 8) 24 new vscode.Position(7, 8),
25); 25);
26 26
27const diagnostic1 = new vscode.Diagnostic(range1, 'First diagnostic'); 27const diagnostic1 = new vscode.Diagnostic(range1, 'First diagnostic');
@@ -32,7 +32,7 @@ function suggestion1(): SuggestedFix {
32 return new SuggestedFix( 32 return new SuggestedFix(
33 'Replace me!', 33 'Replace me!',
34 new vscode.Location(uri1, range1), 34 new vscode.Location(uri1, range1),
35 'With this!' 35 'With this!',
36 ); 36 );
37} 37}
38 38
@@ -44,7 +44,7 @@ describe('SuggestedFixCollection', () => {
44 // Specify the document and range that exactly matches 44 // Specify the document and range that exactly matches
45 const codeActions = suggestedFixes.provideCodeActions( 45 const codeActions = suggestedFixes.provideCodeActions(
46 mockDocument1, 46 mockDocument1,
47 range1 47 range1,
48 ); 48 );
49 49
50 assert.strictEqual(codeActions.length, 1); 50 assert.strictEqual(codeActions.length, 1);
@@ -53,7 +53,8 @@ describe('SuggestedFixCollection', () => {
53 53
54 const { diagnostics } = codeAction; 54 const { diagnostics } = codeAction;
55 if (!diagnostics) { 55 if (!diagnostics) {
56 return assert.fail('Diagnostics unexpectedly missing'); 56 assert.fail('Diagnostics unexpectedly missing');
57 return;
57 } 58 }
58 59
59 assert.strictEqual(diagnostics.length, 1); 60 assert.strictEqual(diagnostics.length, 1);
@@ -66,7 +67,7 @@ describe('SuggestedFixCollection', () => {
66 67
67 const codeActions = suggestedFixes.provideCodeActions( 68 const codeActions = suggestedFixes.provideCodeActions(
68 mockDocument1, 69 mockDocument1,
69 range2 70 range2,
70 ); 71 );
71 72
72 assert(!codeActions || codeActions.length === 0); 73 assert(!codeActions || codeActions.length === 0);
@@ -78,7 +79,7 @@ describe('SuggestedFixCollection', () => {
78 79
79 const codeActions = suggestedFixes.provideCodeActions( 80 const codeActions = suggestedFixes.provideCodeActions(
80 mockDocument2, 81 mockDocument2,
81 range1 82 range1,
82 ); 83 );
83 84
84 assert(!codeActions || codeActions.length === 0); 85 assert(!codeActions || codeActions.length === 0);
@@ -91,7 +92,7 @@ describe('SuggestedFixCollection', () => {
91 92
92 const codeActions = suggestedFixes.provideCodeActions( 93 const codeActions = suggestedFixes.provideCodeActions(
93 mockDocument1, 94 mockDocument1,
94 range1 95 range1,
95 ); 96 );
96 97
97 assert(!codeActions || codeActions.length === 0); 98 assert(!codeActions || codeActions.length === 0);
@@ -106,7 +107,7 @@ describe('SuggestedFixCollection', () => {
106 107
107 const codeActions = suggestedFixes.provideCodeActions( 108 const codeActions = suggestedFixes.provideCodeActions(
108 mockDocument1, 109 mockDocument1,
109 range1 110 range1,
110 ); 111 );
111 112
112 assert.strictEqual(codeActions.length, 1); 113 assert.strictEqual(codeActions.length, 1);
@@ -114,7 +115,8 @@ describe('SuggestedFixCollection', () => {
114 const { diagnostics } = codeAction; 115 const { diagnostics } = codeAction;
115 116
116 if (!diagnostics) { 117 if (!diagnostics) {
117 return assert.fail('Diagnostics unexpectedly missing'); 118 assert.fail('Diagnostics unexpectedly missing');
119 return;
118 } 120 }
119 121
120 // We should be associated with both diagnostics 122 // We should be associated with both diagnostics
diff --git a/editors/code/src/test/utils/diagnotics/rust.test.ts b/editors/code/src/test/utils/diagnotics/rust.test.ts
index 327d15046..358325cc8 100644
--- a/editors/code/src/test/utils/diagnotics/rust.test.ts
+++ b/editors/code/src/test/utils/diagnotics/rust.test.ts
@@ -6,14 +6,14 @@ import {
6 MappedRustDiagnostic, 6 MappedRustDiagnostic,
7 mapRustDiagnosticToVsCode, 7 mapRustDiagnosticToVsCode,
8 RustDiagnostic, 8 RustDiagnostic,
9 SuggestionApplicability 9 SuggestionApplicability,
10} from '../../../utils/diagnostics/rust'; 10} from '../../../utils/diagnostics/rust';
11 11
12function loadDiagnosticFixture(name: string): RustDiagnostic { 12function loadDiagnosticFixture(name: string): RustDiagnostic {
13 const jsonText = fs 13 const jsonText = fs
14 .readFileSync( 14 .readFileSync(
15 // We're actually in our JavaScript output directory, climb out 15 // We're actually in our JavaScript output directory, climb out
16 `${__dirname}/../../../../src/test/fixtures/rust-diagnostics/${name}.json` 16 `${__dirname}/../../../../src/test/fixtures/rust-diagnostics/${name}.json`,
17 ) 17 )
18 .toString(); 18 .toString();
19 19
@@ -33,12 +33,12 @@ function mapFixtureToVsCode(name: string): MappedRustDiagnostic {
33describe('mapRustDiagnosticToVsCode', () => { 33describe('mapRustDiagnosticToVsCode', () => {
34 it('should map an incompatible type for trait error', () => { 34 it('should map an incompatible type for trait error', () => {
35 const { diagnostic, suggestedFixes } = mapFixtureToVsCode( 35 const { diagnostic, suggestedFixes } = mapFixtureToVsCode(
36 'error/E0053' 36 'error/E0053',
37 ); 37 );
38 38
39 assert.strictEqual( 39 assert.strictEqual(
40 diagnostic.severity, 40 diagnostic.severity,
41 vscode.DiagnosticSeverity.Error 41 vscode.DiagnosticSeverity.Error,
42 ); 42 );
43 assert.strictEqual(diagnostic.source, 'rustc'); 43 assert.strictEqual(diagnostic.source, 'rustc');
44 assert.strictEqual( 44 assert.strictEqual(
@@ -46,8 +46,8 @@ describe('mapRustDiagnosticToVsCode', () => {
46 [ 46 [
47 `method \`next\` has an incompatible type for trait`, 47 `method \`next\` has an incompatible type for trait`,
48 `expected type \`fn(&mut ty::list_iter::ListIterator<'list, M>) -> std::option::Option<&ty::Ref<M>>\``, 48 `expected type \`fn(&mut ty::list_iter::ListIterator<'list, M>) -> std::option::Option<&ty::Ref<M>>\``,
49 ` found type \`fn(&ty::list_iter::ListIterator<'list, M>) -> std::option::Option<&'list ty::Ref<M>>\`` 49 ` found type \`fn(&ty::list_iter::ListIterator<'list, M>) -> std::option::Option<&'list ty::Ref<M>>\``,
50 ].join('\n') 50 ].join('\n'),
51 ); 51 );
52 assert.strictEqual(diagnostic.code, 'E0053'); 52 assert.strictEqual(diagnostic.code, 'E0053');
53 assert.deepStrictEqual(diagnostic.tags, []); 53 assert.deepStrictEqual(diagnostic.tags, []);
@@ -61,24 +61,24 @@ describe('mapRustDiagnosticToVsCode', () => {
61 61
62 it('should map an unused variable warning', () => { 62 it('should map an unused variable warning', () => {
63 const { diagnostic, suggestedFixes } = mapFixtureToVsCode( 63 const { diagnostic, suggestedFixes } = mapFixtureToVsCode(
64 'warning/unused_variables' 64 'warning/unused_variables',
65 ); 65 );
66 66
67 assert.strictEqual( 67 assert.strictEqual(
68 diagnostic.severity, 68 diagnostic.severity,
69 vscode.DiagnosticSeverity.Warning 69 vscode.DiagnosticSeverity.Warning,
70 ); 70 );
71 assert.strictEqual( 71 assert.strictEqual(
72 diagnostic.message, 72 diagnostic.message,
73 [ 73 [
74 'unused variable: `foo`', 74 'unused variable: `foo`',
75 '#[warn(unused_variables)] on by default' 75 '#[warn(unused_variables)] on by default',
76 ].join('\n') 76 ].join('\n'),
77 ); 77 );
78 assert.strictEqual(diagnostic.code, 'unused_variables'); 78 assert.strictEqual(diagnostic.code, 'unused_variables');
79 assert.strictEqual(diagnostic.source, 'rustc'); 79 assert.strictEqual(diagnostic.source, 'rustc');
80 assert.deepStrictEqual(diagnostic.tags, [ 80 assert.deepStrictEqual(diagnostic.tags, [
81 vscode.DiagnosticTag.Unnecessary 81 vscode.DiagnosticTag.Unnecessary,
82 ]); 82 ]);
83 83
84 // No related information 84 // No related information
@@ -89,29 +89,29 @@ describe('mapRustDiagnosticToVsCode', () => {
89 const [suggestedFix] = suggestedFixes; 89 const [suggestedFix] = suggestedFixes;
90 assert.strictEqual( 90 assert.strictEqual(
91 suggestedFix.title, 91 suggestedFix.title,
92 'consider prefixing with an underscore: `_foo`' 92 'consider prefixing with an underscore: `_foo`',
93 ); 93 );
94 assert.strictEqual( 94 assert.strictEqual(
95 suggestedFix.applicability, 95 suggestedFix.applicability,
96 SuggestionApplicability.MachineApplicable 96 SuggestionApplicability.MachineApplicable,
97 ); 97 );
98 }); 98 });
99 99
100 it('should map a wrong number of parameters error', () => { 100 it('should map a wrong number of parameters error', () => {
101 const { diagnostic, suggestedFixes } = mapFixtureToVsCode( 101 const { diagnostic, suggestedFixes } = mapFixtureToVsCode(
102 'error/E0061' 102 'error/E0061',
103 ); 103 );
104 104
105 assert.strictEqual( 105 assert.strictEqual(
106 diagnostic.severity, 106 diagnostic.severity,
107 vscode.DiagnosticSeverity.Error 107 vscode.DiagnosticSeverity.Error,
108 ); 108 );
109 assert.strictEqual( 109 assert.strictEqual(
110 diagnostic.message, 110 diagnostic.message,
111 [ 111 [
112 'this function takes 2 parameters but 3 parameters were supplied', 112 'this function takes 2 parameters but 3 parameters were supplied',
113 'expected 2 parameters' 113 'expected 2 parameters',
114 ].join('\n') 114 ].join('\n'),
115 ); 115 );
116 assert.strictEqual(diagnostic.code, 'E0061'); 116 assert.strictEqual(diagnostic.code, 'E0061');
117 assert.strictEqual(diagnostic.source, 'rustc'); 117 assert.strictEqual(diagnostic.source, 'rustc');
@@ -120,7 +120,8 @@ describe('mapRustDiagnosticToVsCode', () => {
120 // One related information for the original definition 120 // One related information for the original definition
121 const relatedInformation = diagnostic.relatedInformation; 121 const relatedInformation = diagnostic.relatedInformation;
122 if (!relatedInformation) { 122 if (!relatedInformation) {
123 return assert.fail('Related information unexpectedly undefined'); 123 assert.fail('Related information unexpectedly undefined');
124 return;
124 } 125 }
125 assert.strictEqual(relatedInformation.length, 1); 126 assert.strictEqual(relatedInformation.length, 1);
126 const [related] = relatedInformation; 127 const [related] = relatedInformation;
@@ -132,12 +133,12 @@ describe('mapRustDiagnosticToVsCode', () => {
132 133
133 it('should map a Clippy copy pass by ref warning', () => { 134 it('should map a Clippy copy pass by ref warning', () => {
134 const { diagnostic, suggestedFixes } = mapFixtureToVsCode( 135 const { diagnostic, suggestedFixes } = mapFixtureToVsCode(
135 'clippy/trivially_copy_pass_by_ref' 136 'clippy/trivially_copy_pass_by_ref',
136 ); 137 );
137 138
138 assert.strictEqual( 139 assert.strictEqual(
139 diagnostic.severity, 140 diagnostic.severity,
140 vscode.DiagnosticSeverity.Warning 141 vscode.DiagnosticSeverity.Warning,
141 ); 142 );
142 assert.strictEqual(diagnostic.source, 'clippy'); 143 assert.strictEqual(diagnostic.source, 'clippy');
143 assert.strictEqual( 144 assert.strictEqual(
@@ -145,8 +146,8 @@ describe('mapRustDiagnosticToVsCode', () => {
145 [ 146 [
146 'this argument is passed by reference, but would be more efficient if passed by value', 147 'this argument is passed by reference, but would be more efficient if passed by value',
147 '#[warn(clippy::trivially_copy_pass_by_ref)] implied by #[warn(clippy::all)]', 148 '#[warn(clippy::trivially_copy_pass_by_ref)] implied by #[warn(clippy::all)]',
148 'for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#trivially_copy_pass_by_ref' 149 'for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#trivially_copy_pass_by_ref',
149 ].join('\n') 150 ].join('\n'),
150 ); 151 );
151 assert.strictEqual(diagnostic.code, 'trivially_copy_pass_by_ref'); 152 assert.strictEqual(diagnostic.code, 'trivially_copy_pass_by_ref');
152 assert.deepStrictEqual(diagnostic.tags, []); 153 assert.deepStrictEqual(diagnostic.tags, []);
@@ -154,7 +155,8 @@ describe('mapRustDiagnosticToVsCode', () => {
154 // One related information for the lint definition 155 // One related information for the lint definition
155 const relatedInformation = diagnostic.relatedInformation; 156 const relatedInformation = diagnostic.relatedInformation;
156 if (!relatedInformation) { 157 if (!relatedInformation) {
157 return assert.fail('Related information unexpectedly undefined'); 158 assert.fail('Related information unexpectedly undefined');
159 return;
158 } 160 }
159 assert.strictEqual(relatedInformation.length, 1); 161 assert.strictEqual(relatedInformation.length, 1);
160 const [related] = relatedInformation; 162 const [related] = relatedInformation;
@@ -165,27 +167,27 @@ describe('mapRustDiagnosticToVsCode', () => {
165 const [suggestedFix] = suggestedFixes; 167 const [suggestedFix] = suggestedFixes;
166 assert.strictEqual( 168 assert.strictEqual(
167 suggestedFix.title, 169 suggestedFix.title,
168 'consider passing by value instead: `self`' 170 'consider passing by value instead: `self`',
169 ); 171 );
170 // Clippy does not mark this with any applicability 172 // Clippy does not mark this with any applicability
171 assert.strictEqual( 173 assert.strictEqual(
172 suggestedFix.applicability, 174 suggestedFix.applicability,
173 SuggestionApplicability.Unspecified 175 SuggestionApplicability.Unspecified,
174 ); 176 );
175 }); 177 });
176 178
177 it('should map a mismatched type error', () => { 179 it('should map a mismatched type error', () => {
178 const { diagnostic, suggestedFixes } = mapFixtureToVsCode( 180 const { diagnostic, suggestedFixes } = mapFixtureToVsCode(
179 'error/E0308' 181 'error/E0308',
180 ); 182 );
181 183
182 assert.strictEqual( 184 assert.strictEqual(
183 diagnostic.severity, 185 diagnostic.severity,
184 vscode.DiagnosticSeverity.Error 186 vscode.DiagnosticSeverity.Error,
185 ); 187 );
186 assert.strictEqual( 188 assert.strictEqual(
187 diagnostic.message, 189 diagnostic.message,
188 ['mismatched types', 'expected usize, found u32'].join('\n') 190 ['mismatched types', 'expected usize, found u32'].join('\n'),
189 ); 191 );
190 assert.strictEqual(diagnostic.code, 'E0308'); 192 assert.strictEqual(diagnostic.code, 'E0308');
191 assert.strictEqual(diagnostic.source, 'rustc'); 193 assert.strictEqual(diagnostic.source, 'rustc');
@@ -197,4 +199,38 @@ describe('mapRustDiagnosticToVsCode', () => {
197 // There are no suggested fixes 199 // There are no suggested fixes
198 assert.strictEqual(suggestedFixes.length, 0); 200 assert.strictEqual(suggestedFixes.length, 0);
199 }); 201 });
202
203 it('should map a macro invocation location to normal file path', () => {
204 const { location, diagnostic, suggestedFixes } = mapFixtureToVsCode(
205 'error/E0277',
206 );
207
208 assert.strictEqual(
209 diagnostic.severity,
210 vscode.DiagnosticSeverity.Error,
211 );
212 assert.strictEqual(
213 diagnostic.message,
214 [
215 "can't compare `{integer}` with `&str`",
216 'the trait `std::cmp::PartialEq<&str>` is not implemented for `{integer}`',
217 ].join('\n'),
218 );
219 assert.strictEqual(diagnostic.code, 'E0277');
220 assert.strictEqual(diagnostic.source, 'rustc');
221 assert.deepStrictEqual(diagnostic.tags, []);
222
223 // No related information
224 assert.deepStrictEqual(diagnostic.relatedInformation, []);
225
226 // There are no suggested fixes
227 assert.strictEqual(suggestedFixes.length, 0);
228
229 // The file url should be normal file
230 // Ignore the first part because it depends on vs workspace location
231 assert.strictEqual(
232 location.uri.path.substr(-'src/main.rs'.length),
233 'src/main.rs',
234 );
235 });
200}); 236});
diff --git a/editors/code/src/test/utils/diagnotics/vscode.test.ts b/editors/code/src/test/utils/diagnotics/vscode.test.ts
index 542dec1f5..4944dd032 100644
--- a/editors/code/src/test/utils/diagnotics/vscode.test.ts
+++ b/editors/code/src/test/utils/diagnotics/vscode.test.ts
@@ -5,12 +5,12 @@ import { areDiagnosticsEqual } from '../../../utils/diagnostics/vscode';
5 5
6const range1 = new vscode.Range( 6const range1 = new vscode.Range(
7 new vscode.Position(1, 2), 7 new vscode.Position(1, 2),
8 new vscode.Position(3, 4) 8 new vscode.Position(3, 4),
9); 9);
10 10
11const range2 = new vscode.Range( 11const range2 = new vscode.Range(
12 new vscode.Position(5, 6), 12 new vscode.Position(5, 6),
13 new vscode.Position(7, 8) 13 new vscode.Position(7, 8),
14); 14);
15 15
16describe('areDiagnosticsEqual', () => { 16describe('areDiagnosticsEqual', () => {
@@ -18,13 +18,13 @@ describe('areDiagnosticsEqual', () => {
18 const diagnostic1 = new vscode.Diagnostic( 18 const diagnostic1 = new vscode.Diagnostic(
19 range1, 19 range1,
20 'Hello, world!', 20 'Hello, world!',
21 vscode.DiagnosticSeverity.Error 21 vscode.DiagnosticSeverity.Error,
22 ); 22 );
23 23
24 const diagnostic2 = new vscode.Diagnostic( 24 const diagnostic2 = new vscode.Diagnostic(
25 range1, 25 range1,
26 'Hello, world!', 26 'Hello, world!',
27 vscode.DiagnosticSeverity.Error 27 vscode.DiagnosticSeverity.Error,
28 ); 28 );
29 29
30 assert(areDiagnosticsEqual(diagnostic1, diagnostic2)); 30 assert(areDiagnosticsEqual(diagnostic1, diagnostic2));
@@ -34,14 +34,14 @@ describe('areDiagnosticsEqual', () => {
34 const diagnostic1 = new vscode.Diagnostic( 34 const diagnostic1 = new vscode.Diagnostic(
35 range1, 35 range1,
36 'Hello, world!', 36 'Hello, world!',
37 vscode.DiagnosticSeverity.Error 37 vscode.DiagnosticSeverity.Error,
38 ); 38 );
39 diagnostic1.source = 'rustc'; 39 diagnostic1.source = 'rustc';
40 40
41 const diagnostic2 = new vscode.Diagnostic( 41 const diagnostic2 = new vscode.Diagnostic(
42 range1, 42 range1,
43 'Hello, world!', 43 'Hello, world!',
44 vscode.DiagnosticSeverity.Error 44 vscode.DiagnosticSeverity.Error,
45 ); 45 );
46 diagnostic2.source = 'clippy'; 46 diagnostic2.source = 'clippy';
47 47
@@ -52,13 +52,13 @@ describe('areDiagnosticsEqual', () => {
52 const diagnostic1 = new vscode.Diagnostic( 52 const diagnostic1 = new vscode.Diagnostic(
53 range1, 53 range1,
54 'Hello, world!', 54 'Hello, world!',
55 vscode.DiagnosticSeverity.Error 55 vscode.DiagnosticSeverity.Error,
56 ); 56 );
57 57
58 const diagnostic2 = new vscode.Diagnostic( 58 const diagnostic2 = new vscode.Diagnostic(
59 range2, 59 range2,
60 'Hello, world!', 60 'Hello, world!',
61 vscode.DiagnosticSeverity.Error 61 vscode.DiagnosticSeverity.Error,
62 ); 62 );
63 63
64 assert(!areDiagnosticsEqual(diagnostic1, diagnostic2)); 64 assert(!areDiagnosticsEqual(diagnostic1, diagnostic2));
@@ -68,13 +68,13 @@ describe('areDiagnosticsEqual', () => {
68 const diagnostic1 = new vscode.Diagnostic( 68 const diagnostic1 = new vscode.Diagnostic(
69 range1, 69 range1,
70 'Hello, world!', 70 'Hello, world!',
71 vscode.DiagnosticSeverity.Error 71 vscode.DiagnosticSeverity.Error,
72 ); 72 );
73 73
74 const diagnostic2 = new vscode.Diagnostic( 74 const diagnostic2 = new vscode.Diagnostic(
75 range1, 75 range1,
76 'Goodbye!, world!', 76 'Goodbye!, world!',
77 vscode.DiagnosticSeverity.Error 77 vscode.DiagnosticSeverity.Error,
78 ); 78 );
79 79
80 assert(!areDiagnosticsEqual(diagnostic1, diagnostic2)); 80 assert(!areDiagnosticsEqual(diagnostic1, diagnostic2));
@@ -84,13 +84,13 @@ describe('areDiagnosticsEqual', () => {
84 const diagnostic1 = new vscode.Diagnostic( 84 const diagnostic1 = new vscode.Diagnostic(
85 range1, 85 range1,
86 'Hello, world!', 86 'Hello, world!',
87 vscode.DiagnosticSeverity.Warning 87 vscode.DiagnosticSeverity.Warning,
88 ); 88 );
89 89
90 const diagnostic2 = new vscode.Diagnostic( 90 const diagnostic2 = new vscode.Diagnostic(
91 range1, 91 range1,
92 'Hello, world!', 92 'Hello, world!',
93 vscode.DiagnosticSeverity.Error 93 vscode.DiagnosticSeverity.Error,
94 ); 94 );
95 95
96 assert(!areDiagnosticsEqual(diagnostic1, diagnostic2)); 96 assert(!areDiagnosticsEqual(diagnostic1, diagnostic2));
diff --git a/editors/code/src/test/utils/index.ts b/editors/code/src/test/utils/index.ts
index 16715a286..9927daaf6 100644
--- a/editors/code/src/test/utils/index.ts
+++ b/editors/code/src/test/utils/index.ts
@@ -17,7 +17,7 @@ import * as path from 'path';
17export function run(): Promise<void> { 17export function run(): Promise<void> {
18 // Create the mocha test 18 // Create the mocha test
19 const mocha = new Mocha({ 19 const mocha = new Mocha({
20 ui: 'bdd' 20 ui: 'bdd',
21 }); 21 });
22 mocha.useColors(true); 22 mocha.useColors(true);
23 23
diff --git a/editors/code/src/utils/diagnostics/SuggestedFix.ts b/editors/code/src/utils/diagnostics/SuggestedFix.ts
index b1be2a225..6e660bb61 100644
--- a/editors/code/src/utils/diagnostics/SuggestedFix.ts
+++ b/editors/code/src/utils/diagnostics/SuggestedFix.ts
@@ -24,7 +24,7 @@ export default class SuggestedFix {
24 title: string, 24 title: string,
25 location: vscode.Location, 25 location: vscode.Location,
26 replacement: string, 26 replacement: string,
27 applicability: SuggestionApplicability = SuggestionApplicability.Unspecified 27 applicability: SuggestionApplicability = SuggestionApplicability.Unspecified,
28 ) { 28 ) {
29 this.title = title; 29 this.title = title;
30 this.location = location; 30 this.location = location;
@@ -51,7 +51,7 @@ export default class SuggestedFix {
51 public toCodeAction(): vscode.CodeAction { 51 public toCodeAction(): vscode.CodeAction {
52 const codeAction = new vscode.CodeAction( 52 const codeAction = new vscode.CodeAction(
53 this.title, 53 this.title,
54 vscode.CodeActionKind.QuickFix 54 vscode.CodeActionKind.QuickFix,
55 ); 55 );
56 56
57 const edit = new vscode.WorkspaceEdit(); 57 const edit = new vscode.WorkspaceEdit();
diff --git a/editors/code/src/utils/diagnostics/SuggestedFixCollection.ts b/editors/code/src/utils/diagnostics/SuggestedFixCollection.ts
index 132ce12f8..57c9856cf 100644
--- a/editors/code/src/utils/diagnostics/SuggestedFixCollection.ts
+++ b/editors/code/src/utils/diagnostics/SuggestedFixCollection.ts
@@ -38,13 +38,13 @@ export default class SuggestedFixCollection
38 */ 38 */
39 public addSuggestedFixForDiagnostic( 39 public addSuggestedFixForDiagnostic(
40 suggestedFix: SuggestedFix, 40 suggestedFix: SuggestedFix,
41 diagnostic: vscode.Diagnostic 41 diagnostic: vscode.Diagnostic,
42 ): void { 42 ): void {
43 const fileUriString = suggestedFix.location.uri.toString(); 43 const fileUriString = suggestedFix.location.uri.toString();
44 const fileSuggestions = this.suggestedFixes.get(fileUriString) || []; 44 const fileSuggestions = this.suggestedFixes.get(fileUriString) || [];
45 45
46 const existingSuggestion = fileSuggestions.find(s => 46 const existingSuggestion = fileSuggestions.find(s =>
47 s.isEqual(suggestedFix) 47 s.isEqual(suggestedFix),
48 ); 48 );
49 49
50 if (existingSuggestion) { 50 if (existingSuggestion) {
@@ -65,7 +65,7 @@ export default class SuggestedFixCollection
65 */ 65 */
66 public provideCodeActions( 66 public provideCodeActions(
67 document: vscode.TextDocument, 67 document: vscode.TextDocument,
68 range: vscode.Range 68 range: vscode.Range,
69 ): vscode.CodeAction[] { 69 ): vscode.CodeAction[] {
70 const documentUriString = document.uri.toString(); 70 const documentUriString = document.uri.toString();
71 71
diff --git a/editors/code/src/utils/diagnostics/rust.ts b/editors/code/src/utils/diagnostics/rust.ts
index 0550d0372..1f0c0d3e4 100644
--- a/editors/code/src/utils/diagnostics/rust.ts
+++ b/editors/code/src/utils/diagnostics/rust.ts
@@ -7,7 +7,13 @@ export enum SuggestionApplicability {
7 MachineApplicable = 'MachineApplicable', 7 MachineApplicable = 'MachineApplicable',
8 HasPlaceholders = 'HasPlaceholders', 8 HasPlaceholders = 'HasPlaceholders',
9 MaybeIncorrect = 'MaybeIncorrect', 9 MaybeIncorrect = 'MaybeIncorrect',
10 Unspecified = 'Unspecified' 10 Unspecified = 'Unspecified',
11}
12
13export interface RustDiagnosticSpanMacroExpansion {
14 span: RustDiagnosticSpan;
15 macro_decl_name: string;
16 def_site_span?: RustDiagnosticSpan;
11} 17}
12 18
13// Reference: 19// Reference:
@@ -20,6 +26,7 @@ export interface RustDiagnosticSpan {
20 is_primary: boolean; 26 is_primary: boolean;
21 file_name: string; 27 file_name: string;
22 label?: string; 28 label?: string;
29 expansion?: RustDiagnosticSpanMacroExpansion;
23 suggested_replacement?: string; 30 suggested_replacement?: string;
24 suggestion_applicability?: SuggestionApplicability; 31 suggestion_applicability?: SuggestionApplicability;
25} 32}
@@ -61,15 +68,46 @@ function mapLevelToSeverity(s: string): vscode.DiagnosticSeverity {
61} 68}
62 69
63/** 70/**
71 * Check whether a file name is from macro invocation
72 */
73function isFromMacro(fileName: string): boolean {
74 return fileName.startsWith('<') && fileName.endsWith('>');
75}
76
77/**
78 * Converts a Rust macro span to a VsCode location recursively
79 */
80function mapMacroSpanToLocation(
81 spanMacro: RustDiagnosticSpanMacroExpansion,
82): vscode.Location | undefined {
83 if (!isFromMacro(spanMacro.span.file_name)) {
84 return mapSpanToLocation(spanMacro.span);
85 }
86
87 if (spanMacro.span.expansion) {
88 return mapMacroSpanToLocation(spanMacro.span.expansion);
89 }
90
91 return;
92}
93
94/**
64 * Converts a Rust span to a VsCode location 95 * Converts a Rust span to a VsCode location
65 */ 96 */
66function mapSpanToLocation(span: RustDiagnosticSpan): vscode.Location { 97function mapSpanToLocation(span: RustDiagnosticSpan): vscode.Location {
98 if (isFromMacro(span.file_name) && span.expansion) {
99 const macroLoc = mapMacroSpanToLocation(span.expansion);
100 if (macroLoc) {
101 return macroLoc;
102 }
103 }
104
67 const fileName = path.join(vscode.workspace.rootPath || '', span.file_name); 105 const fileName = path.join(vscode.workspace.rootPath || '', span.file_name);
68 const fileUri = vscode.Uri.file(fileName); 106 const fileUri = vscode.Uri.file(fileName);
69 107
70 const range = new vscode.Range( 108 const range = new vscode.Range(
71 new vscode.Position(span.line_start - 1, span.column_start - 1), 109 new vscode.Position(span.line_start - 1, span.column_start - 1),
72 new vscode.Position(span.line_end - 1, span.column_end - 1) 110 new vscode.Position(span.line_end - 1, span.column_end - 1),
73 ); 111 );
74 112
75 return new vscode.Location(fileUri, range); 113 return new vscode.Location(fileUri, range);
@@ -81,7 +119,7 @@ function mapSpanToLocation(span: RustDiagnosticSpan): vscode.Location {
81 * If the span is unlabelled this will return `undefined`. 119 * If the span is unlabelled this will return `undefined`.
82 */ 120 */
83function mapSecondarySpanToRelated( 121function mapSecondarySpanToRelated(
84 span: RustDiagnosticSpan 122 span: RustDiagnosticSpan,
85): vscode.DiagnosticRelatedInformation | undefined { 123): vscode.DiagnosticRelatedInformation | undefined {
86 if (!span.label) { 124 if (!span.label) {
87 // Nothing to label this with 125 // Nothing to label this with
@@ -107,7 +145,7 @@ function isUnusedOrUnnecessary(rd: RustDiagnostic): boolean {
107 'unused_attributes', 145 'unused_attributes',
108 'unused_imports', 146 'unused_imports',
109 'unused_macros', 147 'unused_macros',
110 'unused_variables' 148 'unused_variables',
111 ].includes(rd.code.code); 149 ].includes(rd.code.code);
112} 150}
113 151
@@ -157,13 +195,13 @@ function mapRustChildDiagnostic(rd: RustDiagnostic): MappedRustChildDiagnostic {
157 title, 195 title,
158 location, 196 location,
159 span.suggested_replacement, 197 span.suggested_replacement,
160 span.suggestion_applicability 198 span.suggestion_applicability,
161 ) 199 ),
162 }; 200 };
163 } else { 201 } else {
164 const related = new vscode.DiagnosticRelatedInformation( 202 const related = new vscode.DiagnosticRelatedInformation(
165 location, 203 location,
166 rd.message 204 rd.message,
167 ); 205 );
168 206
169 return { related }; 207 return { related };
@@ -183,7 +221,7 @@ function mapRustChildDiagnostic(rd: RustDiagnostic): MappedRustChildDiagnostic {
183 * If the diagnostic has no primary span this will return `undefined` 221 * If the diagnostic has no primary span this will return `undefined`
184 */ 222 */
185export function mapRustDiagnosticToVsCode( 223export function mapRustDiagnosticToVsCode(
186 rd: RustDiagnostic 224 rd: RustDiagnostic,
187): MappedRustDiagnostic | undefined { 225): MappedRustDiagnostic | undefined {
188 const primarySpan = rd.spans.find(s => s.is_primary); 226 const primarySpan = rd.spans.find(s => s.is_primary);
189 if (!primarySpan) { 227 if (!primarySpan) {
@@ -223,7 +261,7 @@ export function mapRustDiagnosticToVsCode(
223 const suggestedFixes = []; 261 const suggestedFixes = [];
224 for (const child of rd.children) { 262 for (const child of rd.children) {
225 const { related, suggestedFix, messageLine } = mapRustChildDiagnostic( 263 const { related, suggestedFix, messageLine } = mapRustChildDiagnostic(
226 child 264 child,
227 ); 265 );
228 266
229 if (related) { 267 if (related) {
@@ -256,6 +294,6 @@ export function mapRustDiagnosticToVsCode(
256 return { 294 return {
257 location, 295 location,
258 diagnostic: vd, 296 diagnostic: vd,
259 suggestedFixes 297 suggestedFixes,
260 }; 298 };
261} 299}
diff --git a/editors/code/src/utils/diagnostics/vscode.ts b/editors/code/src/utils/diagnostics/vscode.ts
index d8b85b720..f4a5450e2 100644
--- a/editors/code/src/utils/diagnostics/vscode.ts
+++ b/editors/code/src/utils/diagnostics/vscode.ts
@@ -3,7 +3,7 @@ import * as vscode from 'vscode';
3/** Compares two `vscode.Diagnostic`s for equality */ 3/** Compares two `vscode.Diagnostic`s for equality */
4export function areDiagnosticsEqual( 4export function areDiagnosticsEqual(
5 left: vscode.Diagnostic, 5 left: vscode.Diagnostic,
6 right: vscode.Diagnostic 6 right: vscode.Diagnostic,
7): boolean { 7): boolean {
8 return ( 8 return (
9 left.source === right.source && 9 left.source === right.source &&
diff --git a/editors/code/src/utils/processes.ts b/editors/code/src/utils/processes.ts
index da8be9eb1..a1d6b7eaf 100644
--- a/editors/code/src/utils/processes.ts
+++ b/editors/code/src/utils/processes.ts
@@ -22,7 +22,7 @@ export function terminate(process: ChildProcess, cwd?: string): boolean {
22 // Ignore stderr since this is otherwise piped to parent.stderr 22 // Ignore stderr since this is otherwise piped to parent.stderr
23 // which might be already closed. 23 // which might be already closed.
24 const options: any = { 24 const options: any = {
25 stdio: ['pipe', 'pipe', 'ignore'] 25 stdio: ['pipe', 'pipe', 'ignore'],
26 }; 26 };
27 if (cwd) { 27 if (cwd) {
28 options.cwd = cwd; 28 options.cwd = cwd;
@@ -30,7 +30,7 @@ export function terminate(process: ChildProcess, cwd?: string): boolean {
30 cp.execFileSync( 30 cp.execFileSync(
31 'taskkill', 31 'taskkill',
32 ['/T', '/F', '/PID', process.pid.toString()], 32 ['/T', '/F', '/PID', process.pid.toString()],
33 options 33 options,
34 ); 34 );
35 return true; 35 return true;
36 } catch (err) { 36 } catch (err) {