Unnamed repository; edit this file 'description' to name the repository.
-rw-r--r--editors/code/src/bootstrap.ts11
-rw-r--r--editors/code/src/ctx.ts54
-rw-r--r--editors/code/src/util.ts25
3 files changed, 86 insertions, 4 deletions
diff --git a/editors/code/src/bootstrap.ts b/editors/code/src/bootstrap.ts
index bddf195803..ca5b7e3ec7 100644
--- a/editors/code/src/bootstrap.ts
+++ b/editors/code/src/bootstrap.ts
@@ -1,7 +1,7 @@
import * as vscode from "vscode";
import * as os from "os";
import type { Config } from "./config";
-import { type Env, log, spawnAsync } from "./util";
+import { type Env, log, RUST_TOOLCHAIN_FILES, spawnAsync } from "./util";
import type { PersistentState } from "./persistent_state";
import { exec } from "child_process";
import { TextDecoder } from "node:util";
@@ -59,8 +59,12 @@ async function getServer(
// otherwise check if there is a toolchain override for the current vscode workspace
// and if the toolchain of this override has a rust-analyzer component
// if so, use the rust-analyzer component
- const toolchainUri = vscode.Uri.joinPath(workspaceFolder.uri, "rust-toolchain.toml");
- if (await hasToolchainFileWithRaDeclared(toolchainUri)) {
+ // Check both rust-toolchain.toml and rust-toolchain files
+ for (const toolchainFile of RUST_TOOLCHAIN_FILES) {
+ const toolchainUri = vscode.Uri.joinPath(workspaceFolder.uri, toolchainFile);
+ if (!(await hasToolchainFileWithRaDeclared(toolchainUri))) {
+ continue;
+ }
const res = await spawnAsync("rustup", ["which", "rust-analyzer"], {
env: { ...process.env },
cwd: workspaceFolder.uri.fsPath,
@@ -71,6 +75,7 @@ async function getServer(
res.stdout.trim(),
raVersionResolver,
);
+ break;
}
}
}
diff --git a/editors/code/src/ctx.ts b/editors/code/src/ctx.ts
index a7b7be03b5..e07fbb8bea 100644
--- a/editors/code/src/ctx.ts
+++ b/editors/code/src/ctx.ts
@@ -1,10 +1,11 @@
import * as vscode from "vscode";
-import type * as lc from "vscode-languageclient/node";
+import * as lc from "vscode-languageclient/node";
import * as ra from "./lsp_ext";
import { Config, prepareVSCodeConfig } from "./config";
import { createClient } from "./client";
import {
+ findRustToolchainFiles,
isCargoTomlEditor,
isDocumentInWorkspace,
isRustDocument,
@@ -266,6 +267,17 @@ export class Ctx implements RustAnalyzerExtensionApi {
this.outputChannel!.show();
}),
);
+ this.pushClientCleanup(
+ this._client.onNotification(
+ lc.ShowMessageNotification.type,
+ async (params: lc.ShowMessageParams) => {
+ // When an MSRV warning is detected and a rust-toolchain file exists,
+ // show an additional message with actionable guidance about adding
+ // the rust-analyzer component.
+ await handleMsrvWarning(params.message);
+ },
+ ),
+ );
}
return this._client;
}
@@ -592,3 +604,43 @@ export interface Disposable {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
export type Cmd = (...args: any[]) => unknown;
+
+/**
+ * Pattern to detect MSRV warning messages from the rust-analyzer server.
+ */
+const MSRV_WARNING_PATTERN = /using an outdated toolchain version.*rust-analyzer only supports/is;
+
+/**
+ * Handles the MSRV warning by checking for rust-toolchain files and showing
+ * an enhanced message if found.
+ */
+export async function handleMsrvWarning(message: string): Promise<boolean> {
+ if (!MSRV_WARNING_PATTERN.test(message)) {
+ return false;
+ }
+
+ const toolchainFiles = await findRustToolchainFiles();
+ if (toolchainFiles.length === 0) {
+ return false;
+ }
+
+ const openFile = "Open rust-toolchain file";
+ const result = await vscode.window.showWarningMessage(
+ "Your workspace uses a rust-toolchain file with a toolchain too old for the extension shipped rust-analyzer to work properly. " +
+ "Consider adding the rust-analyzer component to the toolchain file to use a compatible rust-analyzer version. " +
+ "Add the following to your rust-toolchain file's `[toolchain]` section:\n" +
+ 'components = ["rust-analyzer"]',
+ { modal: true },
+ openFile,
+ );
+
+ if (result === openFile) {
+ const fileToOpen = toolchainFiles[0];
+ if (fileToOpen) {
+ const document = await vscode.workspace.openTextDocument(fileToOpen);
+ await vscode.window.showTextDocument(document);
+ }
+ }
+
+ return true;
+}
diff --git a/editors/code/src/util.ts b/editors/code/src/util.ts
index 410b055100..05b475080c 100644
--- a/editors/code/src/util.ts
+++ b/editors/code/src/util.ts
@@ -328,3 +328,28 @@ export function normalizeDriveLetter(path: string, isWindowsOS: boolean = isWind
return path;
}
+
+export const RUST_TOOLCHAIN_FILES = ["rust-toolchain.toml", "rust-toolchain"] as const;
+
+export async function findRustToolchainFiles(): Promise<vscode.Uri[]> {
+ const found: vscode.Uri[] = [];
+ const workspaceFolders = vscode.workspace.workspaceFolders;
+ if (!workspaceFolders) {
+ return found;
+ }
+
+ for (const folder of workspaceFolders) {
+ for (const filename of RUST_TOOLCHAIN_FILES) {
+ const toolchainUri = vscode.Uri.joinPath(folder.uri, filename);
+ try {
+ await vscode.workspace.fs.stat(toolchainUri);
+ found.push(toolchainUri);
+ // Only add the first toolchain file found per workspace folder
+ break;
+ } catch {
+ // File doesn't exist, continue
+ }
+ }
+ }
+ return found;
+}