@@ -7,21 +7,15 @@ import { Cargo } from "./toolchain";
7
7
import type { Ctx } from "./ctx" ;
8
8
import { prepareEnv } from "./run" ;
9
9
import { execute , isCargoRunnableArgs , unwrapUndefinable } from "./util" ;
10
+ import type { Config } from "./config" ;
10
11
11
12
const 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 ;
19
13
20
14
export async function makeDebugConfig ( ctx : Ctx , runnable : ra . Runnable ) : Promise < void > {
21
15
const scope = ctx . activeRustEditor ?. document . uri ;
22
16
if ( ! scope ) return ;
23
17
24
- const debugConfig = await getDebugConfiguration ( ctx , runnable ) ;
18
+ const debugConfig = await getDebugConfiguration ( ctx . config , runnable , false ) ;
25
19
if ( ! debugConfig ) return ;
26
20
27
21
const wsLaunchSection = vscode . workspace . getConfiguration ( "launch" , scope ) ;
@@ -57,7 +51,7 @@ export async function startDebugSession(ctx: Ctx, runnable: ra.Runnable): Promis
57
51
message = " (from launch.json)" ;
58
52
debugOutput . clear ( ) ;
59
53
} else {
60
- debugConfig = await getDebugConfiguration ( ctx , runnable ) ;
54
+ debugConfig = await getDebugConfiguration ( ctx . config , runnable ) ;
61
55
}
62
56
63
57
if ( ! debugConfig ) return false ;
@@ -74,35 +68,35 @@ function createCommandLink(extensionId: string): string {
74
68
}
75
69
76
70
async function getDebugConfiguration (
77
- ctx : Ctx ,
71
+ config : Config ,
78
72
runnable : ra . Runnable ,
73
+ inheritEnv : boolean = true ,
79
74
) : Promise < vscode . DebugConfiguration | undefined > {
80
75
if ( ! isCargoRunnableArgs ( runnable . args ) ) {
81
76
return ;
82
77
}
83
78
const runnableArgs : ra . CargoRunnableArgs = runnable . args ;
84
79
85
- const editor = ctx . activeRustEditor ;
86
- if ( ! editor ) return ;
80
+ const debugOptions = config . debug ;
87
81
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 ;
94
83
95
- let debugEngine = null ;
96
84
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
+ }
100
91
}
101
92
} 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
+ }
103
97
}
104
98
105
- if ( ! debugEngine ) {
99
+ if ( ! provider ) {
106
100
const commandCCpp : string = createCommandLink ( "ms-vscode.cpptools" ) ;
107
101
const commandCodeLLDB : string = createCommandLink ( "vadimcn.vscode-lldb" ) ;
108
102
const commandNativeDebug : string = createCommandLink ( "webfreak.debug" ) ;
@@ -116,7 +110,7 @@ async function getDebugConfiguration(
116
110
}
117
111
118
112
debugOutput . clear ( ) ;
119
- if ( ctx . config . debug . openDebugPane ) {
113
+ if ( config . debug . openDebugPane ) {
120
114
debugOutput . show ( true ) ;
121
115
}
122
116
// folder exists or RA is not active.
@@ -131,37 +125,36 @@ async function getDebugConfiguration(
131
125
firstWorkspace ;
132
126
133
127
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
+
135
134
const workspaceQualifier = isMultiFolderWorkspace ? `:${ workspace . name } ` : "" ;
136
135
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
+ }
137
140
// see https://github.com/rust-lang/rust-analyzer/pull/5513#issuecomment-663458818 for why this is needed
138
141
return path . normalize ( p ) . replace ( wsFolder , `\${workspaceFolder${ workspaceQualifier } }` ) ;
139
142
}
140
143
141
- const env = prepareEnv ( runnable . label , runnableArgs , ctx . config . runnablesExtraEnv ) ;
144
+ const env = prepareEnv ( inheritEnv , runnable . label , runnableArgs , config . runnablesExtraEnv ) ;
142
145
const executable = await getDebugExecutable ( runnableArgs , env ) ;
143
146
let sourceFileMap = debugOptions . sourceFileMap ;
144
147
if ( sourceFileMap === "auto" ) {
145
148
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 ) ;
158
150
}
159
151
160
- const provider = unwrapUndefinable ( knownEngines [ debugEngine . id ] ) ;
161
- const debugConfig = provider (
152
+ const debugConfig = getDebugConfig (
153
+ provider ,
154
+ simplifyPath ,
162
155
runnable ,
163
156
runnableArgs ,
164
- simplifyPath ( executable ) ,
157
+ executable ,
165
158
env ,
166
159
sourceFileMap ,
167
160
) ;
@@ -186,6 +179,92 @@ async function getDebugConfiguration(
186
179
return debugConfig ;
187
180
}
188
181
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
+
189
268
async function getDebugExecutable (
190
269
runnableArgs : ra . CargoRunnableArgs ,
191
270
env : Record < string , string > ,
@@ -197,71 +276,74 @@ async function getDebugExecutable(
197
276
return executable ;
198
277
}
199
278
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
+ } ;
225
285
226
- function getCodeLldbDebugConfig (
286
+ function getDebugConfig (
287
+ provider : KnownEnginesType ,
288
+ simplifyPath : ( p : string ) => string ,
227
289
runnable : ra . Runnable ,
228
290
runnableArgs : ra . CargoRunnableArgs ,
229
291
executable : string ,
230
292
env : Record < string , string > ,
231
293
sourceFileMap ?: Record < string , string > ,
232
294
) : 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 ) ;
233
305
return {
234
- type : "lldb" ,
306
+ type,
235
307
request : "launch" ,
236
308
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 ,
243
315
} ;
244
316
}
245
317
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" ;
263
329
} ;
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" > ;
265
347
266
348
// Based on https://github.com/ljharb/shell-quote/blob/main/quote.js
267
349
function quote ( xs : string [ ] ) {
0 commit comments