mirror of
https://github.com/rust-lang/rust.git
synced 2026-04-28 03:07:24 +03:00
Merge pull request #21359 from Veykril/push-syvnrvtmlsqk
Prompt the user in VSCode to add the rust-anaylzer componenet to the toolchain file
This commit is contained in:
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user