@@ -7,21 +7,15 @@ import { Cargo } from "./toolchain";
77import type { Ctx } from "./ctx" ;
88import { prepareEnv } from "./run" ;
99import { execute , isCargoRunnableArgs , unwrapUndefinable } from "./util" ;
10+ import type { Config } from "./config" ;
1011
1112const debugOutput = vscode . window . createOutputChannel ( "Debug" ) ;
12- type DebugConfigProvider = (
13- runnable : ra . Runnable ,
14- runnableArgs : ra . CargoRunnableArgs ,
15- executable : string ,
16- env : Record < string , string > ,
17- sourceFileMap ?: Record < string , string > ,
18- ) => vscode . DebugConfiguration ;
1913
2014export async function makeDebugConfig ( ctx : Ctx , runnable : ra . Runnable ) : Promise < void > {
2115 const scope = ctx . activeRustEditor ?. document . uri ;
2216 if ( ! scope ) return ;
2317
24- const debugConfig = await getDebugConfiguration ( ctx , runnable ) ;
18+ const debugConfig = await getDebugConfiguration ( ctx . config , runnable , false ) ;
2519 if ( ! debugConfig ) return ;
2620
2721 const wsLaunchSection = vscode . workspace . getConfiguration ( "launch" , scope ) ;
@@ -57,7 +51,7 @@ export async function startDebugSession(ctx: Ctx, runnable: ra.Runnable): Promis
5751 message = " (from launch.json)" ;
5852 debugOutput . clear ( ) ;
5953 } else {
60- debugConfig = await getDebugConfiguration ( ctx , runnable ) ;
54+ debugConfig = await getDebugConfiguration ( ctx . config , runnable ) ;
6155 }
6256
6357 if ( ! debugConfig ) return false ;
@@ -74,35 +68,35 @@ function createCommandLink(extensionId: string): string {
7468}
7569
7670async function getDebugConfiguration (
77- ctx : Ctx ,
71+ config : Config ,
7872 runnable : ra . Runnable ,
73+ inheritEnv : boolean = true ,
7974) : Promise < vscode . DebugConfiguration | undefined > {
8075 if ( ! isCargoRunnableArgs ( runnable . args ) ) {
8176 return ;
8277 }
8378 const runnableArgs : ra . CargoRunnableArgs = runnable . args ;
8479
85- const editor = ctx . activeRustEditor ;
86- if ( ! editor ) return ;
80+ const debugOptions = config . debug ;
8781
88- const knownEngines : Record < string , DebugConfigProvider > = {
89- "vadimcn.vscode-lldb" : getCodeLldbDebugConfig ,
90- "ms-vscode.cpptools" : getCCppDebugConfig ,
91- "webfreak.debug" : getNativeDebugConfig ,
92- } ;
93- const debugOptions = ctx . config . debug ;
82+ let provider : null | KnownEnginesType = null ;
9483
95- let debugEngine = null ;
9684 if ( debugOptions . engine === "auto" ) {
97- for ( var engineId in knownEngines ) {
98- debugEngine = vscode . extensions . getExtension ( engineId ) ;
99- if ( debugEngine ) break ;
85+ for ( const engineId in knownEngines ) {
86+ const debugEngine = vscode . extensions . getExtension ( engineId ) ;
87+ if ( debugEngine ) {
88+ provider = knownEngines [ engineId as keyof typeof knownEngines ] ;
89+ break ;
90+ }
10091 }
10192 } else if ( debugOptions . engine ) {
102- debugEngine = vscode . extensions . getExtension ( debugOptions . engine ) ;
93+ const debugEngine = vscode . extensions . getExtension ( debugOptions . engine ) ;
94+ if ( debugEngine && Object . keys ( knownEngines ) . includes ( debugOptions . engine ) ) {
95+ provider = knownEngines [ debugOptions . engine as keyof typeof knownEngines ] ;
96+ }
10397 }
10498
105- if ( ! debugEngine ) {
99+ if ( ! provider ) {
106100 const commandCCpp : string = createCommandLink ( "ms-vscode.cpptools" ) ;
107101 const commandCodeLLDB : string = createCommandLink ( "vadimcn.vscode-lldb" ) ;
108102 const commandNativeDebug : string = createCommandLink ( "webfreak.debug" ) ;
@@ -116,7 +110,7 @@ async function getDebugConfiguration(
116110 }
117111
118112 debugOutput . clear ( ) ;
119- if ( ctx . config . debug . openDebugPane ) {
113+ if ( config . debug . openDebugPane ) {
120114 debugOutput . show ( true ) ;
121115 }
122116 // folder exists or RA is not active.
@@ -131,37 +125,36 @@ async function getDebugConfiguration(
131125 firstWorkspace ;
132126
133127 const workspace = unwrapUndefinable ( maybeWorkspace ) ;
134- const wsFolder = path . normalize ( workspace . uri . fsPath ) ;
128+ let wsFolder = path . normalize ( workspace . uri . fsPath ) ;
129+ if ( os . platform ( ) === "win32" ) {
130+ // in windows, the drive letter can vary in casing for VSCode, so we gotta normalize that first
131+ wsFolder = wsFolder . replace ( / ^ [ a - z ] : \\ / , ( c ) => c . toUpperCase ( ) ) ;
132+ }
133+
135134 const workspaceQualifier = isMultiFolderWorkspace ? `:${ workspace . name } ` : "" ;
136135 function simplifyPath ( p : string ) : string {
136+ // in windows, the drive letter can vary in casing for VSCode, so we gotta normalize that first
137+ if ( os . platform ( ) === "win32" ) {
138+ p = p . replace ( / ^ [ a - z ] : \\ / , ( c ) => c . toUpperCase ( ) ) ;
139+ }
137140 // see https://github.com/rust-lang/rust-analyzer/pull/5513#issuecomment-663458818 for why this is needed
138141 return path . normalize ( p ) . replace ( wsFolder , `\${workspaceFolder${ workspaceQualifier } }` ) ;
139142 }
140143
141- const env = prepareEnv ( runnable . label , runnableArgs , ctx . config . runnablesExtraEnv ) ;
144+ const env = prepareEnv ( inheritEnv , runnable . label , runnableArgs , config . runnablesExtraEnv ) ;
142145 const executable = await getDebugExecutable ( runnableArgs , env ) ;
143146 let sourceFileMap = debugOptions . sourceFileMap ;
144147 if ( sourceFileMap === "auto" ) {
145148 sourceFileMap = { } ;
146- const sysroot = env [ "RUSTC_TOOLCHAIN" ] ;
147- if ( sysroot ) {
148- // let's try to use the default toolchain
149- const data = await execute ( `rustc -V -v` , { cwd : wsFolder , env } ) ;
150- const rx = / c o m m i t - h a s h : \s ( .* ) $ / m;
151-
152- const commitHash = rx . exec ( data ) ?. [ 1 ] ;
153- if ( commitHash ) {
154- const rustlib = path . normalize ( sysroot + "/lib/rustlib/src/rust" ) ;
155- sourceFileMap [ `/rustc/${ commitHash } /` ] = rustlib ;
156- }
157- }
149+ await discoverSourceFileMap ( sourceFileMap , env , wsFolder ) ;
158150 }
159151
160- const provider = unwrapUndefinable ( knownEngines [ debugEngine . id ] ) ;
161- const debugConfig = provider (
152+ const debugConfig = getDebugConfig (
153+ provider ,
154+ simplifyPath ,
162155 runnable ,
163156 runnableArgs ,
164- simplifyPath ( executable ) ,
157+ executable ,
165158 env ,
166159 sourceFileMap ,
167160 ) ;
@@ -186,6 +179,92 @@ async function getDebugConfiguration(
186179 return debugConfig ;
187180}
188181
182+ async function discoverSourceFileMap (
183+ sourceFileMap : Record < string , string > ,
184+ env : Record < string , string > ,
185+ cwd : string ,
186+ ) {
187+ const sysroot = env [ "RUSTC_TOOLCHAIN" ] ;
188+ if ( sysroot ) {
189+ // let's try to use the default toolchain
190+ const data = await execute ( `rustc -V -v` , { cwd, env } ) ;
191+ const rx = / c o m m i t - h a s h : \s ( .* ) $ / m;
192+
193+ const commitHash = rx . exec ( data ) ?. [ 1 ] ;
194+ if ( commitHash ) {
195+ const rustlib = path . normalize ( sysroot + "/lib/rustlib/src/rust" ) ;
196+ sourceFileMap [ `/rustc/${ commitHash } /` ] = rustlib ;
197+ }
198+ }
199+ }
200+
201+ type PropertyFetcher < Config , Input , Key extends keyof Config > = (
202+ input : Input ,
203+ ) => [ Key , Config [ Key ] ] ;
204+
205+ type DebugConfigProvider < Type extends string , DebugConfig extends BaseDebugConfig < Type > > = {
206+ executableProperty : keyof DebugConfig ;
207+ environmentProperty : PropertyFetcher < DebugConfig , Record < string , string > , keyof DebugConfig > ;
208+ runnableArgsProperty : PropertyFetcher < DebugConfig , ra . CargoRunnableArgs , keyof DebugConfig > ;
209+ sourceFileMapProperty ?: keyof DebugConfig ;
210+ type : Type ;
211+ additional ?: Record < string , unknown > ;
212+ } ;
213+
214+ type KnownEnginesType = ( typeof knownEngines ) [ keyof typeof knownEngines ] ;
215+ const knownEngines : {
216+ "vadimcn.vscode-lldb" : DebugConfigProvider < "lldb" , CodeLldbDebugConfig > ;
217+ "ms-vscode.cpptools" : DebugConfigProvider < "cppvsdbg" | "cppdbg" , CCppDebugConfig > ;
218+ "webfreak.debug" : DebugConfigProvider < "gdb" , NativeDebugConfig > ;
219+ } = {
220+ "vadimcn.vscode-lldb" : {
221+ type : "lldb" ,
222+ executableProperty : "program" ,
223+ environmentProperty : ( env ) => [ "env" , env ] ,
224+ runnableArgsProperty : ( runnableArgs : ra . CargoRunnableArgs ) => [
225+ "args" ,
226+ runnableArgs . executableArgs ,
227+ ] ,
228+ sourceFileMapProperty : "sourceMap" ,
229+ additional : {
230+ sourceLanguages : [ "rust" ] ,
231+ } ,
232+ } ,
233+ "ms-vscode.cpptools" : {
234+ type : os . platform ( ) === "win32" ? "cppvsdbg" : "cppdbg" ,
235+ executableProperty : "program" ,
236+ environmentProperty : ( env ) => [
237+ "environment" ,
238+ Object . entries ( env ) . map ( ( entry ) => ( {
239+ name : entry [ 0 ] ,
240+ value : entry [ 1 ] ,
241+ } ) ) ,
242+ ] ,
243+ runnableArgsProperty : ( runnableArgs : ra . CargoRunnableArgs ) => [
244+ "args" ,
245+ runnableArgs . executableArgs ,
246+ ] ,
247+ sourceFileMapProperty : "sourceFileMap" ,
248+ additional : {
249+ osx : {
250+ MIMode : "lldb" ,
251+ } ,
252+ } ,
253+ } ,
254+ "webfreak.debug" : {
255+ type : "gdb" ,
256+ executableProperty : "target" ,
257+ runnableArgsProperty : ( runnableArgs : ra . CargoRunnableArgs ) => [
258+ "arguments" ,
259+ quote ( runnableArgs . executableArgs ) ,
260+ ] ,
261+ environmentProperty : ( env ) => [ "env" , env ] ,
262+ additional : {
263+ valuesFormatting : "prettyPrinters" ,
264+ } ,
265+ } ,
266+ } ;
267+
189268async function getDebugExecutable (
190269 runnableArgs : ra . CargoRunnableArgs ,
191270 env : Record < string , string > ,
@@ -197,71 +276,74 @@ async function getDebugExecutable(
197276 return executable ;
198277}
199278
200- function getCCppDebugConfig (
201- runnable : ra . Runnable ,
202- runnableArgs : ra . CargoRunnableArgs ,
203- executable : string ,
204- env : Record < string , string > ,
205- sourceFileMap ?: Record < string , string > ,
206- ) : vscode . DebugConfiguration {
207- return {
208- type : os . platform ( ) === "win32" ? "cppvsdbg" : "cppdbg" ,
209- request : "launch" ,
210- name : runnable . label ,
211- program : executable ,
212- args : runnableArgs . executableArgs ,
213- cwd : runnable . args . cwd || runnableArgs . workspaceRoot || "." ,
214- sourceFileMap,
215- environment : Object . entries ( env ) . map ( ( entry ) => ( {
216- name : entry [ 0 ] ,
217- value : entry [ 1 ] ,
218- } ) ) ,
219- // See https://github.com/rust-lang/rust-analyzer/issues/16901#issuecomment-2024486941
220- osx : {
221- MIMode : "lldb" ,
222- } ,
223- } ;
224- }
279+ type BaseDebugConfig < type extends string > = {
280+ type : type ;
281+ request : "launch" ;
282+ name : string ;
283+ cwd : string ;
284+ } ;
225285
226- function getCodeLldbDebugConfig (
286+ function getDebugConfig (
287+ provider : KnownEnginesType ,
288+ simplifyPath : ( p : string ) => string ,
227289 runnable : ra . Runnable ,
228290 runnableArgs : ra . CargoRunnableArgs ,
229291 executable : string ,
230292 env : Record < string , string > ,
231293 sourceFileMap ?: Record < string , string > ,
232294) : vscode . DebugConfiguration {
295+ const {
296+ environmentProperty,
297+ executableProperty,
298+ runnableArgsProperty,
299+ type,
300+ additional,
301+ sourceFileMapProperty,
302+ } = provider ;
303+ const [ envProperty , envValue ] = environmentProperty ( env ) ;
304+ const [ argsProperty , argsValue ] = runnableArgsProperty ( runnableArgs ) ;
233305 return {
234- type : "lldb" ,
306+ type,
235307 request : "launch" ,
236308 name : runnable . label ,
237- program : executable ,
238- args : runnableArgs . executableArgs ,
239- cwd : runnable . args . cwd || runnableArgs . workspaceRoot || "." ,
240- sourceMap : sourceFileMap ,
241- sourceLanguages : [ "rust" ] ,
242- env ,
309+ cwd : simplifyPath ( runnable . args . cwd || runnableArgs . workspaceRoot || "." ) ,
310+ [ executableProperty ] : simplifyPath ( executable ) ,
311+ [ envProperty ] : envValue ,
312+ [ argsProperty ] : argsValue ,
313+ ... ( sourceFileMapProperty ? { [ sourceFileMapProperty ] : sourceFileMap } : { } ) ,
314+ ... additional ,
243315 } ;
244316}
245317
246- function getNativeDebugConfig (
247- runnable : ra . Runnable ,
248- runnableArgs : ra . CargoRunnableArgs ,
249- executable : string ,
250- env : Record < string , string > ,
251- _sourceFileMap ?: Record < string , string > ,
252- ) : vscode . DebugConfiguration {
253- return {
254- type : "gdb" ,
255- request : "launch" ,
256- name : runnable . label ,
257- target : executable ,
258- // See https://github.com/WebFreak001/code-debug/issues/359
259- arguments : quote ( runnableArgs . executableArgs ) ,
260- cwd : runnable . args . cwd || runnableArgs . workspaceRoot || "." ,
261- env,
262- valuesFormatting : "prettyPrinters" ,
318+ type CCppDebugConfig = {
319+ program : string ;
320+ args : string [ ] ;
321+ sourceFileMap : Record < string , string > | undefined ;
322+ environment : {
323+ name : string ;
324+ value : string ;
325+ } [ ] ;
326+ // See https://github.com/rust-lang/rust-analyzer/issues/16901#issuecomment-2024486941
327+ osx : {
328+ MIMode : "lldb" ;
263329 } ;
264- }
330+ } & BaseDebugConfig < "cppvsdbg" | "cppdbg" > ;
331+
332+ type CodeLldbDebugConfig = {
333+ program : string ;
334+ args : string [ ] ;
335+ sourceMap : Record < string , string > | undefined ;
336+ sourceLanguages : [ "rust" ] ;
337+ env : Record < string , string > ;
338+ } & BaseDebugConfig < "lldb" > ;
339+
340+ type NativeDebugConfig = {
341+ target : string ;
342+ // See https://github.com/WebFreak001/code-debug/issues/359
343+ arguments : string ;
344+ env : Record < string , string > ;
345+ valuesFormatting : "prettyPrinters" ;
346+ } & BaseDebugConfig < "gdb" > ;
265347
266348// Based on https://github.com/ljharb/shell-quote/blob/main/quote.js
267349function quote ( xs : string [ ] ) {
0 commit comments