Unnamed repository; edit this file 'description' to name the repository.
Merge pull request #21359 from Veykril/push-syvnrvtmlsqk
Prompt the user in VSCode to add the rust-anaylzer componenet to the toolchain file
| -rw-r--r-- | editors/code/src/bootstrap.ts | 11 | ||||
| -rw-r--r-- | editors/code/src/ctx.ts | 54 | ||||
| -rw-r--r-- | editors/code/src/util.ts | 25 |
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; +} |