mirror of
https://github.com/rust-lang/rust-analyzer.git
synced 2025-08-04 18:58:41 +00:00
Update Node.js, vscode, and ts deps
This commit is contained in:
parent
2fa819c9d3
commit
00726cf697
29 changed files with 2715 additions and 1857 deletions
|
@ -1,2 +0,0 @@
|
|||
node_modules
|
||||
.eslintrc.js
|
|
@ -1,46 +0,0 @@
|
|||
module.exports = {
|
||||
env: {
|
||||
es6: true,
|
||||
node: true,
|
||||
},
|
||||
extends: ["prettier"],
|
||||
parser: "@typescript-eslint/parser",
|
||||
parserOptions: {
|
||||
project: true,
|
||||
tsconfigRootDir: __dirname,
|
||||
sourceType: "module",
|
||||
},
|
||||
plugins: ["@typescript-eslint"],
|
||||
rules: {
|
||||
camelcase: ["error"],
|
||||
eqeqeq: ["error", "always", { null: "ignore" }],
|
||||
curly: ["error", "multi-line"],
|
||||
"no-console": ["error", { allow: ["warn", "error"] }],
|
||||
"prefer-const": "error",
|
||||
"@typescript-eslint/member-delimiter-style": [
|
||||
"error",
|
||||
{
|
||||
multiline: {
|
||||
delimiter: "semi",
|
||||
requireLast: true,
|
||||
},
|
||||
singleline: {
|
||||
delimiter: "semi",
|
||||
requireLast: false,
|
||||
},
|
||||
},
|
||||
],
|
||||
"@typescript-eslint/semi": ["error", "always"],
|
||||
"@typescript-eslint/no-unnecessary-type-assertion": "error",
|
||||
"@typescript-eslint/no-floating-promises": "error",
|
||||
|
||||
"@typescript-eslint/consistent-type-imports": [
|
||||
"error",
|
||||
{
|
||||
prefer: "type-imports",
|
||||
fixStyle: "inline-type-imports",
|
||||
},
|
||||
],
|
||||
"@typescript-eslint/no-import-type-side-effects": "error",
|
||||
},
|
||||
};
|
|
@ -1,5 +0,0 @@
|
|||
module.exports = {
|
||||
// use 100 because it's Rustfmt's default
|
||||
// https://rust-lang.github.io/rustfmt/?version=v1.4.38&search=#max_width
|
||||
printWidth: 100,
|
||||
};
|
48
editors/code/eslint.config.mts
Normal file
48
editors/code/eslint.config.mts
Normal file
|
@ -0,0 +1,48 @@
|
|||
import eslintConfigPrettier from "eslint-config-prettier";
|
||||
import stylistic from "@stylistic/eslint-plugin";
|
||||
import eslint from "@eslint/js";
|
||||
import tseslint from "typescript-eslint";
|
||||
import stylisticJs from "@stylistic/eslint-plugin-js";
|
||||
import { type FlatESLintConfig } from "eslint-define-config";
|
||||
|
||||
const config: FlatESLintConfig[] = [
|
||||
eslintConfigPrettier,
|
||||
eslint.configs.recommended,
|
||||
stylisticJs.configs["disable-legacy"],
|
||||
...tseslint.configs.recommended,
|
||||
stylistic.configs.customize({
|
||||
indent: 4,
|
||||
quotes: "double",
|
||||
semi: true,
|
||||
braceStyle: "1tbs",
|
||||
arrowParens: true,
|
||||
}),
|
||||
{
|
||||
rules: {
|
||||
"no-console": "warn",
|
||||
"@typescript-eslint/no-unused-vars": [
|
||||
"error",
|
||||
{
|
||||
args: "all",
|
||||
argsIgnorePattern: "^_",
|
||||
caughtErrors: "all",
|
||||
caughtErrorsIgnorePattern: "^_",
|
||||
destructuredArrayIgnorePattern: "^_",
|
||||
varsIgnorePattern: "^_",
|
||||
ignoreRestSiblings: true,
|
||||
},
|
||||
],
|
||||
// the following stylistic lints conflict with prettier
|
||||
"@stylistic/operator-linebreak": "off",
|
||||
"@stylistic/indent-binary-ops": "off",
|
||||
"@stylistic/indent": "off",
|
||||
"@stylistic/brace-style": "off",
|
||||
"@stylistic/quotes": "off",
|
||||
},
|
||||
},
|
||||
{
|
||||
ignores: ["out/", ".vscode-test/", "node_modules/"],
|
||||
},
|
||||
];
|
||||
|
||||
export default config;
|
3670
editors/code/package-lock.json
generated
3670
editors/code/package-lock.json
generated
File diff suppressed because it is too large
Load diff
|
@ -7,6 +7,7 @@
|
|||
"version": "0.5.0-dev",
|
||||
"releaseTag": null,
|
||||
"publisher": "rust-lang",
|
||||
"type": "commonjs",
|
||||
"repository": {
|
||||
"url": "https://github.com/rust-lang/rust-analyzer.git",
|
||||
"type": "git"
|
||||
|
@ -27,45 +28,51 @@
|
|||
}
|
||||
},
|
||||
"engines": {
|
||||
"vscode": "^1.83.0"
|
||||
"vscode": "^1.93.0"
|
||||
},
|
||||
"enabledApiProposals": [],
|
||||
"scripts": {
|
||||
"vscode:prepublish": "npm run build-base -- --minify",
|
||||
"package": "vsce package -o rust-analyzer.vsix",
|
||||
"build-base": "esbuild ./src/main.ts --bundle --outfile=out/main.js --external:vscode --format=cjs --platform=node --target=node16",
|
||||
"build-base": "esbuild ./src/main.ts --bundle --outfile=out/main.js --external:vscode --format=cjs --platform=node --target=node20",
|
||||
"build": "npm run build-base -- --sourcemap",
|
||||
"watch": "npm run build-base -- --sourcemap --watch",
|
||||
"format": "prettier --write .",
|
||||
"format:check": "prettier --check .",
|
||||
"lint": "eslint -c .eslintrc.js --ext ts ./src ./tests",
|
||||
"format": "node --experimental-strip-types node_modules/prettier/bin/prettier.cjs . --write",
|
||||
"format:check": "node --experimental-strip-types node_modules/prettier/bin/prettier.cjs . --check",
|
||||
"lint": "eslint .",
|
||||
"lint:fix": "npm run lint -- --fix",
|
||||
"typecheck": "tsc",
|
||||
"pretest": "npm run typecheck && npm run build",
|
||||
"test": "node ./out/tests/runTests.js"
|
||||
},
|
||||
"dependencies": {
|
||||
"@hpcc-js/wasm": "^2.13.0",
|
||||
"anser": "^2.1.1",
|
||||
"d3": "^7.8.5",
|
||||
"d3-graphviz": "^5.0.2",
|
||||
"@hpcc-js/wasm": "^2.22.4",
|
||||
"anser": "^2.3.2",
|
||||
"d3": "^7.9.0",
|
||||
"d3-graphviz": "^5.6.0",
|
||||
"jiti": "^2.4.2",
|
||||
"vscode-languageclient": "^9.0.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@tsconfig/strictest": "^2.0.1",
|
||||
"@types/node": "~16.11.7",
|
||||
"@types/vscode": "~1.83",
|
||||
"@typescript-eslint/eslint-plugin": "^6.0.0",
|
||||
"@typescript-eslint/parser": "^6.0.0",
|
||||
"@vscode/test-electron": "^2.3.8",
|
||||
"@vscode/vsce": "^3.0.0",
|
||||
"@eslint/js": "^9.21.0",
|
||||
"@stylistic/eslint-plugin": "^4.1.0",
|
||||
"@stylistic/eslint-plugin-js": "^4.1.0",
|
||||
"@tsconfig/strictest": "^2.0.5",
|
||||
"@types/node": "~22.13.4",
|
||||
"@types/vscode": "~1.93.0",
|
||||
"@typescript-eslint/eslint-plugin": "^8.25.0",
|
||||
"@typescript-eslint/parser": "^8.25.0",
|
||||
"@vscode/test-electron": "^2.4.1",
|
||||
"@vscode/vsce": "^3.2.2",
|
||||
"esbuild": "^0.25.0",
|
||||
"eslint": "^8.44.0",
|
||||
"eslint-config-prettier": "^8.8.0",
|
||||
"ovsx": "^0.8.2",
|
||||
"prettier": "^3.0.0",
|
||||
"tslib": "^2.6.0",
|
||||
"typescript": "^5.6.0"
|
||||
"eslint": "^9.21.0",
|
||||
"eslint-config-prettier": "^10.0.2",
|
||||
"eslint-define-config": "^2.1.0",
|
||||
"ovsx": "0.10.1",
|
||||
"prettier": "^3.5.2",
|
||||
"tslib": "^2.8.1",
|
||||
"typescript": "^5.7.3",
|
||||
"typescript-eslint": "^8.25.0"
|
||||
},
|
||||
"activationEvents": [
|
||||
"workspaceContains:Cargo.toml",
|
||||
|
|
12
editors/code/prettier.config.mts
Normal file
12
editors/code/prettier.config.mts
Normal file
|
@ -0,0 +1,12 @@
|
|||
import { type Config } from "prettier";
|
||||
|
||||
const config: Config = {
|
||||
// use 4 because it's Rustfmt's default
|
||||
// https://rust-lang.github.io/rustfmt/?version=v1.4.38&search=#%5C34%20%5C%20%5C(default%5C)%5C%3A
|
||||
tabWidth: 4,
|
||||
// use 100 because it's Rustfmt's default
|
||||
// https://rust-lang.github.io/rustfmt/?version=v1.4.38&search=#max_width
|
||||
printWidth: 100,
|
||||
};
|
||||
|
||||
export default config;
|
|
@ -177,9 +177,9 @@ async function hasToolchainFileWithRaDeclared(uri: vscode.Uri): Promise<boolean>
|
|||
await vscode.workspace.fs.readFile(uri),
|
||||
);
|
||||
return (
|
||||
toolchainFileContents.match(/components\s*=\s*\[.*\"rust-analyzer\".*\]/g)?.length === 1
|
||||
toolchainFileContents.match(/components\s*=\s*\[.*"rust-analyzer".*\]/g)?.length === 1
|
||||
);
|
||||
} catch (e) {
|
||||
} catch (_) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -18,282 +18,263 @@ export async function createClient(
|
|||
config: Config,
|
||||
unlinkedFiles: vscode.Uri[],
|
||||
): Promise<lc.LanguageClient> {
|
||||
const raMiddleware: lc.Middleware = {
|
||||
workspace: {
|
||||
// HACK: This is a workaround, when the client has been disposed, VSCode
|
||||
// continues to emit events to the client and the default one for this event
|
||||
// attempt to restart the client for no reason
|
||||
async didChangeWatchedFile(event, next) {
|
||||
if (client.isRunning()) {
|
||||
await next(event);
|
||||
}
|
||||
},
|
||||
async configuration(
|
||||
params: lc.ConfigurationParams,
|
||||
token: vscode.CancellationToken,
|
||||
next: lc.ConfigurationRequest.HandlerSignature,
|
||||
) {
|
||||
const resp = await next(params, token);
|
||||
if (resp && Array.isArray(resp)) {
|
||||
return resp.map((val) => {
|
||||
return prepareVSCodeConfig(val);
|
||||
});
|
||||
} else {
|
||||
return resp;
|
||||
}
|
||||
},
|
||||
},
|
||||
async handleDiagnostics(
|
||||
uri: vscode.Uri,
|
||||
diagnosticList: vscode.Diagnostic[],
|
||||
next: lc.HandleDiagnosticsSignature,
|
||||
) {
|
||||
const preview = config.previewRustcOutput;
|
||||
const errorCode = config.useRustcErrorCode;
|
||||
diagnosticList.forEach((diag, idx) => {
|
||||
const value =
|
||||
typeof diag.code === "string" || typeof diag.code === "number"
|
||||
? diag.code
|
||||
: diag.code?.value;
|
||||
if (
|
||||
// FIXME: We currently emit this diagnostic way too early, before we have
|
||||
// loaded the project fully
|
||||
// value === "unlinked-file" &&
|
||||
value === "temporary-disabled" &&
|
||||
!unlinkedFiles.includes(uri) &&
|
||||
(diag.message === "file not included in crate hierarchy" ||
|
||||
diag.message.startsWith("This file is not included in any crates"))
|
||||
) {
|
||||
const config = vscode.workspace.getConfiguration("rust-analyzer");
|
||||
if (config.get("showUnlinkedFileNotification")) {
|
||||
unlinkedFiles.push(uri);
|
||||
const folder = vscode.workspace.getWorkspaceFolder(uri)?.uri.fsPath;
|
||||
if (folder) {
|
||||
const parentBackslash = uri.fsPath.lastIndexOf(pathSeparator + "src");
|
||||
const parent = uri.fsPath.substring(0, parentBackslash);
|
||||
|
||||
if (parent.startsWith(folder)) {
|
||||
const path = vscode.Uri.file(parent + pathSeparator + "Cargo.toml");
|
||||
void vscode.workspace.fs.stat(path).then(async () => {
|
||||
const choice = await vscode.window.showInformationMessage(
|
||||
`This rust file does not belong to a loaded cargo project. It looks like it might belong to the workspace at ${path.path}, do you want to add it to the linked Projects?`,
|
||||
"Yes",
|
||||
"No",
|
||||
"Don't show this again",
|
||||
);
|
||||
switch (choice) {
|
||||
case undefined:
|
||||
break;
|
||||
case "No":
|
||||
break;
|
||||
case "Yes": {
|
||||
const pathToInsert =
|
||||
"." +
|
||||
parent.substring(folder.length) +
|
||||
pathSeparator +
|
||||
"Cargo.toml";
|
||||
const value = config
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
.get<any[]>("linkedProjects")
|
||||
?.concat(pathToInsert);
|
||||
await config.update("linkedProjects", value, false);
|
||||
break;
|
||||
}
|
||||
case "Don't show this again":
|
||||
await config.update(
|
||||
"showUnlinkedFileNotification",
|
||||
false,
|
||||
false,
|
||||
);
|
||||
break;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Abuse the fact that VSCode leaks the LSP diagnostics data field through the
|
||||
// Diagnostic class, if they ever break this we are out of luck and have to go
|
||||
// back to the worst diagnostics experience ever:)
|
||||
|
||||
// We encode the rendered output of a rustc diagnostic in the rendered field of
|
||||
// the data payload of the lsp diagnostic. If that field exists, overwrite the
|
||||
// diagnostic code such that clicking it opens the diagnostic in a readonly
|
||||
// text editor for easy inspection
|
||||
const rendered = (diag as unknown as { data?: { rendered?: string } }).data
|
||||
?.rendered;
|
||||
if (rendered) {
|
||||
if (preview) {
|
||||
const decolorized = anser.ansiToText(rendered);
|
||||
const index = decolorized.match(/^(note|help):/m)?.index || rendered.length;
|
||||
diag.message = decolorized
|
||||
.substring(0, index)
|
||||
.replace(/^ -->[^\n]+\n/m, "");
|
||||
}
|
||||
diag.code = {
|
||||
target: vscode.Uri.from({
|
||||
scheme: diagnostics.URI_SCHEME,
|
||||
path: `/diagnostic message [${idx.toString()}]`,
|
||||
fragment: uri.toString(),
|
||||
query: idx.toString(),
|
||||
}),
|
||||
value: errorCode && value ? value : "Click for full compiler diagnostic",
|
||||
};
|
||||
}
|
||||
});
|
||||
return next(uri, diagnosticList);
|
||||
},
|
||||
async provideHover(
|
||||
document: vscode.TextDocument,
|
||||
position: vscode.Position,
|
||||
token: vscode.CancellationToken,
|
||||
_next: lc.ProvideHoverSignature,
|
||||
) {
|
||||
const editor = vscode.window.activeTextEditor;
|
||||
const positionOrRange = editor?.selection?.contains(position)
|
||||
? client.code2ProtocolConverter.asRange(editor.selection)
|
||||
: client.code2ProtocolConverter.asPosition(position);
|
||||
const params = {
|
||||
textDocument: client.code2ProtocolConverter.asTextDocumentIdentifier(document),
|
||||
position: positionOrRange,
|
||||
};
|
||||
return client.sendRequest(ra.hover, params, token).then(
|
||||
(result) => {
|
||||
if (!result) return null;
|
||||
const hover = client.protocol2CodeConverter.asHover(result);
|
||||
if (result.actions) {
|
||||
hover.contents.push(renderHoverActions(result.actions));
|
||||
}
|
||||
return hover;
|
||||
},
|
||||
(error) => {
|
||||
client.handleFailedRequest(lc.HoverRequest.type, token, error, null);
|
||||
return Promise.resolve(null);
|
||||
},
|
||||
);
|
||||
},
|
||||
// Using custom handling of CodeActions to support action groups and snippet edits.
|
||||
// Note that this means we have to re-implement lazy edit resolving ourselves as well.
|
||||
async provideCodeActions(
|
||||
document: vscode.TextDocument,
|
||||
range: vscode.Range,
|
||||
context: vscode.CodeActionContext,
|
||||
token: vscode.CancellationToken,
|
||||
_next: lc.ProvideCodeActionsSignature,
|
||||
) {
|
||||
const params: lc.CodeActionParams = {
|
||||
textDocument: client.code2ProtocolConverter.asTextDocumentIdentifier(document),
|
||||
range: client.code2ProtocolConverter.asRange(range),
|
||||
context: await client.code2ProtocolConverter.asCodeActionContext(context, token),
|
||||
};
|
||||
const callback = async (
|
||||
values: (lc.Command | lc.CodeAction)[] | null,
|
||||
): Promise<(vscode.Command | vscode.CodeAction)[] | undefined> => {
|
||||
if (values === null) return undefined;
|
||||
const result: (vscode.CodeAction | vscode.Command)[] = [];
|
||||
const groups = new Map<string, { index: number; items: vscode.CodeAction[] }>();
|
||||
for (const item of values) {
|
||||
// In our case we expect to get code edits only from diagnostics
|
||||
if (lc.CodeAction.is(item)) {
|
||||
assert(!item.command, "We don't expect to receive commands in CodeActions");
|
||||
const action = await client.protocol2CodeConverter.asCodeAction(
|
||||
item,
|
||||
token,
|
||||
);
|
||||
result.push(action);
|
||||
continue;
|
||||
}
|
||||
assert(
|
||||
isCodeActionWithoutEditsAndCommands(item),
|
||||
"We don't expect edits or commands here",
|
||||
);
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
const kind = client.protocol2CodeConverter.asCodeActionKind((item as any).kind);
|
||||
const action = new vscode.CodeAction(item.title, kind);
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
const group = (item as any).group;
|
||||
action.command = {
|
||||
command: "rust-analyzer.resolveCodeAction",
|
||||
title: item.title,
|
||||
arguments: [item],
|
||||
};
|
||||
|
||||
// Set a dummy edit, so that VS Code doesn't try to resolve this.
|
||||
action.edit = new WorkspaceEdit();
|
||||
|
||||
if (group) {
|
||||
let entry = groups.get(group);
|
||||
if (!entry) {
|
||||
entry = { index: result.length, items: [] };
|
||||
groups.set(group, entry);
|
||||
result.push(action);
|
||||
}
|
||||
entry.items.push(action);
|
||||
} else {
|
||||
result.push(action);
|
||||
}
|
||||
}
|
||||
for (const [group, { index, items }] of groups) {
|
||||
if (items.length === 1) {
|
||||
const item = unwrapUndefinable(items[0]);
|
||||
result[index] = item;
|
||||
} else {
|
||||
const action = new vscode.CodeAction(group);
|
||||
const item = unwrapUndefinable(items[0]);
|
||||
action.kind = item.kind;
|
||||
action.command = {
|
||||
command: "rust-analyzer.applyActionGroup",
|
||||
title: "",
|
||||
arguments: [
|
||||
items.map((item) => {
|
||||
return {
|
||||
label: item.title,
|
||||
arguments: item.command!.arguments![0],
|
||||
};
|
||||
}),
|
||||
],
|
||||
};
|
||||
|
||||
// Set a dummy edit, so that VS Code doesn't try to resolve this.
|
||||
action.edit = new WorkspaceEdit();
|
||||
|
||||
result[index] = action;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
};
|
||||
return client
|
||||
.sendRequest(lc.CodeActionRequest.type, params, token)
|
||||
.then(callback, (_error) => undefined);
|
||||
},
|
||||
};
|
||||
const clientOptions: lc.LanguageClientOptions = {
|
||||
documentSelector: [{ scheme: "file", language: "rust" }],
|
||||
initializationOptions,
|
||||
diagnosticCollectionName: "rustc",
|
||||
traceOutputChannel,
|
||||
outputChannel,
|
||||
middleware: {
|
||||
workspace: {
|
||||
// HACK: This is a workaround, when the client has been disposed, VSCode
|
||||
// continues to emit events to the client and the default one for this event
|
||||
// attempt to restart the client for no reason
|
||||
async didChangeWatchedFile(event, next) {
|
||||
if (client.isRunning()) {
|
||||
await next(event);
|
||||
}
|
||||
},
|
||||
async configuration(
|
||||
params: lc.ConfigurationParams,
|
||||
token: vscode.CancellationToken,
|
||||
next: lc.ConfigurationRequest.HandlerSignature,
|
||||
) {
|
||||
const resp = await next(params, token);
|
||||
if (resp && Array.isArray(resp)) {
|
||||
return resp.map((val) => {
|
||||
return prepareVSCodeConfig(val);
|
||||
});
|
||||
} else {
|
||||
return resp;
|
||||
}
|
||||
},
|
||||
},
|
||||
async handleDiagnostics(
|
||||
uri: vscode.Uri,
|
||||
diagnosticList: vscode.Diagnostic[],
|
||||
next: lc.HandleDiagnosticsSignature,
|
||||
) {
|
||||
const preview = config.previewRustcOutput;
|
||||
const errorCode = config.useRustcErrorCode;
|
||||
diagnosticList.forEach((diag, idx) => {
|
||||
const value =
|
||||
typeof diag.code === "string" || typeof diag.code === "number"
|
||||
? diag.code
|
||||
: diag.code?.value;
|
||||
if (
|
||||
// FIXME: We currently emit this diagnostic way too early, before we have
|
||||
// loaded the project fully
|
||||
// value === "unlinked-file" &&
|
||||
value === "temporary-disabled" &&
|
||||
!unlinkedFiles.includes(uri) &&
|
||||
(diag.message === "file not included in crate hierarchy" ||
|
||||
diag.message.startsWith("This file is not included in any crates"))
|
||||
) {
|
||||
const config = vscode.workspace.getConfiguration("rust-analyzer");
|
||||
if (config.get("showUnlinkedFileNotification")) {
|
||||
unlinkedFiles.push(uri);
|
||||
const folder = vscode.workspace.getWorkspaceFolder(uri)?.uri.fsPath;
|
||||
if (folder) {
|
||||
const parentBackslash = uri.fsPath.lastIndexOf(
|
||||
pathSeparator + "src",
|
||||
);
|
||||
const parent = uri.fsPath.substring(0, parentBackslash);
|
||||
|
||||
if (parent.startsWith(folder)) {
|
||||
const path = vscode.Uri.file(
|
||||
parent + pathSeparator + "Cargo.toml",
|
||||
);
|
||||
void vscode.workspace.fs.stat(path).then(async () => {
|
||||
const choice = await vscode.window.showInformationMessage(
|
||||
`This rust file does not belong to a loaded cargo project. It looks like it might belong to the workspace at ${path.path}, do you want to add it to the linked Projects?`,
|
||||
"Yes",
|
||||
"No",
|
||||
"Don't show this again",
|
||||
);
|
||||
switch (choice) {
|
||||
case undefined:
|
||||
break;
|
||||
case "No":
|
||||
break;
|
||||
case "Yes":
|
||||
const pathToInsert =
|
||||
"." +
|
||||
parent.substring(folder.length) +
|
||||
pathSeparator +
|
||||
"Cargo.toml";
|
||||
await config.update(
|
||||
"linkedProjects",
|
||||
config
|
||||
.get<any[]>("linkedProjects")
|
||||
?.concat(pathToInsert),
|
||||
false,
|
||||
);
|
||||
break;
|
||||
case "Don't show this again":
|
||||
await config.update(
|
||||
"showUnlinkedFileNotification",
|
||||
false,
|
||||
false,
|
||||
);
|
||||
break;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Abuse the fact that VSCode leaks the LSP diagnostics data field through the
|
||||
// Diagnostic class, if they ever break this we are out of luck and have to go
|
||||
// back to the worst diagnostics experience ever:)
|
||||
|
||||
// We encode the rendered output of a rustc diagnostic in the rendered field of
|
||||
// the data payload of the lsp diagnostic. If that field exists, overwrite the
|
||||
// diagnostic code such that clicking it opens the diagnostic in a readonly
|
||||
// text editor for easy inspection
|
||||
const rendered = (diag as unknown as { data?: { rendered?: string } }).data
|
||||
?.rendered;
|
||||
if (rendered) {
|
||||
if (preview) {
|
||||
const decolorized = anser.ansiToText(rendered);
|
||||
const index =
|
||||
decolorized.match(/^(note|help):/m)?.index || rendered.length;
|
||||
diag.message = decolorized
|
||||
.substring(0, index)
|
||||
.replace(/^ -->[^\n]+\n/m, "");
|
||||
}
|
||||
diag.code = {
|
||||
target: vscode.Uri.from({
|
||||
scheme: diagnostics.URI_SCHEME,
|
||||
path: `/diagnostic message [${idx.toString()}]`,
|
||||
fragment: uri.toString(),
|
||||
query: idx.toString(),
|
||||
}),
|
||||
value:
|
||||
errorCode && value ? value : "Click for full compiler diagnostic",
|
||||
};
|
||||
}
|
||||
});
|
||||
return next(uri, diagnosticList);
|
||||
},
|
||||
async provideHover(
|
||||
document: vscode.TextDocument,
|
||||
position: vscode.Position,
|
||||
token: vscode.CancellationToken,
|
||||
_next: lc.ProvideHoverSignature,
|
||||
) {
|
||||
const editor = vscode.window.activeTextEditor;
|
||||
const positionOrRange = editor?.selection?.contains(position)
|
||||
? client.code2ProtocolConverter.asRange(editor.selection)
|
||||
: client.code2ProtocolConverter.asPosition(position);
|
||||
return client
|
||||
.sendRequest(
|
||||
ra.hover,
|
||||
{
|
||||
textDocument:
|
||||
client.code2ProtocolConverter.asTextDocumentIdentifier(document),
|
||||
position: positionOrRange,
|
||||
},
|
||||
token,
|
||||
)
|
||||
.then(
|
||||
(result) => {
|
||||
if (!result) return null;
|
||||
const hover = client.protocol2CodeConverter.asHover(result);
|
||||
if (!!result.actions) {
|
||||
hover.contents.push(renderHoverActions(result.actions));
|
||||
}
|
||||
return hover;
|
||||
},
|
||||
(error) => {
|
||||
client.handleFailedRequest(lc.HoverRequest.type, token, error, null);
|
||||
return Promise.resolve(null);
|
||||
},
|
||||
);
|
||||
},
|
||||
// Using custom handling of CodeActions to support action groups and snippet edits.
|
||||
// Note that this means we have to re-implement lazy edit resolving ourselves as well.
|
||||
async provideCodeActions(
|
||||
document: vscode.TextDocument,
|
||||
range: vscode.Range,
|
||||
context: vscode.CodeActionContext,
|
||||
token: vscode.CancellationToken,
|
||||
_next: lc.ProvideCodeActionsSignature,
|
||||
) {
|
||||
const params: lc.CodeActionParams = {
|
||||
textDocument: client.code2ProtocolConverter.asTextDocumentIdentifier(document),
|
||||
range: client.code2ProtocolConverter.asRange(range),
|
||||
context: await client.code2ProtocolConverter.asCodeActionContext(
|
||||
context,
|
||||
token,
|
||||
),
|
||||
};
|
||||
return client.sendRequest(lc.CodeActionRequest.type, params, token).then(
|
||||
async (values) => {
|
||||
if (values === null) return undefined;
|
||||
const result: (vscode.CodeAction | vscode.Command)[] = [];
|
||||
const groups = new Map<
|
||||
string,
|
||||
{ index: number; items: vscode.CodeAction[] }
|
||||
>();
|
||||
for (const item of values) {
|
||||
// In our case we expect to get code edits only from diagnostics
|
||||
if (lc.CodeAction.is(item)) {
|
||||
assert(
|
||||
!item.command,
|
||||
"We don't expect to receive commands in CodeActions",
|
||||
);
|
||||
const action = await client.protocol2CodeConverter.asCodeAction(
|
||||
item,
|
||||
token,
|
||||
);
|
||||
result.push(action);
|
||||
continue;
|
||||
}
|
||||
assert(
|
||||
isCodeActionWithoutEditsAndCommands(item),
|
||||
"We don't expect edits or commands here",
|
||||
);
|
||||
const kind = client.protocol2CodeConverter.asCodeActionKind(
|
||||
(item as any).kind,
|
||||
);
|
||||
const action = new vscode.CodeAction(item.title, kind);
|
||||
const group = (item as any).group;
|
||||
action.command = {
|
||||
command: "rust-analyzer.resolveCodeAction",
|
||||
title: item.title,
|
||||
arguments: [item],
|
||||
};
|
||||
|
||||
// Set a dummy edit, so that VS Code doesn't try to resolve this.
|
||||
action.edit = new WorkspaceEdit();
|
||||
|
||||
if (group) {
|
||||
let entry = groups.get(group);
|
||||
if (!entry) {
|
||||
entry = { index: result.length, items: [] };
|
||||
groups.set(group, entry);
|
||||
result.push(action);
|
||||
}
|
||||
entry.items.push(action);
|
||||
} else {
|
||||
result.push(action);
|
||||
}
|
||||
}
|
||||
for (const [group, { index, items }] of groups) {
|
||||
if (items.length === 1) {
|
||||
const item = unwrapUndefinable(items[0]);
|
||||
result[index] = item;
|
||||
} else {
|
||||
const action = new vscode.CodeAction(group);
|
||||
const item = unwrapUndefinable(items[0]);
|
||||
action.kind = item.kind;
|
||||
action.command = {
|
||||
command: "rust-analyzer.applyActionGroup",
|
||||
title: "",
|
||||
arguments: [
|
||||
items.map((item) => {
|
||||
return {
|
||||
label: item.title,
|
||||
arguments: item.command!.arguments![0],
|
||||
};
|
||||
}),
|
||||
],
|
||||
};
|
||||
|
||||
// Set a dummy edit, so that VS Code doesn't try to resolve this.
|
||||
action.edit = new WorkspaceEdit();
|
||||
|
||||
result[index] = action;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
},
|
||||
(_error) => undefined,
|
||||
);
|
||||
},
|
||||
},
|
||||
middleware: raMiddleware,
|
||||
markdown: {
|
||||
supportHtml: true,
|
||||
},
|
||||
|
@ -319,9 +300,11 @@ class ExperimentalFeatures implements lc.StaticFeature {
|
|||
constructor(config: Config) {
|
||||
this.testExplorer = config.testExplorer || false;
|
||||
}
|
||||
|
||||
getState(): lc.FeatureState {
|
||||
return { kind: "static" };
|
||||
}
|
||||
|
||||
fillClientCapabilities(capabilities: lc.ClientCapabilities): void {
|
||||
capabilities.experimental = {
|
||||
snippetTextEdit: true,
|
||||
|
@ -345,11 +328,14 @@ class ExperimentalFeatures implements lc.StaticFeature {
|
|||
...capabilities.experimental,
|
||||
};
|
||||
}
|
||||
|
||||
initialize(
|
||||
_capabilities: lc.ServerCapabilities,
|
||||
_documentSelector: lc.DocumentSelector | undefined,
|
||||
): void {}
|
||||
|
||||
dispose(): void {}
|
||||
|
||||
clear(): void {}
|
||||
}
|
||||
|
||||
|
@ -357,6 +343,7 @@ class OverrideFeatures implements lc.StaticFeature {
|
|||
getState(): lc.FeatureState {
|
||||
return { kind: "static" };
|
||||
}
|
||||
|
||||
fillClientCapabilities(capabilities: lc.ClientCapabilities): void {
|
||||
// Force disable `augmentsSyntaxTokens`, VSCode's textmate grammar is somewhat incomplete
|
||||
// making the experience generally worse
|
||||
|
@ -365,14 +352,18 @@ class OverrideFeatures implements lc.StaticFeature {
|
|||
caps.augmentsSyntaxTokens = false;
|
||||
}
|
||||
}
|
||||
|
||||
initialize(
|
||||
_capabilities: lc.ServerCapabilities,
|
||||
_documentSelector: lc.DocumentSelector | undefined,
|
||||
): void {}
|
||||
|
||||
dispose(): void {}
|
||||
|
||||
clear(): void {}
|
||||
}
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
function isCodeActionWithoutEditsAndCommands(value: any): boolean {
|
||||
const candidate: lc.CodeAction = value;
|
||||
return (
|
||||
|
|
|
@ -78,6 +78,7 @@ export function memoryUsage(ctx: CtxInit): Cmd {
|
|||
provideTextDocumentContent(_uri: vscode.Uri): vscode.ProviderResult<string> {
|
||||
if (!vscode.window.activeTextEditor) return "";
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
return ctx.client.sendRequest(ra.memoryUsage).then((mem: any) => {
|
||||
return "Per-query memory usage:\n" + mem + "\n(note: database has been cleared)";
|
||||
});
|
||||
|
@ -161,7 +162,7 @@ export function joinLines(ctx: CtxInit): Cmd {
|
|||
});
|
||||
const textEdits = await client.protocol2CodeConverter.asTextEdits(items);
|
||||
await editor.edit((builder) => {
|
||||
textEdits.forEach((edit: any) => {
|
||||
textEdits.forEach((edit: vscode.TextEdit) => {
|
||||
builder.replace(edit.range, edit.newText);
|
||||
});
|
||||
});
|
||||
|
@ -209,6 +210,7 @@ export function onEnter(ctx: CtxInit): Cmd {
|
|||
),
|
||||
position: client.code2ProtocolConverter.asPosition(editor.selection.active),
|
||||
})
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
.catch((_error: any) => {
|
||||
// client.handleFailedRequest(OnEnterRequest.type, error, null);
|
||||
return null;
|
||||
|
@ -528,6 +530,7 @@ function viewFileUsingTextDocumentContentProvider(
|
|||
void sleep(10).then(() => this.eventEmitter.fire(this.uri));
|
||||
}
|
||||
}
|
||||
|
||||
private onDidChangeActiveTextEditor(editor: vscode.TextEditor | undefined) {
|
||||
if (editor && isRustEditor(editor) && shouldUpdate) {
|
||||
this.eventEmitter.fire(this.uri);
|
||||
|
@ -620,6 +623,7 @@ export function viewFileText(ctx: CtxInit): Cmd {
|
|||
void sleep(10).then(() => this.eventEmitter.fire(this.uri));
|
||||
}
|
||||
}
|
||||
|
||||
private onDidChangeActiveTextEditor(editor: vscode.TextEditor | undefined) {
|
||||
if (editor && isRustEditor(editor)) {
|
||||
this.eventEmitter.fire(this.uri);
|
||||
|
@ -683,6 +687,7 @@ export function viewItemTree(ctx: CtxInit): Cmd {
|
|||
void sleep(10).then(() => this.eventEmitter.fire(this.uri));
|
||||
}
|
||||
}
|
||||
|
||||
private onDidChangeActiveTextEditor(editor: vscode.TextEditor | undefined) {
|
||||
if (editor && isRustEditor(editor)) {
|
||||
this.eventEmitter.fire(this.uri);
|
||||
|
@ -1001,9 +1006,8 @@ export function resolveCodeAction(ctx: CtxInit): Cmd {
|
|||
...itemEdit,
|
||||
documentChanges: itemEdit.documentChanges?.filter((change) => "kind" in change),
|
||||
};
|
||||
const fileSystemEdit = await client.protocol2CodeConverter.asWorkspaceEdit(
|
||||
lcFileSystemEdit,
|
||||
);
|
||||
const fileSystemEdit =
|
||||
await client.protocol2CodeConverter.asWorkspaceEdit(lcFileSystemEdit);
|
||||
await vscode.workspace.applyEdit(fileSystemEdit);
|
||||
|
||||
// replace all text edits so that we can convert snippet text edits into `vscode.SnippetTextEdit`s
|
||||
|
|
|
@ -13,12 +13,7 @@ export type RunnableEnvCfgItem = {
|
|||
};
|
||||
export type RunnableEnvCfg = Record<string, string> | RunnableEnvCfgItem[];
|
||||
|
||||
type ShowStatusBar =
|
||||
| "always"
|
||||
| "never"
|
||||
| {
|
||||
documentSelector: vscode.DocumentSelector;
|
||||
};
|
||||
type ShowStatusBar = "always" | "never" | { documentSelector: vscode.DocumentSelector };
|
||||
|
||||
export class Config {
|
||||
readonly extensionId = "rust-lang.rust-analyzer";
|
||||
|
@ -145,13 +140,13 @@ export class Config {
|
|||
{
|
||||
// Parent doc single-line comment
|
||||
// e.g. //!|
|
||||
beforeText: /^\s*\/{2}\!.*$/,
|
||||
beforeText: /^\s*\/{2}!.*$/,
|
||||
action: { indentAction, appendText: "//! " },
|
||||
},
|
||||
{
|
||||
// Begins an auto-closed multi-line comment (standard or parent doc)
|
||||
// e.g. /** | */ or /*! | */
|
||||
beforeText: /^\s*\/\*(\*|\!)(?!\/)([^\*]|\*(?!\/))*$/,
|
||||
beforeText: /^\s*\/\*(\*|!)(?!\/)([^*]|\*(?!\/))*$/,
|
||||
afterText: /^\s*\*\/$/,
|
||||
action: {
|
||||
indentAction: vscode.IndentAction.IndentOutdent,
|
||||
|
@ -161,19 +156,19 @@ export class Config {
|
|||
{
|
||||
// Begins a multi-line comment (standard or parent doc)
|
||||
// e.g. /** ...| or /*! ...|
|
||||
beforeText: /^\s*\/\*(\*|\!)(?!\/)([^\*]|\*(?!\/))*$/,
|
||||
beforeText: /^\s*\/\*(\*|!)(?!\/)([^*]|\*(?!\/))*$/,
|
||||
action: { indentAction, appendText: " * " },
|
||||
},
|
||||
{
|
||||
// Continues a multi-line comment
|
||||
// e.g. * ...|
|
||||
beforeText: /^(\ \ )*\ \*(\ ([^\*]|\*(?!\/))*)?$/,
|
||||
beforeText: /^( {2})* \*( ([^*]|\*(?!\/))*)?$/,
|
||||
action: { indentAction, appendText: "* " },
|
||||
},
|
||||
{
|
||||
// Dedents after closing a multi-line comment
|
||||
// e.g. */|
|
||||
beforeText: /^(\ \ )*\ \*\/\s*$/,
|
||||
beforeText: /^( {2})* \*\/\s*$/,
|
||||
action: { indentAction, removeText: 1 },
|
||||
},
|
||||
];
|
||||
|
@ -227,9 +222,11 @@ export class Config {
|
|||
),
|
||||
);
|
||||
}
|
||||
|
||||
get checkOnSave() {
|
||||
return this.get<boolean>("checkOnSave") ?? false;
|
||||
}
|
||||
|
||||
async toggleCheckOnSave() {
|
||||
const config = this.cfg.inspect<boolean>("checkOnSave") ?? { key: "checkOnSave" };
|
||||
let overrideInLanguage;
|
||||
|
@ -269,8 +266,10 @@ export class Config {
|
|||
}
|
||||
|
||||
runnablesExtraEnv(label: string): Record<string, string> | undefined {
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
const item = this.get<any>("runnables.extraEnv") ?? this.get<any>("runnableEnv");
|
||||
if (!item) return undefined;
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
const fixRecord = (r: Record<string, any>) => {
|
||||
for (const key in r) {
|
||||
if (typeof r[key] !== "string") {
|
||||
|
@ -339,6 +338,7 @@ export class Config {
|
|||
gotoTypeDef: this.get<boolean>("hover.actions.gotoTypeDef.enable"),
|
||||
};
|
||||
}
|
||||
|
||||
get previewRustcOutput() {
|
||||
return this.get<boolean>("diagnostics.previewRustcOutput");
|
||||
}
|
||||
|
@ -370,6 +370,7 @@ export class Config {
|
|||
get askBeforeUpdateTest() {
|
||||
return this.get<boolean>("runnables.askBeforeUpdateTest");
|
||||
}
|
||||
|
||||
async setAskBeforeUpdateTest(value: boolean) {
|
||||
await this.cfg.update("runnables.askBeforeUpdateTest", value, true);
|
||||
}
|
||||
|
@ -378,11 +379,13 @@ export class Config {
|
|||
export function prepareVSCodeConfig<T>(resp: T): T {
|
||||
if (Is.string(resp)) {
|
||||
return substituteVSCodeVariableInString(resp) as T;
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
} else if (resp && Is.array<any>(resp)) {
|
||||
return resp.map((val) => {
|
||||
return prepareVSCodeConfig(val);
|
||||
}) as T;
|
||||
} else if (resp && typeof resp === "object") {
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
const res: { [key: string]: any } = {};
|
||||
for (const key in resp) {
|
||||
const val = resp[key];
|
||||
|
@ -489,8 +492,7 @@ function computeVscodeVar(varName: string): string | null {
|
|||
// TODO: support for remote workspaces?
|
||||
const fsPath: string =
|
||||
folder === undefined
|
||||
? // no workspace opened
|
||||
""
|
||||
? "" // no workspace opened
|
||||
: // could use currently opened document to detect the correct
|
||||
// workspace. However, that would be determined by the document
|
||||
// user has opened on Editor startup. Could lead to
|
||||
|
|
|
@ -34,13 +34,8 @@ import type { RustAnalyzerExtensionApi } from "./main";
|
|||
|
||||
export type Workspace =
|
||||
| { kind: "Empty" }
|
||||
| {
|
||||
kind: "Workspace Folder";
|
||||
}
|
||||
| {
|
||||
kind: "Detached Files";
|
||||
files: vscode.TextDocument[];
|
||||
};
|
||||
| { kind: "Workspace Folder" }
|
||||
| { kind: "Detached Files"; files: vscode.TextDocument[] };
|
||||
|
||||
export function fetchWorkspace(): Workspace {
|
||||
const folders = (vscode.workspace.workspaceFolders || []).filter(
|
||||
|
@ -53,10 +48,7 @@ export function fetchWorkspace(): Workspace {
|
|||
return folders.length === 0
|
||||
? rustDocuments.length === 0
|
||||
? { kind: "Empty" }
|
||||
: {
|
||||
kind: "Detached Files",
|
||||
files: rustDocuments,
|
||||
}
|
||||
: { kind: "Detached Files", files: rustDocuments }
|
||||
: { kind: "Workspace Folder" };
|
||||
}
|
||||
|
||||
|
@ -89,6 +81,7 @@ export class Ctx implements RustAnalyzerExtensionApi {
|
|||
private _dependencyTreeView:
|
||||
| vscode.TreeView<Dependency | DependencyFile | DependencyId>
|
||||
| undefined;
|
||||
|
||||
private _syntaxTreeProvider: SyntaxTreeProvider | undefined;
|
||||
private _syntaxTreeView: vscode.TreeView<SyntaxElement> | undefined;
|
||||
private lastStatus: ServerStatusParams | { health: "stopped" } = { health: "stopped" };
|
||||
|
@ -267,7 +260,7 @@ export class Ctx implements RustAnalyzerExtensionApi {
|
|||
let message = "bootstrap error. ";
|
||||
|
||||
message +=
|
||||
'See the logs in "OUTPUT > Rust Analyzer Client" (should open automatically). ';
|
||||
'See the logs in "OUTPUT > Rust Analyzer Client" (should open automatically).';
|
||||
message +=
|
||||
'To enable verbose logs, click the gear icon in the "OUTPUT" tab and select "Debug".';
|
||||
|
||||
|
@ -476,9 +469,11 @@ export class Ctx implements RustAnalyzerExtensionApi {
|
|||
this.lastStatus = status;
|
||||
this.updateStatusBarItem();
|
||||
}
|
||||
|
||||
refreshServerStatus() {
|
||||
this.updateStatusBarItem();
|
||||
}
|
||||
|
||||
private updateStatusBarItem() {
|
||||
let icon = "";
|
||||
const status = this.lastStatus;
|
||||
|
@ -533,19 +528,14 @@ export class Ctx implements RustAnalyzerExtensionApi {
|
|||
|
||||
const toggleCheckOnSave = this.config.checkOnSave ? "Disable" : "Enable";
|
||||
statusBar.tooltip.appendMarkdown(
|
||||
`[Extension Info](command:rust-analyzer.serverVersion "Show version and server binary info"): Version ${this.version}, Server Version ${this._serverVersion}` +
|
||||
"\n\n---\n\n" +
|
||||
'[$(terminal) Open Logs](command:rust-analyzer.openLogs "Open the server logs")' +
|
||||
"\n\n" +
|
||||
`[$(settings) ${toggleCheckOnSave} Check on Save](command:rust-analyzer.toggleCheckOnSave "Temporarily ${toggleCheckOnSave.toLowerCase()} check on save functionality")` +
|
||||
"\n\n" +
|
||||
'[$(refresh) Reload Workspace](command:rust-analyzer.reloadWorkspace "Reload and rediscover workspaces")' +
|
||||
"\n\n" +
|
||||
'[$(symbol-property) Rebuild Build Dependencies](command:rust-analyzer.rebuildProcMacros "Rebuild build scripts and proc-macros")' +
|
||||
"\n\n" +
|
||||
'[$(stop-circle) Stop server](command:rust-analyzer.stopServer "Stop the server")' +
|
||||
"\n\n" +
|
||||
'[$(debug-restart) Restart server](command:rust-analyzer.restartServer "Restart the server")',
|
||||
`[Extension Info](command:rust-analyzer.serverVersion "Show version and server binary info"): Version ${this.version}, Server Version ${this._serverVersion}\n\n` +
|
||||
`---\n\n` +
|
||||
`[$(terminal) Open Logs](command:rust-analyzer.openLogs "Open the server logs")\n\n` +
|
||||
`[$(settings) ${toggleCheckOnSave} Check on Save](command:rust-analyzer.toggleCheckOnSave "Temporarily ${toggleCheckOnSave.toLowerCase()} check on save functionality")\n\n` +
|
||||
`[$(refresh) Reload Workspace](command:rust-analyzer.reloadWorkspace "Reload and rediscover workspaces")\n\n` +
|
||||
`[$(symbol-property) Rebuild Build Dependencies](command:rust-analyzer.rebuildProcMacros "Rebuild build scripts and proc-macros")\n\n` +
|
||||
`[$(stop-circle) Stop server](command:rust-analyzer.stopServer "Stop the server")\n\n` +
|
||||
`[$(debug-restart) Restart server](command:rust-analyzer.restartServer "Restart the server")`,
|
||||
);
|
||||
if (!status.quiescent) icon = "$(loading~spin) ";
|
||||
statusBar.text = `${icon}rust-analyzer`;
|
||||
|
@ -580,4 +570,5 @@ export interface Disposable {
|
|||
dispose(): void;
|
||||
}
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
export type Cmd = (...args: any[]) => unknown;
|
||||
|
|
|
@ -22,6 +22,7 @@ export async function makeDebugConfig(ctx: Ctx, runnable: ra.Runnable): Promise<
|
|||
if (!debugConfig) return;
|
||||
|
||||
const wsLaunchSection = vscode.workspace.getConfiguration("launch", scope);
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
const configurations = wsLaunchSection.get<any[]>("configurations") || [];
|
||||
|
||||
const index = configurations.findIndex((c) => c.name === debugConfig.name);
|
||||
|
@ -46,6 +47,7 @@ export async function startDebugSession(ctx: Ctx, runnable: ra.Runnable): Promis
|
|||
let message = "";
|
||||
|
||||
const wsLaunchSection = vscode.workspace.getConfiguration("launch");
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
const configurations = wsLaunchSection.get<any[]>("configurations") || [];
|
||||
|
||||
// The runnable label is the name of the test with the "test prefix"
|
||||
|
@ -121,7 +123,7 @@ async function getDebugConfiguration(
|
|||
debugOutput.show(true);
|
||||
}
|
||||
// folder exists or RA is not active.
|
||||
// eslint-disable-next-line @typescript-eslint/no-unnecessary-type-assertion
|
||||
|
||||
const workspaceFolders = vscode.workspace.workspaceFolders!;
|
||||
const isMultiFolderWorkspace = workspaceFolders.length > 1;
|
||||
const firstWorkspace = workspaceFolders[0];
|
||||
|
@ -189,8 +191,9 @@ async function getDebugConfiguration(
|
|||
sourceFileMap,
|
||||
);
|
||||
if (debugConfig.type in debugOptions.engineSettings) {
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
const settingsMap = (debugOptions.engineSettings as any)[debugConfig.type];
|
||||
for (var key in settingsMap) {
|
||||
for (const key in settingsMap) {
|
||||
debugConfig[key] = settingsMap[key];
|
||||
}
|
||||
}
|
||||
|
@ -409,7 +412,7 @@ function quote(xs: string[]) {
|
|||
return "'" + s.replace(/(['\\])/g, "\\$1") + "'";
|
||||
}
|
||||
if (/["'\s]/.test(s)) {
|
||||
return '"' + s.replace(/(["\\$`!])/g, "\\$1") + '"';
|
||||
return `"${s.replace(/(["\\$`!])/g, "\\$1")}"`;
|
||||
}
|
||||
return s.replace(/([A-Za-z]:)?([#!"$&'()*,:;<=>?@[\\\]^`{|}])/g, "$1\\$2");
|
||||
})
|
||||
|
|
|
@ -104,10 +104,7 @@ export class AnsiDecorationProvider implements vscode.Disposable {
|
|||
|
||||
for (const [lineNumber, line] of lines.entries()) {
|
||||
const totalEscapeLength = 0;
|
||||
|
||||
// eslint-disable-next-line camelcase
|
||||
const parsed = anser.ansiToJson(line, { use_classes: true });
|
||||
|
||||
let offset = 0;
|
||||
|
||||
for (const span of parsed) {
|
||||
|
@ -162,23 +159,23 @@ export class AnsiDecorationProvider implements vscode.Disposable {
|
|||
// NOTE: This could just be a kebab-case to camelCase conversion, but I think it's
|
||||
// a short enough list to just write these by hand
|
||||
static readonly _anserToThemeColor: Record<string, ThemeColor> = {
|
||||
"ansi-black": "ansiBlack",
|
||||
"ansi-white": "ansiWhite",
|
||||
"ansi-red": "ansiRed",
|
||||
"ansi-green": "ansiGreen",
|
||||
"ansi-yellow": "ansiYellow",
|
||||
"ansi-blue": "ansiBlue",
|
||||
"ansi-magenta": "ansiMagenta",
|
||||
"ansi-cyan": "ansiCyan",
|
||||
"ansi-black": new ThemeColor("terminal.ansiBlack"),
|
||||
"ansi-white": new ThemeColor("terminal.ansiWhite"),
|
||||
"ansi-red": new ThemeColor("terminal.ansiRed"),
|
||||
"ansi-green": new ThemeColor("terminal.ansiGreen"),
|
||||
"ansi-yellow": new ThemeColor("terminal.ansiYellow"),
|
||||
"ansi-blue": new ThemeColor("terminal.ansiBlue"),
|
||||
"ansi-magenta": new ThemeColor("terminal.ansiMagenta"),
|
||||
"ansi-cyan": new ThemeColor("terminal.ansiCyan"),
|
||||
|
||||
"ansi-bright-black": "ansiBrightBlack",
|
||||
"ansi-bright-white": "ansiBrightWhite",
|
||||
"ansi-bright-red": "ansiBrightRed",
|
||||
"ansi-bright-green": "ansiBrightGreen",
|
||||
"ansi-bright-yellow": "ansiBrightYellow",
|
||||
"ansi-bright-blue": "ansiBrightBlue",
|
||||
"ansi-bright-magenta": "ansiBrightMagenta",
|
||||
"ansi-bright-cyan": "ansiBrightCyan",
|
||||
"ansi-bright-black": new ThemeColor("terminal.ansiBrightBlack"),
|
||||
"ansi-bright-white": new ThemeColor("terminal.ansiBrightWhite"),
|
||||
"ansi-bright-red": new ThemeColor("terminal.ansiBrightRed"),
|
||||
"ansi-bright-green": new ThemeColor("terminal.ansiBrightGreen"),
|
||||
"ansi-bright-yellow": new ThemeColor("terminal.ansiBrightYellow"),
|
||||
"ansi-bright-blue": new ThemeColor("terminal.ansiBrightBlue"),
|
||||
"ansi-bright-magenta": new ThemeColor("terminal.ansiBrightMagenta"),
|
||||
"ansi-bright-cyan": new ThemeColor("terminal.ansiBrightCyan"),
|
||||
};
|
||||
|
||||
private static _convertColor(
|
||||
|
|
|
@ -5,6 +5,8 @@ export class RaLanguageClient extends lc.LanguageClient {
|
|||
override handleFailedRequest<T>(
|
||||
type: lc.MessageSignature,
|
||||
token: vscode.CancellationToken | undefined,
|
||||
// declared as `any` in vscode-languageclient
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
error: any,
|
||||
defaultValue: T,
|
||||
showNotification?: boolean | undefined,
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
/* eslint-disable @typescript-eslint/no-empty-object-type */
|
||||
/**
|
||||
* This file mirrors `crates/rust-analyzer/src/lsp_ext.rs` declarations.
|
||||
*/
|
||||
|
|
|
@ -214,6 +214,7 @@ function checkConflictingExtensions() {
|
|||
"both plugins to not work correctly. You should disable one of them.",
|
||||
"Got it",
|
||||
)
|
||||
// eslint-disable-next-line no-console
|
||||
.then(() => {}, console.error);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -14,6 +14,7 @@ export class PersistentState {
|
|||
get serverVersion(): string | undefined {
|
||||
return this.globalState.get("serverVersion");
|
||||
}
|
||||
|
||||
async updateServerVersion(value: string | undefined) {
|
||||
await this.globalState.update("serverVersion", value);
|
||||
}
|
||||
|
|
|
@ -24,9 +24,7 @@ export async function applySnippetWorkspaceEdit(
|
|||
for (const indel of edits) {
|
||||
assert(
|
||||
!(indel instanceof vscode.SnippetTextEdit),
|
||||
`bad ws edit: snippet received with multiple edits: ${JSON.stringify(
|
||||
edit,
|
||||
)}`,
|
||||
`bad ws edit: snippet received with multiple edits: ${JSON.stringify(edit)}`,
|
||||
);
|
||||
builder.replace(indel.range, indel.newText);
|
||||
}
|
||||
|
|
|
@ -7,8 +7,10 @@ import * as ra from "./lsp_ext";
|
|||
export class SyntaxTreeProvider implements vscode.TreeDataProvider<SyntaxElement> {
|
||||
private _onDidChangeTreeData: vscode.EventEmitter<SyntaxElement | undefined | void> =
|
||||
new vscode.EventEmitter<SyntaxElement | undefined | void>();
|
||||
|
||||
readonly onDidChangeTreeData: vscode.Event<SyntaxElement | undefined | void> =
|
||||
this._onDidChangeTreeData.event;
|
||||
|
||||
ctx: CtxInit;
|
||||
root: SyntaxNode | undefined;
|
||||
hideWhitespace: boolean = false;
|
||||
|
|
|
@ -133,7 +133,7 @@ export const prepareTestExplorer = (
|
|||
}
|
||||
if (scope) {
|
||||
const recursivelyRemove = (tests: vscode.TestItemCollection) => {
|
||||
for (const [_, test] of tests) {
|
||||
for (const [, test] of tests) {
|
||||
if (!testSet.has(test.id)) {
|
||||
deleteTest(test, tests);
|
||||
} else {
|
||||
|
|
|
@ -18,6 +18,22 @@ export interface ArtifactSpec {
|
|||
filter?: (artifacts: CompilationArtifact[]) => CompilationArtifact[];
|
||||
}
|
||||
|
||||
interface CompilerMessage {
|
||||
reason: string;
|
||||
executable?: string;
|
||||
target: {
|
||||
crate_types: [string, ...string[]];
|
||||
kind: [string, ...string[]];
|
||||
name: string;
|
||||
};
|
||||
profile: {
|
||||
test: boolean;
|
||||
};
|
||||
message: {
|
||||
rendered: string;
|
||||
};
|
||||
}
|
||||
|
||||
export class Cargo {
|
||||
constructor(
|
||||
readonly rootFolder: string,
|
||||
|
@ -109,7 +125,7 @@ export class Cargo {
|
|||
|
||||
private async runCargo(
|
||||
cargoArgs: string[],
|
||||
onStdoutJson: (obj: any) => void,
|
||||
onStdoutJson: (obj: CompilerMessage) => void,
|
||||
onStderrString: (data: string) => void,
|
||||
env?: Record<string, string>,
|
||||
): Promise<number> {
|
||||
|
@ -131,7 +147,7 @@ export class Cargo {
|
|||
onStdoutJson(message);
|
||||
});
|
||||
|
||||
cargo.on("exit", (exitCode, _) => {
|
||||
cargo.on("exit", (exitCode) => {
|
||||
if (exitCode === 0) resolve(exitCode);
|
||||
else reject(new Error(`exit code: ${exitCode}.`));
|
||||
});
|
||||
|
|
|
@ -104,6 +104,7 @@ export function isDocumentInWorkspace(document: RustDocument): boolean {
|
|||
}
|
||||
|
||||
/** Sets ['when'](https://code.visualstudio.com/docs/getstarted/keybindings#_when-clause-contexts) clause contexts */
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
export function setContextValue(key: string, value: any): Thenable<void> {
|
||||
return vscode.commands.executeCommand("setContext", key, value);
|
||||
}
|
||||
|
@ -167,27 +168,35 @@ export class LazyOutputChannel implements vscode.OutputChannel {
|
|||
append(value: string): void {
|
||||
this.channel.append(value);
|
||||
}
|
||||
|
||||
appendLine(value: string): void {
|
||||
this.channel.appendLine(value);
|
||||
}
|
||||
|
||||
replace(value: string): void {
|
||||
this.channel.replace(value);
|
||||
}
|
||||
|
||||
clear(): void {
|
||||
if (this._channel) {
|
||||
this._channel.clear();
|
||||
}
|
||||
}
|
||||
show(preserveFocus?: boolean): void;
|
||||
show(column?: vscode.ViewColumn, preserveFocus?: boolean): void;
|
||||
show(column?: any, preserveFocus?: any): void {
|
||||
this.channel.show(column, preserveFocus);
|
||||
|
||||
show(columnOrPreserveFocus?: vscode.ViewColumn | boolean, preserveFocus?: boolean): void {
|
||||
if (typeof columnOrPreserveFocus === "boolean") {
|
||||
this.channel.show(columnOrPreserveFocus);
|
||||
} else {
|
||||
this.channel.show(columnOrPreserveFocus, preserveFocus);
|
||||
}
|
||||
}
|
||||
|
||||
hide(): void {
|
||||
if (this._channel) {
|
||||
this._channel.hide();
|
||||
}
|
||||
}
|
||||
|
||||
dispose(): void {
|
||||
if (this._channel) {
|
||||
this._channel.dispose();
|
||||
|
@ -276,6 +285,7 @@ export async function spawnAsync(
|
|||
stderr: res.stderr,
|
||||
status: res.status,
|
||||
};
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
} catch (e: any) {
|
||||
return {
|
||||
stdout: e.stdout,
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
import * as assert from "node:assert/strict";
|
||||
import { readdir } from "fs/promises";
|
||||
import * as path from "path";
|
||||
import { pathToFileURL } from "url";
|
||||
|
||||
class Test {
|
||||
readonly name: string;
|
||||
|
@ -67,7 +68,7 @@ export async function run(): Promise<void> {
|
|||
);
|
||||
for (const testFile of testFiles) {
|
||||
try {
|
||||
const testModule = require(path.resolve(__dirname, testFile));
|
||||
const testModule = await import(pathToFileURL(path.resolve(__dirname, testFile)).href);
|
||||
await testModule.getTests(context);
|
||||
} catch (e) {
|
||||
error(`${e}`);
|
||||
|
|
|
@ -114,6 +114,7 @@ function f(task: vscode.Task): {
|
|||
execution,
|
||||
};
|
||||
}
|
||||
|
||||
function executionToSimple(
|
||||
taskExecution: vscode.ProcessExecution | vscode.ShellExecution | vscode.CustomExecution,
|
||||
): {
|
||||
|
@ -122,8 +123,8 @@ function executionToSimple(
|
|||
const exec = taskExecution as vscode.ProcessExecution | vscode.ShellExecution;
|
||||
if (exec instanceof vscode.ShellExecution) {
|
||||
return {
|
||||
command: typeof exec.command === "string" ? exec.command : exec.command.value,
|
||||
args: exec.args.map((arg) => {
|
||||
command: typeof exec.command === "string" ? exec.command : (exec.command?.value ?? ""),
|
||||
args: (exec.args ?? []).map((arg) => {
|
||||
if (typeof arg === "string") {
|
||||
return arg;
|
||||
}
|
||||
|
|
|
@ -6,6 +6,6 @@
|
|||
"src",
|
||||
"tests",
|
||||
// these are the eslint-only inclusions
|
||||
".eslintrc.js"
|
||||
"eslint.config.mts"
|
||||
]
|
||||
}
|
||||
|
|
|
@ -2,18 +2,17 @@
|
|||
"extends": "@tsconfig/strictest/tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"esModuleInterop": false,
|
||||
"module": "Node16",
|
||||
"moduleResolution": "Node16",
|
||||
"target": "ES2021",
|
||||
"module": "NodeNext",
|
||||
"moduleResolution": "nodenext",
|
||||
"target": "ES2024",
|
||||
"outDir": "out",
|
||||
"lib": ["ES2021"],
|
||||
"lib": ["ES2024"],
|
||||
"sourceMap": true,
|
||||
"rootDir": ".",
|
||||
"newLine": "lf",
|
||||
|
||||
// FIXME: https://github.com/rust-lang/rust-analyzer/issues/15253
|
||||
"exactOptionalPropertyTypes": false
|
||||
},
|
||||
"exclude": ["node_modules", ".vscode-test"],
|
||||
"exclude": ["node_modules", ".vscode-test", "out"],
|
||||
"include": ["src", "tests"]
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue