@@ -5,12 +5,15 @@ import type * as ra from "./lsp_ext";
55
66import { Cargo } from "./toolchain" ;
77import type { Ctx } from "./ctx" ;
8- import { prepareEnv } from "./run" ;
8+ import { createTaskFromRunnable , prepareEnv } from "./run" ;
99import { execute , isCargoRunnableArgs , unwrapUndefinable } from "./util" ;
1010import type { Config } from "./config" ;
1111
1212const debugOutput = vscode . window . createOutputChannel ( "Debug" ) ;
1313
14+ // Here we want to keep track on everything that's currently running
15+ const activeDebugSessionIds : string [ ] = [ ] ;
16+
1417export async function makeDebugConfig ( ctx : Ctx , runnable : ra . Runnable ) : Promise < void > {
1518 const scope = ctx . activeRustEditor ?. document . uri ;
1619 if ( ! scope ) return ;
@@ -45,6 +48,8 @@ export async function startDebugSession(ctx: Ctx, runnable: ra.Runnable): Promis
4548 const wsLaunchSection = vscode . workspace . getConfiguration ( "launch" ) ;
4649 const configurations = wsLaunchSection . get < any [ ] > ( "configurations" ) || [ ] ;
4750
51+ // The runnable label is the name of the test with the "test prefix"
52+ // e.g. test test_feature_x
4853 const index = configurations . findIndex ( ( c ) => c . name === runnable . label ) ;
4954 if ( - 1 !== index ) {
5055 debugConfig = configurations [ index ] ;
@@ -359,3 +364,49 @@ function quote(xs: string[]) {
359364 } )
360365 . join ( " " ) ;
361366}
367+
368+ async function recompileTestFromDebuggingSession ( session : vscode . DebugSession , ctx : Ctx ) {
369+ const { cwd, args : sessionArgs } : vscode . DebugConfiguration = session . configuration ;
370+
371+ const args : ra . CargoRunnableArgs = {
372+ cwd : cwd ,
373+ cargoArgs : [ "test" , "--no-run" , "--test" , "lib" ] ,
374+
375+ // The first element of the debug configuration args is the test path e.g. "test_bar::foo::test_a::test_b"
376+ executableArgs : sessionArgs ,
377+ } ;
378+ const runnable : ra . Runnable = {
379+ kind : "cargo" ,
380+ label : "compile-test" ,
381+ args,
382+ } ;
383+ const task : vscode . Task = await createTaskFromRunnable ( runnable , ctx . config ) ;
384+
385+ // It is not needed to call the language server, since the test path is already resolved in the
386+ // configuration option. We can simply call a debug configuration with the --no-run option to compile
387+ await vscode . tasks . executeTask ( task ) ;
388+ }
389+
390+ export function initializeDebugSessionTrackingAndRebuild ( ctx : Ctx ) {
391+ vscode . debug . onDidStartDebugSession ( ( session : vscode . DebugSession ) => {
392+ if ( ! activeDebugSessionIds . includes ( session . id ) ) {
393+ activeDebugSessionIds . push ( session . id ) ;
394+ }
395+ } ) ;
396+
397+ vscode . debug . onDidTerminateDebugSession ( async ( session : vscode . DebugSession ) => {
398+ // The id of the session will be the same when pressing restart the restart button
399+ if ( activeDebugSessionIds . find ( ( s ) => s === session . id ) ) {
400+ await recompileTestFromDebuggingSession ( session , ctx ) ;
401+ }
402+ removeActiveSession ( session ) ;
403+ } ) ;
404+ }
405+
406+ function removeActiveSession ( session : vscode . DebugSession ) {
407+ const activeSessionId = activeDebugSessionIds . findIndex ( ( id ) => id === session . id ) ;
408+
409+ if ( activeSessionId !== - 1 ) {
410+ activeDebugSessionIds . splice ( activeSessionId , 1 ) ;
411+ }
412+ }
0 commit comments