mirror of
https://github.com/rust-lang/rust-analyzer
synced 2025-01-14 14:13:58 +00:00
Auto merge of #17923 - basvandriel:feature/build-before-restart-debug, r=Veykril
Building before a debugging session was restarted # Background Resolves #17901. It adds support for rebuilding after debugging a test was restarted. This means the test doesn't have to be aborted and manually re-ran again. # How this is tested First, all the Visual Studio Code extensions are loaded into an Extension Host window. Then, a sample test like below was ran and restarted to see if it was correctly rebuild. ```rust #[test] fn test_x() { assert_eq!("1.1.1", "1.1.0"); } ```
This commit is contained in:
commit
62649a57be
4 changed files with 63 additions and 1 deletions
|
@ -512,6 +512,11 @@
|
||||||
"type": "boolean",
|
"type": "boolean",
|
||||||
"default": false
|
"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": {
|
"rust-analyzer.debug.engineSettings": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"default": {},
|
"default": {},
|
||||||
|
|
|
@ -299,6 +299,7 @@ export class Config {
|
||||||
engine: this.get<string>("debug.engine"),
|
engine: this.get<string>("debug.engine"),
|
||||||
engineSettings: this.get<object>("debug.engineSettings") ?? {},
|
engineSettings: this.get<object>("debug.engineSettings") ?? {},
|
||||||
openDebugPane: this.get<boolean>("debug.openDebugPane"),
|
openDebugPane: this.get<boolean>("debug.openDebugPane"),
|
||||||
|
buildBeforeRestart: this.get<boolean>("debug.buildBeforeRestart"),
|
||||||
sourceFileMap: sourceFileMap,
|
sourceFileMap: sourceFileMap,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,12 +5,15 @@ import type * as ra from "./lsp_ext";
|
||||||
|
|
||||||
import { Cargo } from "./toolchain";
|
import { Cargo } from "./toolchain";
|
||||||
import type { Ctx } from "./ctx";
|
import type { Ctx } from "./ctx";
|
||||||
import { prepareEnv } from "./run";
|
import { createTaskFromRunnable, prepareEnv } from "./run";
|
||||||
import { execute, isCargoRunnableArgs, unwrapUndefinable } from "./util";
|
import { execute, isCargoRunnableArgs, unwrapUndefinable } from "./util";
|
||||||
import type { Config } from "./config";
|
import type { Config } from "./config";
|
||||||
|
|
||||||
const debugOutput = vscode.window.createOutputChannel("Debug");
|
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> {
|
export async function makeDebugConfig(ctx: Ctx, runnable: ra.Runnable): Promise<void> {
|
||||||
const scope = ctx.activeRustEditor?.document.uri;
|
const scope = ctx.activeRustEditor?.document.uri;
|
||||||
if (!scope) return;
|
if (!scope) return;
|
||||||
|
@ -45,6 +48,8 @@ export async function startDebugSession(ctx: Ctx, runnable: ra.Runnable): Promis
|
||||||
const wsLaunchSection = vscode.workspace.getConfiguration("launch");
|
const wsLaunchSection = vscode.workspace.getConfiguration("launch");
|
||||||
const configurations = wsLaunchSection.get<any[]>("configurations") || [];
|
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);
|
const index = configurations.findIndex((c) => c.name === runnable.label);
|
||||||
if (-1 !== index) {
|
if (-1 !== index) {
|
||||||
debugConfig = configurations[index];
|
debugConfig = configurations[index];
|
||||||
|
@ -359,3 +364,49 @@ function quote(xs: string[]) {
|
||||||
})
|
})
|
||||||
.join(" ");
|
.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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -6,6 +6,7 @@ import { type CommandFactory, Ctx, fetchWorkspace } from "./ctx";
|
||||||
import * as diagnostics from "./diagnostics";
|
import * as diagnostics from "./diagnostics";
|
||||||
import { activateTaskProvider } from "./tasks";
|
import { activateTaskProvider } from "./tasks";
|
||||||
import { setContextValue } from "./util";
|
import { setContextValue } from "./util";
|
||||||
|
import { initializeDebugSessionTrackingAndRebuild } from "./debug";
|
||||||
|
|
||||||
const RUST_PROJECT_CONTEXT_NAME = "inRustProject";
|
const RUST_PROJECT_CONTEXT_NAME = "inRustProject";
|
||||||
|
|
||||||
|
@ -102,6 +103,10 @@ async function activateServer(ctx: Ctx): Promise<RustAnalyzerExtensionApi> {
|
||||||
ctx.subscriptions,
|
ctx.subscriptions,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
if (ctx.config.debug.buildBeforeRestart) {
|
||||||
|
initializeDebugSessionTrackingAndRebuild(ctx);
|
||||||
|
}
|
||||||
|
|
||||||
await ctx.start();
|
await ctx.start();
|
||||||
return ctx;
|
return ctx;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue