diff options
| author | bors <bors@rust-lang.org> | 2025-06-30 22:36:52 +0000 |
|---|---|---|
| committer | bors <bors@rust-lang.org> | 2025-06-30 22:36:52 +0000 |
| commit | fdad98d7463eebcdca94716ec3036c38a8d66f50 (patch) | |
| tree | a1810b7b03c4fba12d3ec7e740970320ad94b135 /src/tools/rust-analyzer/editors/code | |
| parent | f26e58023071e71636a3c72ac3a2bf89b1f76706 (diff) | |
| parent | 3f6dc54f5c02f8000b3960615b95d830c1bb344e (diff) | |
| download | rust-fdad98d7463eebcdca94716ec3036c38a8d66f50.tar.gz rust-fdad98d7463eebcdca94716ec3036c38a8d66f50.zip | |
Auto merge of #143254 - matthiaskrgr:rollup-7x8bxek, r=matthiaskrgr
Rollup of 9 pull requests Successful merges: - rust-lang/rust#143019 (Ensure -V --verbose processes both codegen_backend and codegen-backend) - rust-lang/rust#143140 (give Pointer::into_parts a more scary name and offer a safer alternative) - rust-lang/rust#143175 (Make combining LLD with external LLVM config a hard error) - rust-lang/rust#143180 (Use `tracing-forest` instead of `tracing-tree` for bootstrap tracing) - rust-lang/rust#143223 (Improve macro stats printing) - rust-lang/rust#143228 (Handle build scripts better in `-Zmacro-stats` output.) - rust-lang/rust#143229 ([COMPILETEST-UNTANGLE 1/N] Move some some early config checks to the lib and move the compiletest binary) - rust-lang/rust#143246 (Subtree update of `rust-analyzer`) - rust-lang/rust#143248 (Update books) r? `@ghost` `@rustbot` modify labels: rollup
Diffstat (limited to 'src/tools/rust-analyzer/editors/code')
| -rw-r--r-- | src/tools/rust-analyzer/editors/code/package.json | 10 | ||||
| -rw-r--r-- | src/tools/rust-analyzer/editors/code/src/client.ts | 114 | ||||
| -rw-r--r-- | src/tools/rust-analyzer/editors/code/src/commands.ts | 4 | ||||
| -rw-r--r-- | src/tools/rust-analyzer/editors/code/src/main.ts | 2 | ||||
| -rw-r--r-- | src/tools/rust-analyzer/editors/code/src/run.ts | 57 |
5 files changed, 129 insertions, 58 deletions
diff --git a/src/tools/rust-analyzer/editors/code/package.json b/src/tools/rust-analyzer/editors/code/package.json index 26a21c1468d..3cb4c21ee1f 100644 --- a/src/tools/rust-analyzer/editors/code/package.json +++ b/src/tools/rust-analyzer/editors/code/package.json @@ -1532,6 +1532,16 @@ { "title": "highlightRelated", "properties": { + "rust-analyzer.highlightRelated.branchExitPoints.enable": { + "markdownDescription": "Enables highlighting of related return values while the cursor is on any `match`, `if`, or match arm arrow (`=>`).", + "default": true, + "type": "boolean" + } + } + }, + { + "title": "highlightRelated", + "properties": { "rust-analyzer.highlightRelated.breakPoints.enable": { "markdownDescription": "Enables highlighting of related references while the cursor is on `break`, `loop`, `while`, or `for` keywords.", "default": true, diff --git a/src/tools/rust-analyzer/editors/code/src/client.ts b/src/tools/rust-analyzer/editors/code/src/client.ts index cdeea7333a6..073ff2f4703 100644 --- a/src/tools/rust-analyzer/editors/code/src/client.ts +++ b/src/tools/rust-analyzer/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)}`, ); } diff --git a/src/tools/rust-analyzer/editors/code/src/commands.ts b/src/tools/rust-analyzer/editors/code/src/commands.ts index 3ac1a933d9e..25b30013fa1 100644 --- a/src/tools/rust-analyzer/editors/code/src/commands.ts +++ b/src/tools/rust-analyzer/editors/code/src/commands.ts @@ -1114,11 +1114,11 @@ export function applySnippetWorkspaceEditCommand(_ctx: CtxInit): Cmd { }; } -export function run(ctx: CtxInit): Cmd { +export function run(ctx: CtxInit, mode?: "cursor"): Cmd { let prevRunnable: RunnableQuickPick | undefined; return async () => { - const item = await selectRunnable(ctx, prevRunnable); + const item = await selectRunnable(ctx, prevRunnable, false, true, mode); if (!item) return; item.detail = "rerun"; diff --git a/src/tools/rust-analyzer/editors/code/src/main.ts b/src/tools/rust-analyzer/editors/code/src/main.ts index 5e500730693..996298524f1 100644 --- a/src/tools/rust-analyzer/editors/code/src/main.ts +++ b/src/tools/rust-analyzer/editors/code/src/main.ts @@ -167,7 +167,7 @@ function createCommands(): Record<string, CommandFactory> { viewCrateGraph: { enabled: commands.viewCrateGraph }, viewFullCrateGraph: { enabled: commands.viewFullCrateGraph }, expandMacro: { enabled: commands.expandMacro }, - run: { enabled: commands.run }, + run: { enabled: (ctx) => (mode?: "cursor") => commands.run(ctx, mode)() }, copyRunCommandLine: { enabled: commands.copyRunCommandLine }, debug: { enabled: commands.debug }, newDebugConfig: { enabled: commands.newDebugConfig }, diff --git a/src/tools/rust-analyzer/editors/code/src/run.ts b/src/tools/rust-analyzer/editors/code/src/run.ts index 40027cc7c85..95166c427b2 100644 --- a/src/tools/rust-analyzer/editors/code/src/run.ts +++ b/src/tools/rust-analyzer/editors/code/src/run.ts @@ -18,10 +18,15 @@ export async function selectRunnable( prevRunnable?: RunnableQuickPick, debuggeeOnly = false, showButtons: boolean = true, + mode?: "cursor", ): Promise<RunnableQuickPick | undefined> { const editor = ctx.activeRustEditor ?? ctx.activeCargoTomlEditor; if (!editor) return; + if (mode === "cursor") { + return selectRunnableAtCursor(ctx, editor, prevRunnable); + } + // show a placeholder while we get the runnables from the server const quickPick = vscode.window.createQuickPick(); quickPick.title = "Select Runnable"; @@ -54,6 +59,58 @@ export async function selectRunnable( ); } +async function selectRunnableAtCursor( + ctx: CtxInit, + editor: RustEditor, + prevRunnable?: RunnableQuickPick, +): Promise<RunnableQuickPick | undefined> { + const runnableQuickPicks = await getRunnables(ctx.client, editor, prevRunnable, false); + let runnableQuickPickAtCursor = null; + const cursorPosition = ctx.client.code2ProtocolConverter.asPosition(editor.selection.active); + for (const runnableQuickPick of runnableQuickPicks) { + if (!runnableQuickPick.runnable.location?.targetRange) { + continue; + } + const runnableQuickPickRange = runnableQuickPick.runnable.location.targetRange; + if ( + runnableQuickPickAtCursor?.runnable?.location?.targetRange != null && + rangeContainsOtherRange( + runnableQuickPickRange, + runnableQuickPickAtCursor.runnable.location.targetRange, + ) + ) { + continue; + } + if (rangeContainsPosition(runnableQuickPickRange, cursorPosition)) { + runnableQuickPickAtCursor = runnableQuickPick; + } + } + if (runnableQuickPickAtCursor == null) { + return; + } + return Promise.resolve(runnableQuickPickAtCursor); +} + +function rangeContainsPosition(range: lc.Range, position: lc.Position): boolean { + return ( + (position.line > range.start.line || + (position.line === range.start.line && position.character >= range.start.character)) && + (position.line < range.end.line || + (position.line === range.end.line && position.character <= range.end.character)) + ); +} + +function rangeContainsOtherRange(range: lc.Range, otherRange: lc.Range) { + return ( + (range.start.line < otherRange.start.line || + (range.start.line === otherRange.start.line && + range.start.character <= otherRange.start.character)) && + (range.end.line > otherRange.end.line || + (range.end.line === otherRange.end.line && + range.end.character >= otherRange.end.character)) + ); +} + export class RunnableQuickPick implements vscode.QuickPickItem { public label: string; public description?: string | undefined; |
