aboutsummaryrefslogtreecommitdiff
path: root/editors/code/src
diff options
context:
space:
mode:
Diffstat (limited to 'editors/code/src')
-rw-r--r--editors/code/src/client.ts11
-rw-r--r--editors/code/src/commands.ts8
-rw-r--r--editors/code/src/config.ts3
-rw-r--r--editors/code/src/ctx.ts2
-rw-r--r--editors/code/src/main.ts50
5 files changed, 56 insertions, 18 deletions
diff --git a/editors/code/src/client.ts b/editors/code/src/client.ts
index 63ab82dde..539e487ec 100644
--- a/editors/code/src/client.ts
+++ b/editors/code/src/client.ts
@@ -6,6 +6,10 @@ import { DocumentSemanticsTokensSignature, DocumentSemanticsTokensEditsSignature
6import { assert } from './util'; 6import { assert } from './util';
7import { WorkspaceEdit } from 'vscode'; 7import { WorkspaceEdit } from 'vscode';
8 8
9export interface Env {
10 [name: string]: string;
11}
12
9function renderCommand(cmd: ra.CommandLink) { 13function renderCommand(cmd: ra.CommandLink) {
10 return `[${cmd.title}](command:${cmd.command}?${encodeURIComponent(JSON.stringify(cmd.arguments))} '${cmd.tooltip!}')`; 14 return `[${cmd.title}](command:${cmd.command}?${encodeURIComponent(JSON.stringify(cmd.arguments))} '${cmd.tooltip!}')`;
11} 15}
@@ -27,14 +31,17 @@ async function semanticHighlightingWorkaround<R, F extends (...args: any[]) => v
27 return res; 31 return res;
28} 32}
29 33
30export function createClient(serverPath: string, cwd: string): lc.LanguageClient { 34export function createClient(serverPath: string, cwd: string, extraEnv: Env): lc.LanguageClient {
31 // '.' Is the fallback if no folder is open 35 // '.' Is the fallback if no folder is open
32 // TODO?: Workspace folders support Uri's (eg: file://test.txt). 36 // TODO?: Workspace folders support Uri's (eg: file://test.txt).
33 // It might be a good idea to test if the uri points to a file. 37 // It might be a good idea to test if the uri points to a file.
34 38
39 const newEnv = Object.assign({}, process.env);
40 Object.assign(newEnv, extraEnv);
41
35 const run: lc.Executable = { 42 const run: lc.Executable = {
36 command: serverPath, 43 command: serverPath,
37 options: { cwd }, 44 options: { cwd, env: newEnv },
38 }; 45 };
39 const serverOptions: lc.ServerOptions = { 46 const serverOptions: lc.ServerOptions = {
40 run, 47 run,
diff --git a/editors/code/src/commands.ts b/editors/code/src/commands.ts
index 92bc4d7f7..b12e134ca 100644
--- a/editors/code/src/commands.ts
+++ b/editors/code/src/commands.ts
@@ -469,8 +469,14 @@ export function resolveCodeAction(ctx: Ctx): Cmd {
469 if (!item.edit) { 469 if (!item.edit) {
470 return; 470 return;
471 } 471 }
472 const edit = client.protocol2CodeConverter.asWorkspaceEdit(item.edit); 472 const itemEdit = item.edit;
473 const edit = client.protocol2CodeConverter.asWorkspaceEdit(itemEdit);
474 // filter out all text edits and recreate the WorkspaceEdit without them so we can apply
475 // snippet edits on our own
476 const itemEditWithoutTextEdits = { ...item, documentChanges: itemEdit.documentChanges?.filter(change => "kind" in change) };
477 const editWithoutTextEdits = client.protocol2CodeConverter.asWorkspaceEdit(itemEditWithoutTextEdits);
473 await applySnippetWorkspaceEdit(edit); 478 await applySnippetWorkspaceEdit(edit);
479 await vscode.workspace.applyEdit(editWithoutTextEdits);
474 }; 480 };
475} 481}
476 482
diff --git a/editors/code/src/config.ts b/editors/code/src/config.ts
index 848e92af9..fe9f3b4a8 100644
--- a/editors/code/src/config.ts
+++ b/editors/code/src/config.ts
@@ -1,4 +1,5 @@
1import * as vscode from 'vscode'; 1import * as vscode from 'vscode';
2import { Env } from './client';
2import { log } from "./util"; 3import { log } from "./util";
3 4
4export type UpdatesChannel = "stable" | "nightly"; 5export type UpdatesChannel = "stable" | "nightly";
@@ -13,6 +14,7 @@ export class Config {
13 readonly rootSection = "rust-analyzer"; 14 readonly rootSection = "rust-analyzer";
14 private readonly requiresReloadOpts = [ 15 private readonly requiresReloadOpts = [
15 "serverPath", 16 "serverPath",
17 "server",
16 "cargo", 18 "cargo",
17 "procMacro", 19 "procMacro",
18 "files", 20 "files",
@@ -92,6 +94,7 @@ export class Config {
92 } 94 }
93 95
94 get serverPath() { return this.get<null | string>("serverPath"); } 96 get serverPath() { return this.get<null | string>("serverPath"); }
97 get serverExtraEnv() { return this.get<Env | null>("server.extraEnv") ?? {}; }
95 get channel() { return this.get<UpdatesChannel>("updates.channel"); } 98 get channel() { return this.get<UpdatesChannel>("updates.channel"); }
96 get askBeforeDownload() { return this.get<boolean>("updates.askBeforeDownload"); } 99 get askBeforeDownload() { return this.get<boolean>("updates.askBeforeDownload"); }
97 get traceExtension() { return this.get<boolean>("trace.extension"); } 100 get traceExtension() { return this.get<boolean>("trace.extension"); }
diff --git a/editors/code/src/ctx.ts b/editors/code/src/ctx.ts
index d39864d33..e7585184b 100644
--- a/editors/code/src/ctx.ts
+++ b/editors/code/src/ctx.ts
@@ -24,7 +24,7 @@ export class Ctx {
24 serverPath: string, 24 serverPath: string,
25 cwd: string, 25 cwd: string,
26 ): Promise<Ctx> { 26 ): Promise<Ctx> {
27 const client = createClient(serverPath, cwd); 27 const client = createClient(serverPath, cwd, config.serverExtraEnv);
28 28
29 const statusBar = vscode.window.createStatusBarItem(vscode.StatusBarAlignment.Left); 29 const statusBar = vscode.window.createStatusBarItem(vscode.StatusBarAlignment.Left);
30 extCtx.subscriptions.push(statusBar); 30 extCtx.subscriptions.push(statusBar);
diff --git a/editors/code/src/main.ts b/editors/code/src/main.ts
index 191960960..282240d84 100644
--- a/editors/code/src/main.ts
+++ b/editors/code/src/main.ts
@@ -19,9 +19,8 @@ let ctx: Ctx | undefined;
19const RUST_PROJECT_CONTEXT_NAME = "inRustProject"; 19const RUST_PROJECT_CONTEXT_NAME = "inRustProject";
20 20
21export async function activate(context: vscode.ExtensionContext) { 21export async function activate(context: vscode.ExtensionContext) {
22 // For some reason vscode not always shows pop-up error notifications 22 // VS Code doesn't show a notification when an extension fails to activate
23 // when an extension fails to activate, so we do it explicitly by ourselves. 23 // so we do it ourselves.
24 // FIXME: remove this bit of code once vscode fixes this issue: https://github.com/microsoft/vscode/issues/101242
25 await tryActivate(context).catch(err => { 24 await tryActivate(context).catch(err => {
26 void vscode.window.showErrorMessage(`Cannot activate rust-analyzer: ${err.message}`); 25 void vscode.window.showErrorMessage(`Cannot activate rust-analyzer: ${err.message}`);
27 throw err; 26 throw err;
@@ -132,7 +131,7 @@ async function tryActivate(context: vscode.ExtensionContext) {
132 ctx.pushCleanup(activateTaskProvider(workspaceFolder, ctx.config)); 131 ctx.pushCleanup(activateTaskProvider(workspaceFolder, ctx.config));
133 132
134 activateInlayHints(ctx); 133 activateInlayHints(ctx);
135 warnAboutRustLangExtensionConflict(); 134 warnAboutExtensionConflicts();
136 135
137 vscode.workspace.onDidChangeConfiguration( 136 vscode.workspace.onDidChangeConfiguration(
138 _ => ctx?.client?.sendNotification('workspace/didChangeConfiguration', { settings: "" }), 137 _ => ctx?.client?.sendNotification('workspace/didChangeConfiguration', { settings: "" }),
@@ -288,10 +287,14 @@ async function getServer(config: Config, state: PersistentState): Promise<string
288 if (config.package.releaseTag === null) return "rust-analyzer"; 287 if (config.package.releaseTag === null) return "rust-analyzer";
289 288
290 let platform: string | undefined; 289 let platform: string | undefined;
291 if (process.arch === "x64" || process.arch === "ia32") { 290 if ((process.arch === "x64" || process.arch === "ia32") && process.platform === "win32") {
292 if (process.platform === "linux") platform = "linux"; 291 platform = "x86_64-pc-windows-msvc";
293 if (process.platform === "darwin") platform = "mac"; 292 } else if (process.arch === "x64" && process.platform === "linux") {
294 if (process.platform === "win32") platform = "windows"; 293 platform = "x86_64-unknown-linux-gnu";
294 } else if (process.arch === "x64" && process.platform === "darwin") {
295 platform = "x86_64-apple-darwin";
296 } else if (process.arch === "arm64" && process.platform === "darwin") {
297 platform = "aarch64-apple-darwin";
295 } 298 }
296 if (platform === undefined) { 299 if (platform === undefined) {
297 vscode.window.showErrorMessage( 300 vscode.window.showErrorMessage(
@@ -304,7 +307,7 @@ async function getServer(config: Config, state: PersistentState): Promise<string
304 ); 307 );
305 return undefined; 308 return undefined;
306 } 309 }
307 const ext = platform === "windows" ? ".exe" : ""; 310 const ext = platform.indexOf("-windows-") !== -1 ? ".exe" : "";
308 const dest = path.join(config.globalStoragePath, `rust-analyzer-${platform}${ext}`); 311 const dest = path.join(config.globalStoragePath, `rust-analyzer-${platform}${ext}`);
309 const exists = await fs.stat(dest).then(() => true, () => false); 312 const exists = await fs.stat(dest).then(() => true, () => false);
310 if (!exists) { 313 if (!exists) {
@@ -340,7 +343,7 @@ async function getServer(config: Config, state: PersistentState): Promise<string
340 }); 343 });
341 344
342 // Patching executable if that's NixOS. 345 // Patching executable if that's NixOS.
343 if (await fs.stat("/etc/nixos").then(_ => true).catch(_ => false)) { 346 if (await isNixOs()) {
344 await patchelf(dest); 347 await patchelf(dest);
345 } 348 }
346 349
@@ -348,6 +351,15 @@ async function getServer(config: Config, state: PersistentState): Promise<string
348 return dest; 351 return dest;
349} 352}
350 353
354async function isNixOs(): Promise<boolean> {
355 try {
356 const contents = await fs.readFile("/etc/os-release");
357 return contents.indexOf("ID=nixos") !== -1;
358 } catch (e) {
359 return false;
360 }
361}
362
351async function downloadWithRetryDialog<T>(state: PersistentState, downloadFunc: () => Promise<T>): Promise<T> { 363async function downloadWithRetryDialog<T>(state: PersistentState, downloadFunc: () => Promise<T>): Promise<T> {
352 while (true) { 364 while (true) {
353 try { 365 try {
@@ -401,11 +413,21 @@ async function queryForGithubToken(state: PersistentState): Promise<void> {
401 } 413 }
402} 414}
403 415
404function warnAboutRustLangExtensionConflict() { 416function warnAboutExtensionConflicts() {
405 const rustLangExt = vscode.extensions.getExtension("rust-lang.rust"); 417 const conflicting = [
406 if (rustLangExt !== undefined) { 418 ["rust-analyzer", "matklad.rust-analyzer"],
419 ["Rust", "rust-lang.rust"],
420 ["Rust", "kalitaalexey.vscode-rust"],
421 ];
422
423 const found = conflicting.filter(
424 nameId => vscode.extensions.getExtension(nameId[1]) !== undefined);
425
426 if (found.length > 1) {
427 const fst = found[0];
428 const sec = found[1];
407 vscode.window.showWarningMessage( 429 vscode.window.showWarningMessage(
408 "You have both rust-analyzer (matklad.rust-analyzer) and Rust (rust-lang.rust) " + 430 `You have both the ${fst[0]} (${fst[1]}) and ${sec[0]} (${sec[1]}) ` +
409 "plugins enabled. These are known to conflict and cause various functions of " + 431 "plugins enabled. These are known to conflict and cause various functions of " +
410 "both plugins to not work correctly. You should disable one of them.", "Got it"); 432 "both plugins to not work correctly. You should disable one of them.", "Got it");
411 }; 433 };