Unnamed repository; edit this file 'description' to name the repository.
Diffstat (limited to 'editors/code/src/client.ts')
-rw-r--r--editors/code/src/client.ts114
1 files changed, 59 insertions, 55 deletions
diff --git a/editors/code/src/client.ts b/editors/code/src/client.ts
index cdeea7333a..073ff2f470 100644
--- a/editors/code/src/client.ts
+++ b/editors/code/src/client.ts
@@ -3,7 +3,7 @@ import * as lc from "vscode-languageclient/node";
import * as vscode from "vscode";
import * as ra from "../src/lsp_ext";
import * as Is from "vscode-languageclient/lib/common/utils/is";
-import { assert, unwrapUndefinable } from "./util";
+import { assert } from "./util";
import * as diagnostics from "./diagnostics";
import { WorkspaceEdit } from "vscode";
import { type Config, prepareVSCodeConfig } from "./config";
@@ -188,11 +188,17 @@ export async function createClient(
context: await client.code2ProtocolConverter.asCodeActionContext(context, token),
};
const callback = async (
- values: (lc.Command | lc.CodeAction)[] | null,
+ values: (lc.Command | lc.CodeAction | object)[] | 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[] }>();
+ const groups = new Map<
+ string,
+ {
+ primary: vscode.CodeAction;
+ items: { label: string; arguments: lc.CodeAction }[];
+ }
+ >();
for (const item of values) {
// In our case we expect to get code edits only from diagnostics
if (lc.CodeAction.is(item)) {
@@ -204,62 +210,55 @@ export async function createClient(
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],
- };
+ assertIsCodeActionWithoutEditsAndCommands(item);
+ const kind = client.protocol2CodeConverter.asCodeActionKind(item.kind);
+ const group = item.group;
- // Set a dummy edit, so that VS Code doesn't try to resolve this.
- action.edit = new WorkspaceEdit();
+ const mkAction = () => {
+ const action = new vscode.CodeAction(item.title, kind);
+ 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();
+ return action;
+ };
if (group) {
let entry = groups.get(group);
if (!entry) {
- entry = { index: result.length, items: [] };
+ entry = { primary: mkAction(), items: [] };
groups.set(group, entry);
- result.push(action);
+ } else {
+ entry.items.push({
+ label: item.title,
+ arguments: item,
+ });
}
- entry.items.push(action);
} else {
- result.push(action);
+ result.push(mkAction());
}
}
- 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 = {
+ for (const [group, { items, primary }] of groups) {
+ // This group contains more than one item, so rewrite it to be a group action
+ if (items.length !== 0) {
+ const args = [
+ {
+ label: primary.title,
+ arguments: primary.command!.arguments![0],
+ },
+ ...items,
+ ];
+ primary.title = group;
+ primary.command = {
command: "rust-analyzer.applyActionGroup",
title: "",
- arguments: [
- items.map((item) => {
- return {
- label: item.title,
- arguments: item.command!.arguments![0],
- };
- }),
- ],
+ arguments: [args],
};
-
- // Set a dummy edit, so that VS Code doesn't try to resolve this.
- action.edit = new WorkspaceEdit();
-
- result[index] = action;
}
+ result.push(primary);
}
return result;
};
@@ -363,17 +362,22 @@ class OverrideFeatures implements lc.StaticFeature {
clear(): void {}
}
-// eslint-disable-next-line @typescript-eslint/no-explicit-any
-function isCodeActionWithoutEditsAndCommands(value: any): boolean {
- const candidate: lc.CodeAction = value;
- return (
+function assertIsCodeActionWithoutEditsAndCommands(
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
+ candidate: any,
+): asserts candidate is lc.CodeAction & {
+ group?: string;
+} {
+ assert(
candidate &&
- Is.string(candidate.title) &&
- (candidate.diagnostics === void 0 ||
- Is.typedArray(candidate.diagnostics, lc.Diagnostic.is)) &&
- (candidate.kind === void 0 || Is.string(candidate.kind)) &&
- candidate.edit === void 0 &&
- candidate.command === void 0
+ Is.string(candidate.title) &&
+ (candidate.diagnostics === undefined ||
+ Is.typedArray(candidate.diagnostics, lc.Diagnostic.is)) &&
+ (candidate.group === undefined || Is.string(candidate.group)) &&
+ (candidate.kind === undefined || Is.string(candidate.kind)) &&
+ candidate.edit === undefined &&
+ candidate.command === undefined,
+ `Expected a CodeAction without edits or commands, got: ${JSON.stringify(candidate)}`,
);
}