about summary refs log tree commit diff
path: root/editors/code/src
diff options
context:
space:
mode:
authorSeivan Heidari <seivan.heidari@icloud.com>2019-12-23 15:35:31 +0100
committerSeivan Heidari <seivan.heidari@icloud.com>2019-12-23 15:35:31 +0100
commitb21d9337d9200e2cfdc90b386591c72c302dc03e (patch)
treef81f5c08f821115cee26fa4d3ceaae88c7807fd5 /editors/code/src
parent18a0937585b836ec5ed054b9ae48e0156ab6d9ef (diff)
parentce07a2daa9e53aa86a769f8641b14c2878444fbc (diff)
downloadrust-b21d9337d9200e2cfdc90b386591c72c302dc03e.tar.gz
rust-b21d9337d9200e2cfdc90b386591c72c302dc03e.zip
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 63f82c92d88..2777ced2479 100644
--- a/editors/code/src/commands/analyzer_status.ts
+++ b/editors/code/src/commands/analyzer_status.ts
@@ -9,7 +9,7 @@ export class TextDocumentContentProvider
     public syntaxTree: string = 'Not available';
 
     public provideTextDocumentContent(
-        uri: vscode.Uri
+        _uri: vscode.Uri,
     ): vscode.ProviderResult<string> {
         const editor = vscode.window.activeTextEditor;
         if (editor == null) {
@@ -17,7 +17,7 @@ export class TextDocumentContentProvider
         }
         return Server.client.sendRequest<string>(
             'rust-analyzer/analyzerStatus',
-            null
+            null,
         );
     }
 
@@ -35,8 +35,8 @@ export function makeCommand(context: vscode.ExtensionContext) {
     context.subscriptions.push(
         vscode.workspace.registerTextDocumentContentProvider(
             'rust-analyzer-status',
-            textDocumentContentProvider
-        )
+            textDocumentContentProvider,
+        ),
     );
 
     context.subscriptions.push({
@@ -44,21 +44,21 @@ export function makeCommand(context: vscode.ExtensionContext) {
             if (poller != null) {
                 clearInterval(poller);
             }
-        }
+        },
     });
 
     return async function handle() {
         if (poller == null) {
             poller = setInterval(
                 () => textDocumentContentProvider.eventEmitter.fire(statusUri),
-                1000
+                1000,
             );
         }
         const document = await vscode.workspace.openTextDocument(statusUri);
         return vscode.window.showTextDocument(
             document,
             vscode.ViewColumn.Two,
-            true
+            true,
         );
     };
 }
diff --git a/editors/code/src/commands/apply_source_change.ts b/editors/code/src/commands/apply_source_change.ts
index dcd074b8bc8..8167398b1ce 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 {
 
 export async function handle(change: SourceChange) {
     const wsEdit = Server.client.protocol2CodeConverter.asWorkspaceEdit(
-        change.workspaceEdit
+        change.workspaceEdit,
     );
     let created;
     let moved;
@@ -33,10 +33,10 @@ export async function handle(change: SourceChange) {
         await vscode.window.showTextDocument(doc);
     } else if (toReveal) {
         const uri = Server.client.protocol2CodeConverter.asUri(
-            toReveal.textDocument.uri
+            toReveal.textDocument.uri,
         );
         const position = Server.client.protocol2CodeConverter.asPosition(
-            toReveal.position
+            toReveal.position,
         );
         const editor = vscode.window.activeTextEditor;
         if (!editor || editor.document.uri.toString() !== uri.toString()) {
@@ -48,7 +48,7 @@ export async function handle(change: SourceChange) {
         editor.selection = new vscode.Selection(position, position);
         editor.revealRange(
             new vscode.Range(position, position),
-            vscode.TextEditorRevealType.Default
+            vscode.TextEditorRevealType.Default,
         );
     }
 }
diff --git a/editors/code/src/commands/cargo_watch.ts b/editors/code/src/commands/cargo_watch.ts
index 59d4ba97a23..ac62bdd48d2 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';
 
 import {
     mapRustDiagnosticToVsCode,
-    RustDiagnostic
+    RustDiagnostic,
 } from '../utils/diagnostics/rust';
 import SuggestedFixCollection from '../utils/diagnostics/SuggestedFixCollection';
 import { areDiagnosticsEqual } from '../utils/diagnostics/vscode';
 
 export async function registerCargoWatchProvider(
-    subscriptions: vscode.Disposable[]
+    subscriptions: vscode.Disposable[],
 ): Promise<CargoWatchProvider | undefined> {
     let cargoExists = false;
 
@@ -30,7 +30,7 @@ export async function registerCargoWatchProvider(
 
     if (!cargoExists) {
         vscode.window.showErrorMessage(
-            `Couldn\'t find \'Cargo.toml\' at ${cargoTomlPath}`
+            `Couldn\'t find \'Cargo.toml\' at ${cargoTomlPath}`,
         );
         return;
     }
@@ -52,13 +52,13 @@ export class CargoWatchProvider implements vscode.Disposable {
 
     constructor() {
         this.diagnosticCollection = vscode.languages.createDiagnosticCollection(
-            'rustc'
+            'rustc',
         );
         this.statusDisplay = new StatusDisplay(
-            Server.config.cargoWatchOptions.command
+            Server.config.cargoWatchOptions.command,
         );
         this.outputChannel = vscode.window.createOutputChannel(
-            'Cargo Watch Trace'
+            'Cargo Watch Trace',
         );
 
         // Track `rustc`'s suggested fixes so we can convert them to code actions
@@ -68,22 +68,24 @@ export class CargoWatchProvider implements vscode.Disposable {
             this.suggestedFixCollection,
             {
                 providedCodeActionKinds:
-                    SuggestedFixCollection.PROVIDED_CODE_ACTION_KINDS
-            }
+                    SuggestedFixCollection.PROVIDED_CODE_ACTION_KINDS,
+            },
         );
     }
 
     public start() {
         if (this.cargoProcess) {
             vscode.window.showInformationMessage(
-                'Cargo Watch is already running'
+                'Cargo Watch is already running',
             );
             return;
         }
 
         let args =
-            Server.config.cargoWatchOptions.command +
-            ' --all-targets --message-format json';
+            Server.config.cargoWatchOptions.command + ' --message-format json';
+        if (Server.config.cargoWatchOptions.allTargets) {
+            args += ' --all-targets';
+        }
         if (Server.config.cargoWatchOptions.command.length > 0) {
             // Excape the double quote string:
             args += ' ' + Server.config.cargoWatchOptions.arguments;
@@ -95,7 +97,7 @@ export class CargoWatchProvider implements vscode.Disposable {
 
         const ignoreFlags = Server.config.cargoWatchOptions.ignore.reduce(
             (flags, pattern) => [...flags, '--ignore', pattern],
-            [] as string[]
+            [] as string[],
         );
 
         // Start the cargo watch with json message
@@ -105,12 +107,17 @@ export class CargoWatchProvider implements vscode.Disposable {
             {
                 stdio: ['ignore', 'pipe', 'pipe'],
                 cwd: vscode.workspace.rootPath,
-                windowsVerbatimArguments: true
-            }
+                windowsVerbatimArguments: true,
+            },
         );
 
+        if (!this.cargoProcess) {
+            vscode.window.showErrorMessage('Cargo Watch failed to start');
+            return;
+        }
+
         const stdoutData = new LineBuffer();
-        this.cargoProcess.stdout.on('data', (s: string) => {
+        this.cargoProcess.stdout?.on('data', (s: string) => {
             stdoutData.processOutput(s, line => {
                 this.logInfo(line);
                 try {
@@ -122,7 +129,7 @@ export class CargoWatchProvider implements vscode.Disposable {
         });
 
         const stderrData = new LineBuffer();
-        this.cargoProcess.stderr.on('data', (s: string) => {
+        this.cargoProcess.stderr?.on('data', (s: string) => {
             stderrData.processOutput(s, line => {
                 this.logError('Error on cargo-watch : {\n' + line + '}\n');
             });
@@ -130,7 +137,7 @@ export class CargoWatchProvider implements vscode.Disposable {
 
         this.cargoProcess.on('error', (err: Error) => {
             this.logError(
-                'Error on cargo-watch process : {\n' + err.message + '}\n'
+                'Error on cargo-watch process : {\n' + err.message + '}\n',
             );
         });
 
@@ -223,12 +230,12 @@ export class CargoWatchProvider implements vscode.Disposable {
             const fileUri = location.uri;
 
             const diagnostics: vscode.Diagnostic[] = [
-                ...(this.diagnosticCollection!.get(fileUri) || [])
+                ...(this.diagnosticCollection!.get(fileUri) || []),
             ];
 
             // If we're building multiple targets it's possible we've already seen this diagnostic
             const isDuplicate = diagnostics.some(d =>
-                areDiagnosticsEqual(d, diagnostic)
+                areDiagnosticsEqual(d, diagnostic),
             );
             if (isDuplicate) {
                 return;
@@ -241,7 +248,7 @@ export class CargoWatchProvider implements vscode.Disposable {
                 for (const suggestedFix of suggestedFixes) {
                     this.suggestedFixCollection.addSuggestedFixForDiagnostic(
                         suggestedFix,
-                        diagnostic
+                        diagnostic,
                     );
                 }
 
@@ -249,7 +256,7 @@ export class CargoWatchProvider implements vscode.Disposable {
                 vscode.commands.executeCommand(
                     'vscode.executeCodeActionProvider',
                     fileUri,
-                    diagnostic.range
+                    diagnostic.range,
                 );
             }
         }
diff --git a/editors/code/src/commands/expand_macro.ts b/editors/code/src/commands/expand_macro.ts
index 34e0c8fb337..17c78280a89 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';
 import { Server } from '../server';
 
 export const expandMacroUri = vscode.Uri.parse(
-    'rust-analyzer://expandMacro/[EXPANSION].rs'
+    'rust-analyzer://expandMacro/[EXPANSION].rs',
 );
 
 export class ExpandMacroContentProvider
@@ -11,7 +11,7 @@ export class ExpandMacroContentProvider
     public eventEmitter = new vscode.EventEmitter<vscode.Uri>();
 
     public provideTextDocumentContent(
-        uri: vscode.Uri
+        _uri: vscode.Uri,
     ): vscode.ProviderResult<string> {
         async function handle() {
             const editor = vscode.window.activeTextEditor;
@@ -22,11 +22,11 @@ export class ExpandMacroContentProvider
             const position = editor.selection.active;
             const request: MacroExpandParams = {
                 textDocument: { uri: editor.document.uri.toString() },
-                position
+                position,
             };
             const expanded = await Server.client.sendRequest<ExpandedMacro>(
                 'rust-analyzer/expandMacro',
-                request
+                request,
             );
 
             if (expanded == null) {
@@ -58,7 +58,7 @@ export function createHandle(provider: ExpandMacroContentProvider) {
         return vscode.window.showTextDocument(
             document,
             vscode.ViewColumn.Two,
-            true
+            true,
         );
     };
 }
diff --git a/editors/code/src/commands/index.ts b/editors/code/src/commands/index.ts
index 2ade6d331a7..13a696758b4 100644
--- a/editors/code/src/commands/index.ts
+++ b/editors/code/src/commands/index.ts
@@ -19,5 +19,5 @@ export {
     runnables,
     syntaxTree,
     onEnter,
-    inlayHints
+    inlayHints,
 };
diff --git a/editors/code/src/commands/inlay_hints.ts b/editors/code/src/commands/inlay_hints.ts
index 0dbdd94fbac..ac7dcce604b 100644
--- a/editors/code/src/commands/inlay_hints.ts
+++ b/editors/code/src/commands/inlay_hints.ts
@@ -15,8 +15,8 @@ interface InlayHint {
 
 const typeHintDecorationType = vscode.window.createTextEditorDecorationType({
     after: {
-        color: new vscode.ThemeColor('ralsp.inlayHint')
-    }
+        color: new vscode.ThemeColor('ralsp.inlayHint'),
+    },
 });
 
 export class HintsUpdater {
@@ -26,13 +26,13 @@ export class HintsUpdater {
         if (this.displayHints !== displayHints) {
             this.displayHints = displayHints;
             return this.refreshVisibleEditorsHints(
-                displayHints ? undefined : []
+                displayHints ? undefined : [],
             );
         }
     }
 
     public async refreshHintsForVisibleEditors(
-        cause?: TextDocumentChangeEvent
+        cause?: TextDocumentChangeEvent,
     ): Promise<void> {
         if (!this.displayHints) {
             return;
@@ -48,21 +48,21 @@ export class HintsUpdater {
     }
 
     private async refreshVisibleEditorsHints(
-        newDecorations?: vscode.DecorationOptions[]
+        newDecorations?: vscode.DecorationOptions[],
     ) {
         const promises: Array<Promise<void>> = [];
 
         for (const rustEditor of vscode.window.visibleTextEditors.filter(
-            editor => this.isRustDocument(editor.document)
+            editor => this.isRustDocument(editor.document),
         )) {
             if (newDecorations !== undefined) {
                 promises.push(
                     Promise.resolve(
                         rustEditor.setDecorations(
                             typeHintDecorationType,
-                            newDecorations
-                        )
-                    )
+                            newDecorations,
+                        ),
+                    ),
                 );
             } else {
                 promises.push(this.updateDecorationsFromServer(rustEditor));
@@ -79,7 +79,7 @@ export class HintsUpdater {
     }
 
     private async updateDecorationsFromServer(
-        editor: TextEditor
+        editor: TextEditor,
     ): Promise<void> {
         const newHints = await this.queryHints(editor.document.uri.toString());
         if (newHints !== null) {
@@ -87,20 +87,20 @@ export class HintsUpdater {
                 range: hint.range,
                 renderOptions: {
                     after: {
-                        contentText: `: ${hint.label}`
-                    }
-                }
+                        contentText: `: ${hint.label}`,
+                    },
+                },
             }));
             return editor.setDecorations(
                 typeHintDecorationType,
-                newDecorations
+                newDecorations,
             );
         }
     }
 
     private async queryHints(documentUri: string): Promise<InlayHint[] | null> {
         const request: InlayHintsParams = {
-            textDocument: { uri: documentUri }
+            textDocument: { uri: documentUri },
         };
         const client = Server.client;
         return client
@@ -108,8 +108,8 @@ export class HintsUpdater {
             .then(() =>
                 client.sendRequest<InlayHint[] | null>(
                     'rust-analyzer/inlayHints',
-                    request
-                )
+                    request,
+                ),
             );
     }
 }
diff --git a/editors/code/src/commands/join_lines.ts b/editors/code/src/commands/join_lines.ts
index 0d4b12f4d85..134ddc80164 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';
 import { Server } from '../server';
 import {
     handle as applySourceChange,
-    SourceChange
+    SourceChange,
 } from './apply_source_change';
 
 interface JoinLinesParams {
@@ -19,11 +19,11 @@ export async function handle() {
     }
     const request: JoinLinesParams = {
         range: Server.client.code2ProtocolConverter.asRange(editor.selection),
-        textDocument: { uri: editor.document.uri.toString() }
+        textDocument: { uri: editor.document.uri.toString() },
     };
     const change = await Server.client.sendRequest<SourceChange>(
         'rust-analyzer/joinLines',
-        request
+        request,
     );
     await applySourceChange(change);
 }
diff --git a/editors/code/src/commands/matching_brace.ts b/editors/code/src/commands/matching_brace.ts
index d86faf40518..364208cc758 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() {
         textDocument: { uri: editor.document.uri.toString() },
         offsets: editor.selections.map(s => {
             return Server.client.code2ProtocolConverter.asPosition(s.active);
-        })
+        }),
     };
     const response = await Server.client.sendRequest<Position[]>(
         'rust-analyzer/findMatchingBrace',
-        request
+        request,
     );
     editor.selections = editor.selections.map((sel, idx) => {
         const active = Server.client.protocol2CodeConverter.asPosition(
-            response[idx]
+            response[idx],
         );
         const anchor = sel.isEmpty ? active : sel.anchor;
         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 16dcb70c813..772c64b3c78 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';
 import { Server } from '../server';
 import {
     handle as applySourceChange,
-    SourceChange
+    SourceChange,
 } from './apply_source_change';
 
 export async function handle(event: { text: string }): Promise<boolean> {
@@ -18,12 +18,12 @@ export async function handle(event: { text: string }): Promise<boolean> {
     const request: lc.TextDocumentPositionParams = {
         textDocument: { uri: editor.document.uri.toString() },
         position: Server.client.code2ProtocolConverter.asPosition(
-            editor.selection.active
-        )
+            editor.selection.active,
+        ),
     };
     const change = await Server.client.sendRequest<undefined | SourceChange>(
         'rust-analyzer/onEnter',
-        request
+        request,
     );
     if (!change) {
         return false;
diff --git a/editors/code/src/commands/parent_module.ts b/editors/code/src/commands/parent_module.ts
index 9d30b7b59ac..ad49e1bdbbf 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() {
     const request: lc.TextDocumentPositionParams = {
         textDocument: { uri: editor.document.uri.toString() },
         position: Server.client.code2ProtocolConverter.asPosition(
-            editor.selection.active
-        )
+            editor.selection.active,
+        ),
     };
     const response = await Server.client.sendRequest<lc.Location[]>(
         'rust-analyzer/parentModule',
-        request
+        request,
     );
     const loc = response[0];
     if (loc == null) {
diff --git a/editors/code/src/commands/runnables.ts b/editors/code/src/commands/runnables.ts
index ac59bf60db6..cf980e25785 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 {
         label: spec.label,
         command: spec.bin,
         args: spec.args,
-        env: spec.env
+        env: spec.env,
     };
 
     const execOption: vscode.ShellExecutionOptions = {
         cwd: spec.cwd || '.',
-        env: definition.env
+        env: definition.env,
     };
     const exec = new vscode.ShellExecution(
         definition.command,
         definition.args,
-        execOption
+        execOption,
     );
 
     const f = vscode.workspace.workspaceFolders![0];
@@ -66,30 +66,30 @@ function createTask(spec: Runnable): vscode.Task {
         definition.label,
         TASK_SOURCE,
         exec,
-        ['$rustc']
+        ['$rustc'],
     );
     t.presentationOptions.clear = true;
     return t;
 }
 
 let prevRunnable: RunnableQuickPick | undefined;
-export async function handle() {
+export async function handle(): Promise<vscode.TaskExecution | undefined> {
     const editor = vscode.window.activeTextEditor;
     if (editor == null || editor.document.languageId !== 'rust') {
         return;
     }
     const textDocument: lc.TextDocumentIdentifier = {
-        uri: editor.document.uri.toString()
+        uri: editor.document.uri.toString(),
     };
     const params: RunnablesParams = {
         textDocument,
         position: Server.client.code2ProtocolConverter.asPosition(
-            editor.selection.active
-        )
+            editor.selection.active,
+        ),
     };
     const runnables = await Server.client.sendRequest<Runnable[]>(
         'rust-analyzer/runnables',
-        params
+        params,
     );
     const items: RunnableQuickPick[] = [];
     if (prevRunnable) {
@@ -105,12 +105,14 @@ export async function handle() {
         items.push(new RunnableQuickPick(r));
     }
     const item = await vscode.window.showQuickPick(items);
-    if (item) {
-        item.detail = 'rerun';
-        prevRunnable = item;
-        const task = createTask(item.runnable);
-        return await vscode.tasks.executeTask(task);
+    if (!item) {
+        return;
     }
+
+    item.detail = 'rerun';
+    prevRunnable = item;
+    const task = createTask(item.runnable);
+    return await vscode.tasks.executeTask(task);
 }
 
 export async function handleSingle(runnable: Runnable) {
@@ -124,7 +126,7 @@ export async function handleSingle(runnable: Runnable) {
     task.presentationOptions = {
         reveal: vscode.TaskRevealKind.Always,
         panel: vscode.TaskPanelKind.Dedicated,
-        clear: true
+        clear: true,
     };
 
     return vscode.tasks.executeTask(task);
@@ -136,7 +138,7 @@ export async function handleSingle(runnable: Runnable) {
  * that, when accepted, allow us to `cargo install cargo-watch` and then run it.
  */
 export async function interactivelyStartCargoWatch(
-    context: vscode.ExtensionContext
+    context: vscode.ExtensionContext,
 ): Promise<CargoWatchProvider | undefined> {
     if (Server.config.cargoWatchOptions.enableOnStartup === 'disabled') {
         return;
@@ -146,7 +148,7 @@ export async function interactivelyStartCargoWatch(
         const watch = await vscode.window.showInformationMessage(
             'Start watching changes with cargo? (Executes `cargo watch`, provides inline diagnostics)',
             'yes',
-            'no'
+            'no',
         );
         if (watch !== 'yes') {
             return;
@@ -157,12 +159,12 @@ export async function interactivelyStartCargoWatch(
 }
 
 export async function startCargoWatch(
-    context: vscode.ExtensionContext
+    context: vscode.ExtensionContext,
 ): Promise<CargoWatchProvider | undefined> {
     const execPromise = util.promisify(child_process.exec);
 
     const { stderr, code = 0 } = await execPromise(
-        'cargo watch --version'
+        'cargo watch --version',
     ).catch(e => e);
 
     if (stderr.includes('no such subcommand: `watch`')) {
@@ -171,14 +173,14 @@ export async function startCargoWatch(
         const install = await vscode.window.showInformationMessage(
             msg,
             'yes',
-            'no'
+            'no',
         );
         if (install !== 'yes') {
             return;
         }
 
         const label = 'install-cargo-watch';
-        const taskFinished = new Promise((resolve, reject) => {
+        const taskFinished = new Promise((resolve, _reject) => {
             const disposable = vscode.tasks.onDidEndTask(({ execution }) => {
                 if (execution.task.name === label) {
                     disposable.dispose();
@@ -192,20 +194,20 @@ export async function startCargoWatch(
                 label,
                 bin: 'cargo',
                 args: ['install', 'cargo-watch'],
-                env: {}
-            })
+                env: {},
+            }),
         );
         await taskFinished;
         const output = await execPromise('cargo watch --version').catch(e => e);
         if (output.stderr !== '') {
             vscode.window.showErrorMessage(
-                `Couldn't install \`cargo-\`watch: ${output.stderr}`
+                `Couldn't install \`cargo-\`watch: ${output.stderr}`,
             );
             return;
         }
     } else if (code !== 0) {
         vscode.window.showErrorMessage(
-            `\`cargo watch\` failed with ${code}: ${stderr}`
+            `\`cargo watch\` failed with ${code}: ${stderr}`,
         );
         return;
     }
diff --git a/editors/code/src/commands/syntaxTree.ts b/editors/code/src/commands/syntaxTree.ts
index 2f50fe14b3b..89a80550cee 100644
--- a/editors/code/src/commands/syntaxTree.ts
+++ b/editors/code/src/commands/syntaxTree.ts
@@ -11,7 +11,7 @@ export class SyntaxTreeContentProvider
     public syntaxTree: string = 'Not available';
 
     public provideTextDocumentContent(
-        uri: vscode.Uri
+        uri: vscode.Uri,
     ): vscode.ProviderResult<string> {
         const editor = vscode.window.activeTextEditor;
         if (editor == null) {
@@ -25,17 +25,17 @@ export class SyntaxTreeContentProvider
             range = editor.selection.isEmpty
                 ? undefined
                 : Server.client.code2ProtocolConverter.asRange(
-                      editor.selection
+                      editor.selection,
                   );
         }
 
         const request: SyntaxTreeParams = {
             textDocument: { uri: editor.document.uri.toString() },
-            range
+            range,
         };
         return Server.client.sendRequest<SyntaxTreeResult>(
             'rust-analyzer/syntaxTree',
-            request
+            request,
         );
     }
 
@@ -70,7 +70,7 @@ export function createHandle(provider: SyntaxTreeContentProvider) {
         return vscode.window.showTextDocument(
             document,
             vscode.ViewColumn.Two,
-            true
+            true,
         );
     };
 }
diff --git a/editors/code/src/commands/watch_status.ts b/editors/code/src/commands/watch_status.ts
index 6c1f9041bad..8d64394c7b6 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 {
     constructor(command: string) {
         this.statusBarItem = vscode.window.createStatusBarItem(
             vscode.StatusBarAlignment.Left,
-            10
+            10,
         );
         this.command = command;
         this.statusBarItem.hide();
diff --git a/editors/code/src/config.ts b/editors/code/src/config.ts
index 4cedbea4661..c06dddb1c63 100644
--- a/editors/code/src/config.ts
+++ b/editors/code/src/config.ts
@@ -14,6 +14,13 @@ export interface CargoWatchOptions {
     command: string;
     trace: CargoWatchTraceOptions;
     ignore: string[];
+    allTargets: boolean;
+}
+
+export interface CargoFeatures {
+    noDefaultFeatures: boolean;
+    allFeatures: boolean;
+    features: string[];
 }
 
 export class Config {
@@ -25,21 +32,30 @@ export class Config {
     public displayInlayHints = true;
     public maxInlayHintLength: null | number = null;
     public excludeGlobs = [];
-    public useClientWatching = false;
+    public useClientWatching = true;
     public featureFlags = {};
+    // for internal use
+    public withSysroot: null | boolean = null;
     public cargoWatchOptions: CargoWatchOptions = {
         enableOnStartup: 'ask',
         trace: 'off',
         arguments: '',
         command: '',
-        ignore: []
+        ignore: [],
+        allTargets: true,
+    };
+    public cargoFeatures: CargoFeatures = {
+        noDefaultFeatures: false,
+        allFeatures: true,
+        features: [],
     };
 
     private prevEnhancedTyping: null | boolean = null;
+    private prevCargoFeatures: null | CargoFeatures = null;
 
     constructor() {
         vscode.workspace.onDidChangeConfiguration(_ =>
-            this.userConfigChanged()
+            this.userConfigChanged(),
         );
         this.userConfigChanged();
     }
@@ -49,6 +65,8 @@ export class Config {
 
         Server.highlighter.removeHighlights();
 
+        let requireReloadMessage = null;
+
         if (config.has('highlightingOn')) {
             this.highlightingOn = config.get('highlightingOn') as boolean;
             if (this.highlightingOn) {
@@ -59,13 +77,13 @@ export class Config {
 
         if (config.has('rainbowHighlightingOn')) {
             this.rainbowHighlightingOn = config.get(
-                'rainbowHighlightingOn'
+                'rainbowHighlightingOn',
             ) as boolean;
         }
 
         if (config.has('enableEnhancedTyping')) {
             this.enableEnhancedTyping = config.get(
-                'enableEnhancedTyping'
+                'enableEnhancedTyping',
             ) as boolean;
 
             if (this.prevEnhancedTyping === null) {
@@ -76,19 +94,8 @@ export class Config {
         }
 
         if (this.prevEnhancedTyping !== this.enableEnhancedTyping) {
-            const reloadAction = 'Reload now';
-            vscode.window
-                .showInformationMessage(
-                    'Changing enhanced typing setting requires a reload',
-                    reloadAction
-                )
-                .then(selectedAction => {
-                    if (selectedAction === reloadAction) {
-                        vscode.commands.executeCommand(
-                            'workbench.action.reloadWindow'
-                        );
-                    }
-                });
+            requireReloadMessage =
+                'Changing enhanced typing setting requires a reload';
             this.prevEnhancedTyping = this.enableEnhancedTyping;
         }
 
@@ -106,28 +113,35 @@ export class Config {
         if (config.has('trace.cargo-watch')) {
             this.cargoWatchOptions.trace = config.get<CargoWatchTraceOptions>(
                 'trace.cargo-watch',
-                'off'
+                'off',
             );
         }
 
         if (config.has('cargo-watch.arguments')) {
             this.cargoWatchOptions.arguments = config.get<string>(
                 'cargo-watch.arguments',
-                ''
+                '',
             );
         }
 
         if (config.has('cargo-watch.command')) {
             this.cargoWatchOptions.command = config.get<string>(
                 'cargo-watch.command',
-                ''
+                '',
             );
         }
 
         if (config.has('cargo-watch.ignore')) {
             this.cargoWatchOptions.ignore = config.get<string[]>(
                 'cargo-watch.ignore',
-                []
+                [],
+            );
+        }
+
+        if (config.has('cargo-watch.allTargets')) {
+            this.cargoWatchOptions.allTargets = config.get<boolean>(
+                'cargo-watch.allTargets',
+                true,
             );
         }
 
@@ -140,17 +154,68 @@ export class Config {
         }
         if (config.has('maxInlayHintLength')) {
             this.maxInlayHintLength = config.get(
-                'maxInlayHintLength'
+                'maxInlayHintLength',
             ) as number;
         }
         if (config.has('excludeGlobs')) {
             this.excludeGlobs = config.get('excludeGlobs') || [];
         }
         if (config.has('useClientWatching')) {
-            this.useClientWatching = config.get('useClientWatching') || false;
+            this.useClientWatching = config.get('useClientWatching') || true;
         }
         if (config.has('featureFlags')) {
             this.featureFlags = config.get('featureFlags') || {};
         }
+        if (config.has('withSysroot')) {
+            this.withSysroot = config.get('withSysroot') || false;
+        }
+
+        if (config.has('cargoFeatures.noDefaultFeatures')) {
+            this.cargoFeatures.noDefaultFeatures = config.get(
+                'cargoFeatures.noDefaultFeatures',
+                false,
+            );
+        }
+        if (config.has('cargoFeatures.allFeatures')) {
+            this.cargoFeatures.allFeatures = config.get(
+                'cargoFeatures.allFeatures',
+                true,
+            );
+        }
+        if (config.has('cargoFeatures.features')) {
+            this.cargoFeatures.features = config.get(
+                'cargoFeatures.features',
+                [],
+            );
+        }
+
+        if (
+            this.prevCargoFeatures !== null &&
+            (this.cargoFeatures.allFeatures !==
+                this.prevCargoFeatures.allFeatures ||
+                this.cargoFeatures.noDefaultFeatures !==
+                    this.prevCargoFeatures.noDefaultFeatures ||
+                this.cargoFeatures.features.length !==
+                    this.prevCargoFeatures.features.length ||
+                this.cargoFeatures.features.some(
+                    (v, i) => v !== this.prevCargoFeatures!.features[i],
+                ))
+        ) {
+            requireReloadMessage = 'Changing cargo features requires a reload';
+        }
+        this.prevCargoFeatures = { ...this.cargoFeatures };
+
+        if (requireReloadMessage !== null) {
+            const reloadAction = 'Reload now';
+            vscode.window
+                .showInformationMessage(requireReloadMessage, reloadAction)
+                .then(selectedAction => {
+                    if (selectedAction === reloadAction) {
+                        vscode.commands.executeCommand(
+                            'workbench.action.reloadWindow',
+                        );
+                    }
+                });
+        }
     }
 }
diff --git a/editors/code/src/events/change_active_text_editor.ts b/editors/code/src/events/change_active_text_editor.ts
index 64be562250e..74b91bd4871 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';
 
 import {
     SyntaxTreeContentProvider,
-    syntaxTreeUri
+    syntaxTreeUri,
 } from '../commands/syntaxTree';
 import { Decoration } from '../highlighting';
 import { Server } from '../server';
@@ -21,11 +21,11 @@ export function makeHandler(syntaxTreeProvider: SyntaxTreeContentProvider) {
         }
 
         const params: TextDocumentIdentifier = {
-            uri: editor.document.uri.toString()
+            uri: editor.document.uri.toString(),
         };
         const decorations = await Server.client.sendRequest<Decoration[]>(
             'rust-analyzer/decorationsRequest',
-            params
+            params,
         );
         Server.highlighter.setHighlights(editor, decorations);
     };
diff --git a/editors/code/src/events/change_text_document.ts b/editors/code/src/events/change_text_document.ts
index 89488bc61ef..2e998e889ba 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';
 
 import {
     SyntaxTreeContentProvider,
-    syntaxTreeUri
+    syntaxTreeUri,
 } from '../commands/syntaxTree';
 
 export function createHandler(syntaxTreeProvider: SyntaxTreeContentProvider) {
diff --git a/editors/code/src/extension.ts b/editors/code/src/extension.ts
index 683497dfd4d..815f3692c02 100644
--- a/editors/code/src/extension.ts
+++ b/editors/code/src/extension.ts
@@ -7,14 +7,14 @@ import { ExpandMacroContentProvider } from './commands/expand_macro';
 import { HintsUpdater } from './commands/inlay_hints';
 import {
     interactivelyStartCargoWatch,
-    startCargoWatch
+    startCargoWatch,
 } from './commands/runnables';
 import { SyntaxTreeContentProvider } from './commands/syntaxTree';
 import * as events from './events';
 import * as notifications from './notifications';
 import { Server } from './server';
 
-export function activate(context: vscode.ExtensionContext) {
+export async function activate(context: vscode.ExtensionContext) {
     function disposeOnDeactivation(disposable: vscode.Disposable) {
         context.subscriptions.push(disposable);
     }
@@ -24,7 +24,7 @@ export function activate(context: vscode.ExtensionContext) {
     }
     function overrideCommand(
         name: string,
-        f: (...args: any[]) => Promise<boolean>
+        f: (...args: any[]) => Promise<boolean>,
     ) {
         const defaultCmd = `default:${name}`;
         const original = (...args: any[]) =>
@@ -46,7 +46,7 @@ export function activate(context: vscode.ExtensionContext) {
             });
         } catch (_) {
             vscode.window.showWarningMessage(
-                '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'
+                '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',
             );
         }
     }
@@ -54,14 +54,14 @@ export function activate(context: vscode.ExtensionContext) {
     // Commands are requests from vscode to the language server
     registerCommand(
         'rust-analyzer.analyzerStatus',
-        commands.analyzerStatus.makeCommand(context)
+        commands.analyzerStatus.makeCommand(context),
     );
     registerCommand('rust-analyzer.collectGarbage', () =>
-        Server.client.sendRequest<null>('rust-analyzer/collectGarbage', null)
+        Server.client.sendRequest<null>('rust-analyzer/collectGarbage', null),
     );
     registerCommand(
         'rust-analyzer.matchingBrace',
-        commands.matchingBrace.handle
+        commands.matchingBrace.handle,
     );
     registerCommand('rust-analyzer.joinLines', commands.joinLines.handle);
     registerCommand('rust-analyzer.parentModule', commands.parentModule.handle);
@@ -70,7 +70,7 @@ export function activate(context: vscode.ExtensionContext) {
     registerCommand('rust-analyzer.runSingle', commands.runnables.handleSingle);
     registerCommand(
         'rust-analyzer.applySourceChange',
-        commands.applySourceChange.handle
+        commands.applySourceChange.handle,
     );
     registerCommand(
         'rust-analyzer.showReferences',
@@ -79,9 +79,9 @@ export function activate(context: vscode.ExtensionContext) {
                 'editor.action.showReferences',
                 vscode.Uri.parse(uri),
                 Server.client.protocol2CodeConverter.asPosition(position),
-                locations.map(Server.client.protocol2CodeConverter.asLocation)
+                locations.map(Server.client.protocol2CodeConverter.asLocation),
             );
-        }
+        },
     );
 
     if (Server.config.enableEnhancedTyping) {
@@ -89,48 +89,49 @@ export function activate(context: vscode.ExtensionContext) {
     }
 
     // Notifications are events triggered by the language server
-    const allNotifications: Iterable<
-        [string, lc.GenericNotificationHandler]
-    > = [
+    const allNotifications: Iterable<[
+        string,
+        lc.GenericNotificationHandler,
+    ]> = [
         [
             'rust-analyzer/publishDecorations',
-            notifications.publishDecorations.handle
-        ]
+            notifications.publishDecorations.handle,
+        ],
     ];
     const syntaxTreeContentProvider = new SyntaxTreeContentProvider();
     const expandMacroContentProvider = new ExpandMacroContentProvider();
 
     // The events below are plain old javascript events, triggered and handled by vscode
     vscode.window.onDidChangeActiveTextEditor(
-        events.changeActiveTextEditor.makeHandler(syntaxTreeContentProvider)
+        events.changeActiveTextEditor.makeHandler(syntaxTreeContentProvider),
     );
 
     disposeOnDeactivation(
         vscode.workspace.registerTextDocumentContentProvider(
             'rust-analyzer',
-            syntaxTreeContentProvider
-        )
+            syntaxTreeContentProvider,
+        ),
     );
     disposeOnDeactivation(
         vscode.workspace.registerTextDocumentContentProvider(
             'rust-analyzer',
-            expandMacroContentProvider
-        )
+            expandMacroContentProvider,
+        ),
     );
 
     registerCommand(
         'rust-analyzer.syntaxTree',
-        commands.syntaxTree.createHandle(syntaxTreeContentProvider)
+        commands.syntaxTree.createHandle(syntaxTreeContentProvider),
     );
     registerCommand(
         'rust-analyzer.expandMacro',
-        commands.expandMacro.createHandle(expandMacroContentProvider)
+        commands.expandMacro.createHandle(expandMacroContentProvider),
     );
 
     vscode.workspace.onDidChangeTextDocument(
         events.changeTextDocument.createHandler(syntaxTreeContentProvider),
         null,
-        context.subscriptions
+        context.subscriptions,
     );
 
     const startServer = () => Server.start(allNotifications);
@@ -159,7 +160,11 @@ export function activate(context: vscode.ExtensionContext) {
     });
 
     // Start the language server, finally!
-    startServer();
+    try {
+        await startServer();
+    } catch (e) {
+        vscode.window.showErrorMessage(e.message);
+    }
 
     if (Server.config.displayInlayHints) {
         const hintsUpdater = new HintsUpdater();
@@ -173,25 +178,25 @@ export function activate(context: vscode.ExtensionContext) {
                         editorChangeDisposable.dispose();
                     }
                     return hintsUpdater.refreshHintsForVisibleEditors();
-                }
+                },
             );
 
             disposeOnDeactivation(
                 vscode.window.onDidChangeVisibleTextEditors(_ =>
-                    hintsUpdater.refreshHintsForVisibleEditors()
-                )
+                    hintsUpdater.refreshHintsForVisibleEditors(),
+                ),
             );
             disposeOnDeactivation(
                 vscode.workspace.onDidChangeTextDocument(e =>
-                    hintsUpdater.refreshHintsForVisibleEditors(e)
-                )
+                    hintsUpdater.refreshHintsForVisibleEditors(e),
+                ),
             );
             disposeOnDeactivation(
                 vscode.workspace.onDidChangeConfiguration(_ =>
                     hintsUpdater.toggleHintsDisplay(
-                        Server.config.displayInlayHints
-                    )
-                )
+                        Server.config.displayInlayHints,
+                    ),
+                ),
             );
         });
     }
@@ -204,10 +209,10 @@ export function deactivate(): Thenable<void> {
     return Server.client.stop();
 }
 
-async function reloadServer(startServer: () => void) {
+async function reloadServer(startServer: () => Promise<void>) {
     if (Server.client != null) {
         vscode.window.showInformationMessage('Reloading rust-analyzer...');
         await Server.client.stop();
-        startServer();
+        await startServer();
     }
 }
diff --git a/editors/code/src/highlighting.ts b/editors/code/src/highlighting.ts
index 0a38c9ef674..68eae094199 100644
--- a/editors/code/src/highlighting.ts
+++ b/editors/code/src/highlighting.ts
@@ -67,7 +67,7 @@ export class Highlighter {
     > {
         const decoration = (
             tag: string,
-            textDecoration?: string
+            textDecoration?: string,
         ): [string, vscode.TextEditorDecorationType] => {
             const rule = scopesMapper.toRule(tag, scopes.find);
 
@@ -90,9 +90,10 @@ export class Highlighter {
             }
         };
 
-        const decorations: Iterable<
-            [string, vscode.TextEditorDecorationType]
-        > = [
+        const decorations: Iterable<[
+            string,
+            vscode.TextEditorDecorationType,
+        ]> = [
             decoration('comment'),
             decoration('string'),
             decoration('keyword'),
@@ -101,16 +102,23 @@ export class Highlighter {
             decoration('function'),
             decoration('parameter'),
             decoration('constant'),
+            decoration('type.builtin'),
+            decoration('type.generic'),
+            decoration('type.lifetime'),
+            decoration('type.param'),
+            decoration('type.self'),
             decoration('type'),
-            decoration('builtin'),
             decoration('text'),
             decoration('attribute'),
             decoration('literal'),
+            decoration('literal.numeric'),
+            decoration('literal.char'),
+            decoration('literal.byte'),
             decoration('macro'),
             decoration('variable'),
             decoration('variable.mut', 'underline'),
             decoration('field'),
-            decoration('module')
+            decoration('module'),
         ];
 
         return new Map<string, vscode.TextEditorDecorationType>(decorations);
@@ -139,7 +147,6 @@ export class Highlighter {
         //
         // Note: decoration objects need to be kept around so we can dispose them
         // if the user disables syntax highlighting
-
         if (this.decorations == null) {
             this.decorations = Highlighter.initDecorations();
         }
@@ -168,23 +175,22 @@ export class Highlighter {
                 colorfulIdents
                     .get(d.bindingHash)![0]
                     .push(
-                        Server.client.protocol2CodeConverter.asRange(d.range)
+                        Server.client.protocol2CodeConverter.asRange(d.range),
                     );
             } else {
                 byTag
                     .get(d.tag)!
                     .push(
-                        Server.client.protocol2CodeConverter.asRange(d.range)
+                        Server.client.protocol2CodeConverter.asRange(d.range),
                     );
             }
         }
 
         for (const tag of byTag.keys()) {
             const dec = this.decorations.get(
-                tag
+                tag,
             ) as vscode.TextEditorDecorationType;
             const ranges = byTag.get(tag)!;
-
             editor.setDecorations(dec, ranges);
         }
 
@@ -192,7 +198,7 @@ export class Highlighter {
             const textDecoration = mut ? 'underline' : undefined;
             const dec = vscode.window.createTextEditorDecorationType({
                 light: { color: fancify(hash, 'light'), textDecoration },
-                dark: { color: fancify(hash, 'dark'), textDecoration }
+                dark: { color: fancify(hash, 'dark'), textDecoration },
             });
             editor.setDecorations(dec, ranges);
         }
diff --git a/editors/code/src/notifications/publish_decorations.ts b/editors/code/src/notifications/publish_decorations.ts
index 3180019b742..f23e286ad5d 100644
--- a/editors/code/src/notifications/publish_decorations.ts
+++ b/editors/code/src/notifications/publish_decorations.ts
@@ -9,11 +9,16 @@ export interface PublishDecorationsParams {
 }
 
 export function handle(params: PublishDecorationsParams) {
-    const targetEditor = vscode.window.visibleTextEditors.find(
-        editor => editor.document.uri.toString() === params.uri
-    );
+    const targetEditor = vscode.window.visibleTextEditors.find(editor => {
+        const unescapedUri = unescape(editor.document.uri.toString());
+        // Unescaped URI looks like:
+        // file:///c:/Workspace/ra-test/src/main.rs
+        return unescapedUri === params.uri;
+    });
+
     if (!Server.config.highlightingOn || !targetEditor) {
         return;
     }
+
     Server.highlighter.setHighlights(targetEditor, params.decorations);
 }
diff --git a/editors/code/src/server.ts b/editors/code/src/server.ts
index 7907b70bc51..5ace1d0faeb 100644
--- a/editors/code/src/server.ts
+++ b/editors/code/src/server.ts
@@ -1,4 +1,5 @@
-import { homedir } from 'os';
+import { lookpath } from 'lookpath';
+import { homedir, platform } from 'os';
 import * as lc from 'vscode-languageclient';
 
 import { window, workspace } from 'vscode';
@@ -17,8 +18,8 @@ export class Server {
     public static config = new Config();
     public static client: lc.LanguageClient;
 
-    public static start(
-        notificationHandlers: Iterable<[string, lc.GenericNotificationHandler]>
+    public static async start(
+        notificationHandlers: Iterable<[string, lc.GenericNotificationHandler]>,
     ) {
         // '.' Is the fallback if no folder is open
         // 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 {
             folder = workspace.workspaceFolders[0].uri.fsPath.toString();
         }
 
+        const command = expandPathResolving(this.config.raLspServerPath);
+        // FIXME: remove check when the following issue is fixed:
+        // https://github.com/otiai10/lookpath/issues/4
+        if (platform() !== 'win32') {
+            if (!(await lookpath(command))) {
+                throw new Error(
+                    `Cannot find rust-analyzer server \`${command}\` in PATH.`,
+                );
+            }
+        }
         const run: lc.Executable = {
-            command: expandPathResolving(this.config.raLspServerPath),
-            options: { cwd: folder }
+            command,
+            options: { cwd: folder },
         };
         const serverOptions: lc.ServerOptions = {
             run,
-            debug: run
+            debug: run,
         };
         const traceOutputChannel = window.createOutputChannel(
-            'Rust Analyzer Language Server Trace'
+            'Rust Analyzer Language Server Trace',
         );
         const clientOptions: lc.LanguageClientOptions = {
             documentSelector: [{ scheme: 'file', language: 'rust' }],
@@ -46,16 +57,18 @@ export class Server {
                 maxInlayHintLength: Server.config.maxInlayHintLength,
                 excludeGlobs: Server.config.excludeGlobs,
                 useClientWatching: Server.config.useClientWatching,
-                featureFlags: Server.config.featureFlags
+                featureFlags: Server.config.featureFlags,
+                withSysroot: Server.config.withSysroot,
+                cargoFeatures: Server.config.cargoFeatures,
             },
-            traceOutputChannel
+            traceOutputChannel,
         };
 
         Server.client = new lc.LanguageClient(
             'rust-analyzer',
             'Rust Analyzer Language Server',
             serverOptions,
-            clientOptions
+            clientOptions,
         );
         // HACK: This is an awful way of filtering out the decorations notifications
         // However, pending proper support, this is the most effecitve approach
@@ -68,10 +81,10 @@ export class Server {
                 if (typeof messageOrDataObject === 'string') {
                     if (
                         messageOrDataObject.includes(
-                            'rust-analyzer/publishDecorations'
+                            'rust-analyzer/publishDecorations',
                         ) ||
                         messageOrDataObject.includes(
-                            'rust-analyzer/decorationsRequest'
+                            'rust-analyzer/decorationsRequest',
                         )
                     ) {
                         // Don't log publish decorations requests
@@ -83,7 +96,7 @@ export class Server {
                     // @ts-ignore
                     Server.client.logObjectTrace(messageOrDataObject);
                 }
-            }
+            },
         };
         Server.client.registerProposedFeatures();
         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 00000000000..bfef33c7de7
--- /dev/null
+++ b/editors/code/src/test/fixtures/rust-diagnostics/error/E0277.json
@@ -0,0 +1,261 @@
+{
+    "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",
+    "children": [
+        {
+            "children": [],
+            "code": null,
+            "level": "help",
+            "message": "the trait `std::cmp::PartialEq<&str>` is not implemented for `{integer}`",
+            "rendered": null,
+            "spans": []
+        }
+    ],
+    "code": {
+        "code": "E0277",
+        "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"
+    },
+    "level": "error",
+    "message": "can't compare `{integer}` with `&str`",
+    "spans": [
+        {
+            "byte_end": 155,
+            "byte_start": 153,
+            "column_end": 33,
+            "column_start": 31,
+            "expansion": {
+                "def_site_span": {
+                    "byte_end": 940,
+                    "byte_start": 0,
+                    "column_end": 6,
+                    "column_start": 1,
+                    "expansion": null,
+                    "file_name": "<::core::macros::assert_eq macros>",
+                    "is_primary": false,
+                    "label": null,
+                    "line_end": 36,
+                    "line_start": 1,
+                    "suggested_replacement": null,
+                    "suggestion_applicability": null,
+                    "text": [
+                        {
+                            "highlight_end": 35,
+                            "highlight_start": 1,
+                            "text": "($ left : expr, $ right : expr) =>"
+                        },
+                        {
+                            "highlight_end": 3,
+                            "highlight_start": 1,
+                            "text": "({"
+                        },
+                        {
+                            "highlight_end": 33,
+                            "highlight_start": 1,
+                            "text": "     match (& $ left, & $ right)"
+                        },
+                        {
+                            "highlight_end": 7,
+                            "highlight_start": 1,
+                            "text": "     {"
+                        },
+                        {
+                            "highlight_end": 34,
+                            "highlight_start": 1,
+                            "text": "         (left_val, right_val) =>"
+                        },
+                        {
+                            "highlight_end": 11,
+                            "highlight_start": 1,
+                            "text": "         {"
+                        },
+                        {
+                            "highlight_end": 46,
+                            "highlight_start": 1,
+                            "text": "             if ! (* left_val == * right_val)"
+                        },
+                        {
+                            "highlight_end": 15,
+                            "highlight_start": 1,
+                            "text": "             {"
+                        },
+                        {
+                            "highlight_end": 25,
+                            "highlight_start": 1,
+                            "text": "                 panic !"
+                        },
+                        {
+                            "highlight_end": 57,
+                            "highlight_start": 1,
+                            "text": "                 (r#\"assertion failed: `(left == right)`"
+                        },
+                        {
+                            "highlight_end": 16,
+                            "highlight_start": 1,
+                            "text": "  left: `{:?}`,"
+                        },
+                        {
+                            "highlight_end": 18,
+                            "highlight_start": 1,
+                            "text": " right: `{:?}`\"#,"
+                        },
+                        {
+                            "highlight_end": 47,
+                            "highlight_start": 1,
+                            "text": "                  & * left_val, & * right_val)"
+                        },
+                        {
+                            "highlight_end": 15,
+                            "highlight_start": 1,
+                            "text": "             }"
+                        },
+                        {
+                            "highlight_end": 11,
+                            "highlight_start": 1,
+                            "text": "         }"
+                        },
+                        {
+                            "highlight_end": 7,
+                            "highlight_start": 1,
+                            "text": "     }"
+                        },
+                        {
+                            "highlight_end": 42,
+                            "highlight_start": 1,
+                            "text": " }) ; ($ left : expr, $ right : expr,) =>"
+                        },
+                        {
+                            "highlight_end": 49,
+                            "highlight_start": 1,
+                            "text": "({ $ crate :: assert_eq ! ($ left, $ right) }) ;"
+                        },
+                        {
+                            "highlight_end": 53,
+                            "highlight_start": 1,
+                            "text": "($ left : expr, $ right : expr, $ ($ arg : tt) +) =>"
+                        },
+                        {
+                            "highlight_end": 3,
+                            "highlight_start": 1,
+                            "text": "({"
+                        },
+                        {
+                            "highlight_end": 37,
+                            "highlight_start": 1,
+                            "text": "     match (& ($ left), & ($ right))"
+                        },
+                        {
+                            "highlight_end": 7,
+                            "highlight_start": 1,
+                            "text": "     {"
+                        },
+                        {
+                            "highlight_end": 34,
+                            "highlight_start": 1,
+                            "text": "         (left_val, right_val) =>"
+                        },
+                        {
+                            "highlight_end": 11,
+                            "highlight_start": 1,
+                            "text": "         {"
+                        },
+                        {
+                            "highlight_end": 46,
+                            "highlight_start": 1,
+                            "text": "             if ! (* left_val == * right_val)"
+                        },
+                        {
+                            "highlight_end": 15,
+                            "highlight_start": 1,
+                            "text": "             {"
+                        },
+                        {
+                            "highlight_end": 25,
+                            "highlight_start": 1,
+                            "text": "                 panic !"
+                        },
+                        {
+                            "highlight_end": 57,
+                            "highlight_start": 1,
+                            "text": "                 (r#\"assertion failed: `(left == right)`"
+                        },
+                        {
+                            "highlight_end": 16,
+                            "highlight_start": 1,
+                            "text": "  left: `{:?}`,"
+                        },
+                        {
+                            "highlight_end": 22,
+                            "highlight_start": 1,
+                            "text": " right: `{:?}`: {}\"#,"
+                        },
+                        {
+                            "highlight_end": 72,
+                            "highlight_start": 1,
+                            "text": "                  & * left_val, & * right_val, $ crate :: format_args !"
+                        },
+                        {
+                            "highlight_end": 33,
+                            "highlight_start": 1,
+                            "text": "                  ($ ($ arg) +))"
+                        },
+                        {
+                            "highlight_end": 15,
+                            "highlight_start": 1,
+                            "text": "             }"
+                        },
+                        {
+                            "highlight_end": 11,
+                            "highlight_start": 1,
+                            "text": "         }"
+                        },
+                        {
+                            "highlight_end": 7,
+                            "highlight_start": 1,
+                            "text": "     }"
+                        },
+                        {
+                            "highlight_end": 6,
+                            "highlight_start": 1,
+                            "text": " }) ;"
+                        }
+                    ]
+                },
+                "macro_decl_name": "assert_eq!",
+                "span": {
+                    "byte_end": 38,
+                    "byte_start": 16,
+                    "column_end": 27,
+                    "column_start": 5,
+                    "expansion": null,
+                    "file_name": "src/main.rs",
+                    "is_primary": false,
+                    "label": null,
+                    "line_end": 2,
+                    "line_start": 2,
+                    "suggested_replacement": null,
+                    "suggestion_applicability": null,
+                    "text": [
+                        {
+                            "highlight_end": 27,
+                            "highlight_start": 5,
+                            "text": "    assert_eq!(1, \"love\");"
+                        }
+                    ]
+                }
+            },
+            "file_name": "<::core::macros::assert_eq macros>",
+            "is_primary": true,
+            "label": "no implementation for `{integer} == &str`",
+            "line_end": 7,
+            "line_start": 7,
+            "suggested_replacement": null,
+            "suggestion_applicability": null,
+            "text": [
+                {
+                    "highlight_end": 33,
+                    "highlight_start": 31,
+                    "text": "             if ! (* left_val == * right_val)"
+                }
+            ]
+        }
+    ]
+}
diff --git a/editors/code/src/test/utils/diagnotics/SuggestedFix.test.ts b/editors/code/src/test/utils/diagnotics/SuggestedFix.test.ts
index 6c7f436f359..2b25eb705dd 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';
 
 const location1 = new vscode.Location(
     vscode.Uri.file('/file/1'),
-    new vscode.Range(new vscode.Position(1, 2), new vscode.Position(3, 4))
+    new vscode.Range(new vscode.Position(1, 2), new vscode.Position(3, 4)),
 );
 
 const location2 = new vscode.Location(
     vscode.Uri.file('/file/2'),
-    new vscode.Range(new vscode.Position(5, 6), new vscode.Position(7, 8))
+    new vscode.Range(new vscode.Position(5, 6), new vscode.Position(7, 8)),
 );
 
 describe('SuggestedFix', () => {
@@ -20,13 +20,13 @@ describe('SuggestedFix', () => {
             const suggestion1 = new SuggestedFix(
                 'Replace me!',
                 location1,
-                'With this!'
+                'With this!',
             );
 
             const suggestion2 = new SuggestedFix(
                 'Replace me!',
                 location1,
-                'With this!'
+                'With this!',
             );
 
             assert(suggestion1.isEqual(suggestion2));
@@ -36,13 +36,13 @@ describe('SuggestedFix', () => {
             const suggestion1 = new SuggestedFix(
                 'Replace me!',
                 location1,
-                'With this!'
+                'With this!',
             );
 
             const suggestion2 = new SuggestedFix(
                 'Not the same title!',
                 location1,
-                'With this!'
+                'With this!',
             );
 
             assert(!suggestion1.isEqual(suggestion2));
@@ -52,13 +52,13 @@ describe('SuggestedFix', () => {
             const suggestion1 = new SuggestedFix(
                 'Replace me!',
                 location1,
-                'With this!'
+                'With this!',
             );
 
             const suggestion2 = new SuggestedFix(
                 'Replace me!',
                 location1,
-                'With something else!'
+                'With something else!',
             );
 
             assert(!suggestion1.isEqual(suggestion2));
@@ -68,13 +68,13 @@ describe('SuggestedFix', () => {
             const suggestion1 = new SuggestedFix(
                 'Replace me!',
                 location1,
-                'With this!'
+                'With this!',
             );
 
             const suggestion2 = new SuggestedFix(
                 'Replace me!',
                 location2,
-                'With this!'
+                'With this!',
             );
 
             assert(!suggestion1.isEqual(suggestion2));
@@ -85,14 +85,14 @@ describe('SuggestedFix', () => {
                 'Replace me!',
                 location1,
                 'With this!',
-                SuggestionApplicability.MachineApplicable
+                SuggestionApplicability.MachineApplicable,
             );
 
             const suggestion2 = new SuggestedFix(
                 'Replace me!',
                 location2,
                 'With this!',
-                SuggestionApplicability.HasPlaceholders
+                SuggestionApplicability.HasPlaceholders,
             );
 
             assert(!suggestion1.isEqual(suggestion2));
@@ -104,7 +104,7 @@ describe('SuggestedFix', () => {
             const suggestion = new SuggestedFix(
                 'Replace me!',
                 location1,
-                'With this!'
+                'With this!',
             );
 
             const codeAction = suggestion.toCodeAction();
@@ -114,7 +114,8 @@ describe('SuggestedFix', () => {
 
             const edit = codeAction.edit;
             if (!edit) {
-                return assert.fail('Code Action edit unexpectedly missing');
+                assert.fail('Code Action edit unexpectedly missing');
+                return;
             }
 
             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 f0328893e73..ef09013f413 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');
 const uri2 = vscode.Uri.file('/file/2');
 
 const mockDocument1 = ({
-    uri: uri1
+    uri: uri1,
 } as unknown) as vscode.TextDocument;
 
 const mockDocument2 = ({
-    uri: uri2
+    uri: uri2,
 } as unknown) as vscode.TextDocument;
 
 const range1 = new vscode.Range(
     new vscode.Position(1, 2),
-    new vscode.Position(3, 4)
+    new vscode.Position(3, 4),
 );
 const range2 = new vscode.Range(
     new vscode.Position(5, 6),
-    new vscode.Position(7, 8)
+    new vscode.Position(7, 8),
 );
 
 const diagnostic1 = new vscode.Diagnostic(range1, 'First diagnostic');
@@ -32,7 +32,7 @@ function suggestion1(): SuggestedFix {
     return new SuggestedFix(
         'Replace me!',
         new vscode.Location(uri1, range1),
-        'With this!'
+        'With this!',
     );
 }
 
@@ -44,7 +44,7 @@ describe('SuggestedFixCollection', () => {
         // Specify the document and range that exactly matches
         const codeActions = suggestedFixes.provideCodeActions(
             mockDocument1,
-            range1
+            range1,
         );
 
         assert.strictEqual(codeActions.length, 1);
@@ -53,7 +53,8 @@ describe('SuggestedFixCollection', () => {
 
         const { diagnostics } = codeAction;
         if (!diagnostics) {
-            return assert.fail('Diagnostics unexpectedly missing');
+            assert.fail('Diagnostics unexpectedly missing');
+            return;
         }
 
         assert.strictEqual(diagnostics.length, 1);
@@ -66,7 +67,7 @@ describe('SuggestedFixCollection', () => {
 
         const codeActions = suggestedFixes.provideCodeActions(
             mockDocument1,
-            range2
+            range2,
         );
 
         assert(!codeActions || codeActions.length === 0);
@@ -78,7 +79,7 @@ describe('SuggestedFixCollection', () => {
 
         const codeActions = suggestedFixes.provideCodeActions(
             mockDocument2,
-            range1
+            range1,
         );
 
         assert(!codeActions || codeActions.length === 0);
@@ -91,7 +92,7 @@ describe('SuggestedFixCollection', () => {
 
         const codeActions = suggestedFixes.provideCodeActions(
             mockDocument1,
-            range1
+            range1,
         );
 
         assert(!codeActions || codeActions.length === 0);
@@ -106,7 +107,7 @@ describe('SuggestedFixCollection', () => {
 
         const codeActions = suggestedFixes.provideCodeActions(
             mockDocument1,
-            range1
+            range1,
         );
 
         assert.strictEqual(codeActions.length, 1);
@@ -114,7 +115,8 @@ describe('SuggestedFixCollection', () => {
         const { diagnostics } = codeAction;
 
         if (!diagnostics) {
-            return assert.fail('Diagnostics unexpectedly missing');
+            assert.fail('Diagnostics unexpectedly missing');
+            return;
         }
 
         // 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 327d15046f5..358325cc8dd 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 {
     MappedRustDiagnostic,
     mapRustDiagnosticToVsCode,
     RustDiagnostic,
-    SuggestionApplicability
+    SuggestionApplicability,
 } from '../../../utils/diagnostics/rust';
 
 function loadDiagnosticFixture(name: string): RustDiagnostic {
     const jsonText = fs
         .readFileSync(
             // We're actually in our JavaScript output directory, climb out
-            `${__dirname}/../../../../src/test/fixtures/rust-diagnostics/${name}.json`
+            `${__dirname}/../../../../src/test/fixtures/rust-diagnostics/${name}.json`,
         )
         .toString();
 
@@ -33,12 +33,12 @@ function mapFixtureToVsCode(name: string): MappedRustDiagnostic {
 describe('mapRustDiagnosticToVsCode', () => {
     it('should map an incompatible type for trait error', () => {
         const { diagnostic, suggestedFixes } = mapFixtureToVsCode(
-            'error/E0053'
+            'error/E0053',
         );
 
         assert.strictEqual(
             diagnostic.severity,
-            vscode.DiagnosticSeverity.Error
+            vscode.DiagnosticSeverity.Error,
         );
         assert.strictEqual(diagnostic.source, 'rustc');
         assert.strictEqual(
@@ -46,8 +46,8 @@ describe('mapRustDiagnosticToVsCode', () => {
             [
                 `method \`next\` has an incompatible type for trait`,
                 `expected type \`fn(&mut ty::list_iter::ListIterator<'list, M>) -> std::option::Option<&ty::Ref<M>>\``,
-                `   found type \`fn(&ty::list_iter::ListIterator<'list, M>) -> std::option::Option<&'list ty::Ref<M>>\``
-            ].join('\n')
+                `   found type \`fn(&ty::list_iter::ListIterator<'list, M>) -> std::option::Option<&'list ty::Ref<M>>\``,
+            ].join('\n'),
         );
         assert.strictEqual(diagnostic.code, 'E0053');
         assert.deepStrictEqual(diagnostic.tags, []);
@@ -61,24 +61,24 @@ describe('mapRustDiagnosticToVsCode', () => {
 
     it('should map an unused variable warning', () => {
         const { diagnostic, suggestedFixes } = mapFixtureToVsCode(
-            'warning/unused_variables'
+            'warning/unused_variables',
         );
 
         assert.strictEqual(
             diagnostic.severity,
-            vscode.DiagnosticSeverity.Warning
+            vscode.DiagnosticSeverity.Warning,
         );
         assert.strictEqual(
             diagnostic.message,
             [
                 'unused variable: `foo`',
-                '#[warn(unused_variables)] on by default'
-            ].join('\n')
+                '#[warn(unused_variables)] on by default',
+            ].join('\n'),
         );
         assert.strictEqual(diagnostic.code, 'unused_variables');
         assert.strictEqual(diagnostic.source, 'rustc');
         assert.deepStrictEqual(diagnostic.tags, [
-            vscode.DiagnosticTag.Unnecessary
+            vscode.DiagnosticTag.Unnecessary,
         ]);
 
         // No related information
@@ -89,29 +89,29 @@ describe('mapRustDiagnosticToVsCode', () => {
         const [suggestedFix] = suggestedFixes;
         assert.strictEqual(
             suggestedFix.title,
-            'consider prefixing with an underscore: `_foo`'
+            'consider prefixing with an underscore: `_foo`',
         );
         assert.strictEqual(
             suggestedFix.applicability,
-            SuggestionApplicability.MachineApplicable
+            SuggestionApplicability.MachineApplicable,
         );
     });
 
     it('should map a wrong number of parameters error', () => {
         const { diagnostic, suggestedFixes } = mapFixtureToVsCode(
-            'error/E0061'
+            'error/E0061',
         );
 
         assert.strictEqual(
             diagnostic.severity,
-            vscode.DiagnosticSeverity.Error
+            vscode.DiagnosticSeverity.Error,
         );
         assert.strictEqual(
             diagnostic.message,
             [
                 'this function takes 2 parameters but 3 parameters were supplied',
-                'expected 2 parameters'
-            ].join('\n')
+                'expected 2 parameters',
+            ].join('\n'),
         );
         assert.strictEqual(diagnostic.code, 'E0061');
         assert.strictEqual(diagnostic.source, 'rustc');
@@ -120,7 +120,8 @@ describe('mapRustDiagnosticToVsCode', () => {
         // One related information for the original definition
         const relatedInformation = diagnostic.relatedInformation;
         if (!relatedInformation) {
-            return assert.fail('Related information unexpectedly undefined');
+            assert.fail('Related information unexpectedly undefined');
+            return;
         }
         assert.strictEqual(relatedInformation.length, 1);
         const [related] = relatedInformation;
@@ -132,12 +133,12 @@ describe('mapRustDiagnosticToVsCode', () => {
 
     it('should map a Clippy copy pass by ref warning', () => {
         const { diagnostic, suggestedFixes } = mapFixtureToVsCode(
-            'clippy/trivially_copy_pass_by_ref'
+            'clippy/trivially_copy_pass_by_ref',
         );
 
         assert.strictEqual(
             diagnostic.severity,
-            vscode.DiagnosticSeverity.Warning
+            vscode.DiagnosticSeverity.Warning,
         );
         assert.strictEqual(diagnostic.source, 'clippy');
         assert.strictEqual(
@@ -145,8 +146,8 @@ describe('mapRustDiagnosticToVsCode', () => {
             [
                 'this argument is passed by reference, but would be more efficient if passed by value',
                 '#[warn(clippy::trivially_copy_pass_by_ref)] implied by #[warn(clippy::all)]',
-                'for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#trivially_copy_pass_by_ref'
-            ].join('\n')
+                'for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#trivially_copy_pass_by_ref',
+            ].join('\n'),
         );
         assert.strictEqual(diagnostic.code, 'trivially_copy_pass_by_ref');
         assert.deepStrictEqual(diagnostic.tags, []);
@@ -154,7 +155,8 @@ describe('mapRustDiagnosticToVsCode', () => {
         // One related information for the lint definition
         const relatedInformation = diagnostic.relatedInformation;
         if (!relatedInformation) {
-            return assert.fail('Related information unexpectedly undefined');
+            assert.fail('Related information unexpectedly undefined');
+            return;
         }
         assert.strictEqual(relatedInformation.length, 1);
         const [related] = relatedInformation;
@@ -165,27 +167,27 @@ describe('mapRustDiagnosticToVsCode', () => {
         const [suggestedFix] = suggestedFixes;
         assert.strictEqual(
             suggestedFix.title,
-            'consider passing by value instead: `self`'
+            'consider passing by value instead: `self`',
         );
         // Clippy does not mark this with any applicability
         assert.strictEqual(
             suggestedFix.applicability,
-            SuggestionApplicability.Unspecified
+            SuggestionApplicability.Unspecified,
         );
     });
 
     it('should map a mismatched type error', () => {
         const { diagnostic, suggestedFixes } = mapFixtureToVsCode(
-            'error/E0308'
+            'error/E0308',
         );
 
         assert.strictEqual(
             diagnostic.severity,
-            vscode.DiagnosticSeverity.Error
+            vscode.DiagnosticSeverity.Error,
         );
         assert.strictEqual(
             diagnostic.message,
-            ['mismatched types', 'expected usize, found u32'].join('\n')
+            ['mismatched types', 'expected usize, found u32'].join('\n'),
         );
         assert.strictEqual(diagnostic.code, 'E0308');
         assert.strictEqual(diagnostic.source, 'rustc');
@@ -197,4 +199,38 @@ describe('mapRustDiagnosticToVsCode', () => {
         // There are no suggested fixes
         assert.strictEqual(suggestedFixes.length, 0);
     });
+
+    it('should map a macro invocation location to normal file path', () => {
+        const { location, diagnostic, suggestedFixes } = mapFixtureToVsCode(
+            'error/E0277',
+        );
+
+        assert.strictEqual(
+            diagnostic.severity,
+            vscode.DiagnosticSeverity.Error,
+        );
+        assert.strictEqual(
+            diagnostic.message,
+            [
+                "can't compare `{integer}` with `&str`",
+                'the trait `std::cmp::PartialEq<&str>` is not implemented for `{integer}`',
+            ].join('\n'),
+        );
+        assert.strictEqual(diagnostic.code, 'E0277');
+        assert.strictEqual(diagnostic.source, 'rustc');
+        assert.deepStrictEqual(diagnostic.tags, []);
+
+        // No related information
+        assert.deepStrictEqual(diagnostic.relatedInformation, []);
+
+        // There are no suggested fixes
+        assert.strictEqual(suggestedFixes.length, 0);
+
+        // The file url should be normal file
+        // Ignore the first part because it depends on vs workspace location
+        assert.strictEqual(
+            location.uri.path.substr(-'src/main.rs'.length),
+            'src/main.rs',
+        );
+    });
 });
diff --git a/editors/code/src/test/utils/diagnotics/vscode.test.ts b/editors/code/src/test/utils/diagnotics/vscode.test.ts
index 542dec1f54f..4944dd0328c 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';
 
 const range1 = new vscode.Range(
     new vscode.Position(1, 2),
-    new vscode.Position(3, 4)
+    new vscode.Position(3, 4),
 );
 
 const range2 = new vscode.Range(
     new vscode.Position(5, 6),
-    new vscode.Position(7, 8)
+    new vscode.Position(7, 8),
 );
 
 describe('areDiagnosticsEqual', () => {
@@ -18,13 +18,13 @@ describe('areDiagnosticsEqual', () => {
         const diagnostic1 = new vscode.Diagnostic(
             range1,
             'Hello, world!',
-            vscode.DiagnosticSeverity.Error
+            vscode.DiagnosticSeverity.Error,
         );
 
         const diagnostic2 = new vscode.Diagnostic(
             range1,
             'Hello, world!',
-            vscode.DiagnosticSeverity.Error
+            vscode.DiagnosticSeverity.Error,
         );
 
         assert(areDiagnosticsEqual(diagnostic1, diagnostic2));
@@ -34,14 +34,14 @@ describe('areDiagnosticsEqual', () => {
         const diagnostic1 = new vscode.Diagnostic(
             range1,
             'Hello, world!',
-            vscode.DiagnosticSeverity.Error
+            vscode.DiagnosticSeverity.Error,
         );
         diagnostic1.source = 'rustc';
 
         const diagnostic2 = new vscode.Diagnostic(
             range1,
             'Hello, world!',
-            vscode.DiagnosticSeverity.Error
+            vscode.DiagnosticSeverity.Error,
         );
         diagnostic2.source = 'clippy';
 
@@ -52,13 +52,13 @@ describe('areDiagnosticsEqual', () => {
         const diagnostic1 = new vscode.Diagnostic(
             range1,
             'Hello, world!',
-            vscode.DiagnosticSeverity.Error
+            vscode.DiagnosticSeverity.Error,
         );
 
         const diagnostic2 = new vscode.Diagnostic(
             range2,
             'Hello, world!',
-            vscode.DiagnosticSeverity.Error
+            vscode.DiagnosticSeverity.Error,
         );
 
         assert(!areDiagnosticsEqual(diagnostic1, diagnostic2));
@@ -68,13 +68,13 @@ describe('areDiagnosticsEqual', () => {
         const diagnostic1 = new vscode.Diagnostic(
             range1,
             'Hello, world!',
-            vscode.DiagnosticSeverity.Error
+            vscode.DiagnosticSeverity.Error,
         );
 
         const diagnostic2 = new vscode.Diagnostic(
             range1,
             'Goodbye!, world!',
-            vscode.DiagnosticSeverity.Error
+            vscode.DiagnosticSeverity.Error,
         );
 
         assert(!areDiagnosticsEqual(diagnostic1, diagnostic2));
@@ -84,13 +84,13 @@ describe('areDiagnosticsEqual', () => {
         const diagnostic1 = new vscode.Diagnostic(
             range1,
             'Hello, world!',
-            vscode.DiagnosticSeverity.Warning
+            vscode.DiagnosticSeverity.Warning,
         );
 
         const diagnostic2 = new vscode.Diagnostic(
             range1,
             'Hello, world!',
-            vscode.DiagnosticSeverity.Error
+            vscode.DiagnosticSeverity.Error,
         );
 
         assert(!areDiagnosticsEqual(diagnostic1, diagnostic2));
diff --git a/editors/code/src/test/utils/index.ts b/editors/code/src/test/utils/index.ts
index 16715a286c3..9927daaf6ae 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';
 export function run(): Promise<void> {
     // Create the mocha test
     const mocha = new Mocha({
-        ui: 'bdd'
+        ui: 'bdd',
     });
     mocha.useColors(true);
 
diff --git a/editors/code/src/utils/diagnostics/SuggestedFix.ts b/editors/code/src/utils/diagnostics/SuggestedFix.ts
index b1be2a225b6..6e660bb61d9 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 {
         title: string,
         location: vscode.Location,
         replacement: string,
-        applicability: SuggestionApplicability = SuggestionApplicability.Unspecified
+        applicability: SuggestionApplicability = SuggestionApplicability.Unspecified,
     ) {
         this.title = title;
         this.location = location;
@@ -51,7 +51,7 @@ export default class SuggestedFix {
     public toCodeAction(): vscode.CodeAction {
         const codeAction = new vscode.CodeAction(
             this.title,
-            vscode.CodeActionKind.QuickFix
+            vscode.CodeActionKind.QuickFix,
         );
 
         const edit = new vscode.WorkspaceEdit();
diff --git a/editors/code/src/utils/diagnostics/SuggestedFixCollection.ts b/editors/code/src/utils/diagnostics/SuggestedFixCollection.ts
index 132ce12f890..57c9856cfa3 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
      */
     public addSuggestedFixForDiagnostic(
         suggestedFix: SuggestedFix,
-        diagnostic: vscode.Diagnostic
+        diagnostic: vscode.Diagnostic,
     ): void {
         const fileUriString = suggestedFix.location.uri.toString();
         const fileSuggestions = this.suggestedFixes.get(fileUriString) || [];
 
         const existingSuggestion = fileSuggestions.find(s =>
-            s.isEqual(suggestedFix)
+            s.isEqual(suggestedFix),
         );
 
         if (existingSuggestion) {
@@ -65,7 +65,7 @@ export default class SuggestedFixCollection
      */
     public provideCodeActions(
         document: vscode.TextDocument,
-        range: vscode.Range
+        range: vscode.Range,
     ): vscode.CodeAction[] {
         const documentUriString = document.uri.toString();
 
diff --git a/editors/code/src/utils/diagnostics/rust.ts b/editors/code/src/utils/diagnostics/rust.ts
index 0550d037247..1f0c0d3e405 100644
--- a/editors/code/src/utils/diagnostics/rust.ts
+++ b/editors/code/src/utils/diagnostics/rust.ts
@@ -7,7 +7,13 @@ export enum SuggestionApplicability {
     MachineApplicable = 'MachineApplicable',
     HasPlaceholders = 'HasPlaceholders',
     MaybeIncorrect = 'MaybeIncorrect',
-    Unspecified = 'Unspecified'
+    Unspecified = 'Unspecified',
+}
+
+export interface RustDiagnosticSpanMacroExpansion {
+    span: RustDiagnosticSpan;
+    macro_decl_name: string;
+    def_site_span?: RustDiagnosticSpan;
 }
 
 // Reference:
@@ -20,6 +26,7 @@ export interface RustDiagnosticSpan {
     is_primary: boolean;
     file_name: string;
     label?: string;
+    expansion?: RustDiagnosticSpanMacroExpansion;
     suggested_replacement?: string;
     suggestion_applicability?: SuggestionApplicability;
 }
@@ -61,15 +68,46 @@ function mapLevelToSeverity(s: string): vscode.DiagnosticSeverity {
 }
 
 /**
+ * Check whether a file name is from macro invocation
+ */
+function isFromMacro(fileName: string): boolean {
+    return fileName.startsWith('<') && fileName.endsWith('>');
+}
+
+/**
+ * Converts a Rust macro span to a VsCode location recursively
+ */
+function mapMacroSpanToLocation(
+    spanMacro: RustDiagnosticSpanMacroExpansion,
+): vscode.Location | undefined {
+    if (!isFromMacro(spanMacro.span.file_name)) {
+        return mapSpanToLocation(spanMacro.span);
+    }
+
+    if (spanMacro.span.expansion) {
+        return mapMacroSpanToLocation(spanMacro.span.expansion);
+    }
+
+    return;
+}
+
+/**
  * Converts a Rust span to a VsCode location
  */
 function mapSpanToLocation(span: RustDiagnosticSpan): vscode.Location {
+    if (isFromMacro(span.file_name) && span.expansion) {
+        const macroLoc = mapMacroSpanToLocation(span.expansion);
+        if (macroLoc) {
+            return macroLoc;
+        }
+    }
+
     const fileName = path.join(vscode.workspace.rootPath || '', span.file_name);
     const fileUri = vscode.Uri.file(fileName);
 
     const range = new vscode.Range(
         new vscode.Position(span.line_start - 1, span.column_start - 1),
-        new vscode.Position(span.line_end - 1, span.column_end - 1)
+        new vscode.Position(span.line_end - 1, span.column_end - 1),
     );
 
     return new vscode.Location(fileUri, range);
@@ -81,7 +119,7 @@ function mapSpanToLocation(span: RustDiagnosticSpan): vscode.Location {
  * If the span is unlabelled this will return `undefined`.
  */
 function mapSecondarySpanToRelated(
-    span: RustDiagnosticSpan
+    span: RustDiagnosticSpan,
 ): vscode.DiagnosticRelatedInformation | undefined {
     if (!span.label) {
         // Nothing to label this with
@@ -107,7 +145,7 @@ function isUnusedOrUnnecessary(rd: RustDiagnostic): boolean {
         'unused_attributes',
         'unused_imports',
         'unused_macros',
-        'unused_variables'
+        'unused_variables',
     ].includes(rd.code.code);
 }
 
@@ -157,13 +195,13 @@ function mapRustChildDiagnostic(rd: RustDiagnostic): MappedRustChildDiagnostic {
                 title,
                 location,
                 span.suggested_replacement,
-                span.suggestion_applicability
-            )
+                span.suggestion_applicability,
+            ),
         };
     } else {
         const related = new vscode.DiagnosticRelatedInformation(
             location,
-            rd.message
+            rd.message,
         );
 
         return { related };
@@ -183,7 +221,7 @@ function mapRustChildDiagnostic(rd: RustDiagnostic): MappedRustChildDiagnostic {
  * If the diagnostic has no primary span this will return `undefined`
  */
 export function mapRustDiagnosticToVsCode(
-    rd: RustDiagnostic
+    rd: RustDiagnostic,
 ): MappedRustDiagnostic | undefined {
     const primarySpan = rd.spans.find(s => s.is_primary);
     if (!primarySpan) {
@@ -223,7 +261,7 @@ export function mapRustDiagnosticToVsCode(
     const suggestedFixes = [];
     for (const child of rd.children) {
         const { related, suggestedFix, messageLine } = mapRustChildDiagnostic(
-            child
+            child,
         );
 
         if (related) {
@@ -256,6 +294,6 @@ export function mapRustDiagnosticToVsCode(
     return {
         location,
         diagnostic: vd,
-        suggestedFixes
+        suggestedFixes,
     };
 }
diff --git a/editors/code/src/utils/diagnostics/vscode.ts b/editors/code/src/utils/diagnostics/vscode.ts
index d8b85b7200b..f4a5450e2b8 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';
 /** Compares two `vscode.Diagnostic`s for equality */
 export function areDiagnosticsEqual(
     left: vscode.Diagnostic,
-    right: vscode.Diagnostic
+    right: vscode.Diagnostic,
 ): boolean {
     return (
         left.source === right.source &&
diff --git a/editors/code/src/utils/processes.ts b/editors/code/src/utils/processes.ts
index da8be9eb179..a1d6b7eafbc 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 {
             // Ignore stderr since this is otherwise piped to parent.stderr
             // which might be already closed.
             const options: any = {
-                stdio: ['pipe', 'pipe', 'ignore']
+                stdio: ['pipe', 'pipe', 'ignore'],
             };
             if (cwd) {
                 options.cwd = cwd;
@@ -30,7 +30,7 @@ export function terminate(process: ChildProcess, cwd?: string): boolean {
             cp.execFileSync(
                 'taskkill',
                 ['/T', '/F', '/PID', process.pid.toString()],
-                options
+                options,
             );
             return true;
         } catch (err) {