Skip to content

Building before a debugging session was restarted #17923

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions editors/code/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -520,6 +520,11 @@
"type": "boolean",
"default": false
},
"rust-analyzer.debug.buildBeforeRestart": {
"markdownDescription": "Whether to rebuild the project modules before debugging the same test again",
"type": "boolean",
"default": false
},
"rust-analyzer.debug.engineSettings": {
"type": "object",
"default": {},
Expand Down
1 change: 1 addition & 0 deletions editors/code/src/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -303,6 +303,7 @@ export class Config {
engine: this.get<string>("debug.engine"),
engineSettings: this.get<object>("debug.engineSettings") ?? {},
openDebugPane: this.get<boolean>("debug.openDebugPane"),
buildBeforeRestart: this.get<boolean>("debug.buildBeforeRestart"),
sourceFileMap: sourceFileMap,
};
}
Expand Down
53 changes: 52 additions & 1 deletion editors/code/src/debug.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,15 @@ import type * as ra from "./lsp_ext";

import { Cargo } from "./toolchain";
import type { Ctx } from "./ctx";
import { prepareEnv } from "./run";
import { createTaskFromRunnable, prepareEnv } from "./run";
import { execute, isCargoRunnableArgs, unwrapUndefinable } from "./util";
import type { Config } from "./config";

const debugOutput = vscode.window.createOutputChannel("Debug");

// Here we want to keep track on everything that's currently running
const activeDebugSessionIds: string[] = [];

export async function makeDebugConfig(ctx: Ctx, runnable: ra.Runnable): Promise<void> {
const scope = ctx.activeRustEditor?.document.uri;
if (!scope) return;
Expand Down Expand Up @@ -45,6 +48,8 @@ export async function startDebugSession(ctx: Ctx, runnable: ra.Runnable): Promis
const wsLaunchSection = vscode.workspace.getConfiguration("launch");
const configurations = wsLaunchSection.get<any[]>("configurations") || [];

// The runnable label is the name of the test with the "test prefix"
// e.g. test test_feature_x
const index = configurations.findIndex((c) => c.name === runnable.label);
if (-1 !== index) {
debugConfig = configurations[index];
Expand Down Expand Up @@ -359,3 +364,49 @@ function quote(xs: string[]) {
})
.join(" ");
}

async function recompileTestFromDebuggingSession(session: vscode.DebugSession, ctx: Ctx) {
const { cwd, args: sessionArgs }: vscode.DebugConfiguration = session.configuration;

const args: ra.CargoRunnableArgs = {
cwd: cwd,
cargoArgs: ["test", "--no-run", "--test", "lib"],

// The first element of the debug configuration args is the test path e.g. "test_bar::foo::test_a::test_b"
executableArgs: sessionArgs,
};
const runnable: ra.Runnable = {
kind: "cargo",
label: "compile-test",
args,
};
const task: vscode.Task = await createTaskFromRunnable(runnable, ctx.config);

// It is not needed to call the language server, since the test path is already resolved in the
// configuration option. We can simply call a debug configuration with the --no-run option to compile
await vscode.tasks.executeTask(task);
}

export function initializeDebugSessionTrackingAndRebuild(ctx: Ctx) {
vscode.debug.onDidStartDebugSession((session: vscode.DebugSession) => {
if (!activeDebugSessionIds.includes(session.id)) {
activeDebugSessionIds.push(session.id);
}
});

vscode.debug.onDidTerminateDebugSession(async (session: vscode.DebugSession) => {
// The id of the session will be the same when pressing restart the restart button
if (activeDebugSessionIds.find((s) => s === session.id)) {
await recompileTestFromDebuggingSession(session, ctx);
}
removeActiveSession(session);
});
}

function removeActiveSession(session: vscode.DebugSession) {
const activeSessionId = activeDebugSessionIds.findIndex((id) => id === session.id);

if (activeSessionId !== -1) {
activeDebugSessionIds.splice(activeSessionId, 1);
}
}
5 changes: 5 additions & 0 deletions editors/code/src/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import { type CommandFactory, Ctx, fetchWorkspace } from "./ctx";
import * as diagnostics from "./diagnostics";
import { activateTaskProvider } from "./tasks";
import { setContextValue } from "./util";
import { initializeDebugSessionTrackingAndRebuild } from "./debug";

const RUST_PROJECT_CONTEXT_NAME = "inRustProject";

Expand Down Expand Up @@ -102,6 +103,10 @@ async function activateServer(ctx: Ctx): Promise<RustAnalyzerExtensionApi> {
ctx.subscriptions,
);

if (ctx.config.debug.buildBeforeRestart) {
initializeDebugSessionTrackingAndRebuild(ctx);
}

await ctx.start();
return ctx;
}
Expand Down