@@ -19,6 +19,9 @@ import { DebugAdapter, LaunchConfigType, SWIFT_LAUNCH_CONFIG_TYPE } from "./debu
19
19
import { registerLoggingDebugAdapterTracker } from "./logTracker" ;
20
20
import { SwiftToolchain } from "../toolchain/toolchain" ;
21
21
import { SwiftOutputChannel } from "../ui/SwiftOutputChannel" ;
22
+ import { fileExists } from "../utilities/filesystem" ;
23
+ import { getLLDBLibPath } from "./lldb" ;
24
+ import { getErrorDescription } from "../utilities/utilities" ;
22
25
23
26
/**
24
27
* Registers the active debugger with the extension, and reregisters it
@@ -27,35 +30,11 @@ import { SwiftOutputChannel } from "../ui/SwiftOutputChannel";
27
30
* @returns A disposable to be disposed when the extension is deactivated
28
31
*/
29
32
export function registerDebugger ( workspaceContext : WorkspaceContext ) : vscode . Disposable {
30
- async function updateDebugAdapter ( ) {
31
- await workspaceContext . setLLDBVersion ( ) ;
32
-
33
- // Verify that the adapter exists, but only after registration. This async method
34
- // is basically an unstructured task so we don't want to run it before the adapter
35
- // registration above as it could cause code executing immediately after register()
36
- // to use the incorrect adapter.
37
- DebugAdapter . verifyDebugAdapterExists (
38
- workspaceContext . toolchain ,
39
- workspaceContext . outputChannel ,
40
- true
41
- ) . catch ( error => {
42
- workspaceContext . outputChannel . log ( error ) ;
43
- } ) ;
44
- }
45
-
46
33
const subscriptions : vscode . Disposable [ ] = [
47
34
registerLoggingDebugAdapterTracker ( ) ,
48
35
registerLLDBDebugAdapter ( workspaceContext . toolchain , workspaceContext . outputChannel ) ,
49
- vscode . workspace . onDidChangeConfiguration ( event => {
50
- if ( event . affectsConfiguration ( "swift.debugger.useDebugAdapterFromToolchain" ) ) {
51
- updateDebugAdapter ( ) ;
52
- }
53
- } ) ,
54
36
] ;
55
37
56
- // Perform the initial registration, then reregister every time the settings change.
57
- updateDebugAdapter ( ) ;
58
-
59
38
return {
60
39
dispose : ( ) => {
61
40
subscriptions . map ( sub => sub . dispose ( ) ) ;
@@ -79,7 +58,7 @@ function registerLLDBDebugAdapter(
79
58
80
59
const debugConfigProvider = vscode . debug . registerDebugConfigurationProvider (
81
60
SWIFT_LAUNCH_CONFIG_TYPE ,
82
- new LLDBDebugConfigurationProvider ( process . platform , toolchain )
61
+ new LLDBDebugConfigurationProvider ( process . platform , toolchain , outputChannel )
83
62
) ;
84
63
85
64
return {
@@ -117,8 +96,7 @@ export class LLDBDebugAdapterExecutableFactory implements vscode.DebugAdapterDes
117
96
}
118
97
119
98
async createDebugAdapterDescriptor ( ) : Promise < vscode . DebugAdapterDescriptor > {
120
- const path = await DebugAdapter . debugAdapterPath ( this . toolchain ) ;
121
- await DebugAdapter . verifyDebugAdapterExists ( this . toolchain , this . outputChannel ) ;
99
+ const path = await DebugAdapter . getLLDBDebugAdapterPath ( this . toolchain ) ;
122
100
return new vscode . DebugAdapterExecutable ( path , [ ] , { } ) ;
123
101
}
124
102
}
@@ -135,7 +113,8 @@ export class LLDBDebugAdapterExecutableFactory implements vscode.DebugAdapterDes
135
113
export class LLDBDebugConfigurationProvider implements vscode . DebugConfigurationProvider {
136
114
constructor (
137
115
private platform : NodeJS . Platform ,
138
- private toolchain : SwiftToolchain
116
+ private toolchain : SwiftToolchain ,
117
+ private outputChannel : SwiftOutputChannel
139
118
) { }
140
119
141
120
async resolveDebugConfiguration (
@@ -155,15 +134,79 @@ export class LLDBDebugConfigurationProvider implements vscode.DebugConfiguration
155
134
launchConfig . type = DebugAdapter . getLaunchConfigType ( this . toolchain . swiftVersion ) ;
156
135
if ( launchConfig . type === LaunchConfigType . CODE_LLDB ) {
157
136
launchConfig . sourceLanguages = [ "swift" ] ;
137
+ // Prompt the user to update CodeLLDB settings if necessary
138
+ await this . promptForCodeLldbSettings ( ) ;
158
139
} else if ( launchConfig . type === LaunchConfigType . LLDB_DAP ) {
159
140
if ( launchConfig . env ) {
160
141
launchConfig . env = this . convertEnvironmentVariables ( launchConfig . env ) ;
161
142
}
143
+ const lldbDapPath = await DebugAdapter . getLLDBDebugAdapterPath ( this . toolchain ) ;
144
+ // Verify that the debug adapter exists or bail otherwise
145
+ if ( ! ( await fileExists ( lldbDapPath ) ) ) {
146
+ vscode . window . showErrorMessage (
147
+ `Cannot find the LLDB debug adapter in your Swift toolchain: No such file or directory "${ lldbDapPath } "`
148
+ ) ;
149
+ return undefined ;
150
+ }
162
151
}
163
152
164
153
return launchConfig ;
165
154
}
166
155
156
+ private async promptForCodeLldbSettings ( ) : Promise < void > {
157
+ const libLldbPathResult = await getLLDBLibPath ( this . toolchain ) ;
158
+ if ( ! libLldbPathResult . success ) {
159
+ const errorMessage = `Error: ${ getErrorDescription ( libLldbPathResult . failure ) } ` ;
160
+ vscode . window . showWarningMessage (
161
+ `Failed to setup CodeLLDB for debugging of Swift code. Debugging may produce unexpected results. ${ errorMessage } `
162
+ ) ;
163
+ this . outputChannel . log ( `Failed to setup CodeLLDB: ${ errorMessage } ` ) ;
164
+ return ;
165
+ }
166
+ const libLldbPath = libLldbPathResult . success ;
167
+ const lldbConfig = vscode . workspace . getConfiguration ( "lldb" ) ;
168
+ if (
169
+ lldbConfig . get < string > ( "library" ) === libLldbPath &&
170
+ lldbConfig . get < string > ( "launch.expressions" ) === "native"
171
+ ) {
172
+ return ;
173
+ }
174
+ const userSelection = await vscode . window . showInformationMessage (
175
+ "The Swift extension needs to update some CodeLLDB settings to enable debugging features. Do you want to set this up in your global settings or workspace settings?" ,
176
+ { modal : true } ,
177
+ "Global" ,
178
+ "Workspace" ,
179
+ "Run Anyway"
180
+ ) ;
181
+ switch ( userSelection ) {
182
+ case "Global" :
183
+ lldbConfig . update ( "library" , libLldbPath , vscode . ConfigurationTarget . Global ) ;
184
+ lldbConfig . update (
185
+ "launch.expressions" ,
186
+ "native" ,
187
+ vscode . ConfigurationTarget . Global
188
+ ) ;
189
+ // clear workspace setting
190
+ lldbConfig . update ( "library" , undefined , vscode . ConfigurationTarget . Workspace ) ;
191
+ // clear workspace setting
192
+ lldbConfig . update (
193
+ "launch.expressions" ,
194
+ undefined ,
195
+ vscode . ConfigurationTarget . Workspace
196
+ ) ;
197
+ break ;
198
+ case "Workspace" :
199
+ lldbConfig . update ( "library" , libLldbPath , vscode . ConfigurationTarget . Workspace ) ;
200
+ lldbConfig . update (
201
+ "launch.expressions" ,
202
+ "native" ,
203
+ vscode . ConfigurationTarget . Workspace
204
+ ) ;
205
+ break ;
206
+ }
207
+ return ;
208
+ }
209
+
167
210
private convertEnvironmentVariables ( map : { [ key : string ] : string } ) : string [ ] {
168
211
return Object . entries ( map ) . map ( ( [ key , value ] ) => `${ key } =${ value } ` ) ;
169
212
}
0 commit comments