@@ -6,7 +6,7 @@ import * as fs from "node:fs/promises";
66
77const exec = util . promisify ( child_process . execFile ) ;
88
9- export async function isExecutable ( path : string ) : Promise < Boolean > {
9+ async function isExecutable ( path : string ) : Promise < Boolean > {
1010 try {
1111 await fs . access ( path , fs . constants . X_OK ) ;
1212 } catch {
@@ -66,19 +66,17 @@ async function findDAPExecutable(): Promise<string | undefined> {
6666}
6767
6868async function getDAPExecutable (
69- session : vscode . DebugSession ,
69+ folder : vscode . WorkspaceFolder | undefined ,
70+ configuration : vscode . DebugConfiguration ,
7071) : Promise < string | undefined > {
7172 // Check if the executable was provided in the launch configuration.
72- const launchConfigPath = session . configuration [ "debugAdapterExecutable" ] ;
73+ const launchConfigPath = configuration [ "debugAdapterExecutable" ] ;
7374 if ( typeof launchConfigPath === "string" && launchConfigPath . length !== 0 ) {
7475 return launchConfigPath ;
7576 }
7677
7778 // Check if the executable was provided in the extension's configuration.
78- const config = vscode . workspace . getConfiguration (
79- "lldb-dap" ,
80- session . workspaceFolder ,
81- ) ;
79+ const config = vscode . workspace . getConfiguration ( "lldb-dap" , folder ) ;
8280 const configPath = config . get < string > ( "executable-path" ) ;
8381 if ( configPath && configPath . length !== 0 ) {
8482 return configPath ;
@@ -93,9 +91,12 @@ async function getDAPExecutable(
9391 return undefined ;
9492}
9593
96- function getDAPArguments ( session : vscode . DebugSession ) : string [ ] {
94+ function getDAPArguments (
95+ folder : vscode . WorkspaceFolder | undefined ,
96+ configuration : vscode . DebugConfiguration ,
97+ ) : string [ ] {
9798 // Check the debug configuration for arguments first
98- const debugConfigArgs = session . configuration . debugAdapterArgs ;
99+ const debugConfigArgs = configuration . debugAdapterArgs ;
99100 if (
100101 Array . isArray ( debugConfigArgs ) &&
101102 debugConfigArgs . findIndex ( ( entry ) => typeof entry !== "string" ) === - 1
@@ -104,129 +105,110 @@ function getDAPArguments(session: vscode.DebugSession): string[] {
104105 }
105106 // Fall back on the workspace configuration
106107 return vscode . workspace
107- . getConfiguration ( "lldb-dap" )
108+ . getConfiguration ( "lldb-dap" , folder )
108109 . get < string [ ] > ( "arguments" , [ ] ) ;
109110}
110111
111- async function isServerModeSupported ( exe : string ) : Promise < boolean > {
112- const { stdout } = await exec ( exe , [ "--help" ] ) ;
113- return / - - c o n n e c t i o n / . test ( stdout ) ;
112+ /**
113+ * Shows a modal when the debug adapter's path is not found
114+ */
115+ async function showLLDBDapNotFoundMessage ( path ?: string ) {
116+ const message =
117+ path !== undefined
118+ ? `Debug adapter path: ${ path } is not a valid file`
119+ : "Unable to find the path to the LLDB debug adapter executable." ;
120+ const openSettingsAction = "Open Settings" ;
121+ const callbackValue = await vscode . window . showErrorMessage (
122+ message ,
123+ { modal : true } ,
124+ openSettingsAction ,
125+ ) ;
126+
127+ if ( openSettingsAction === callbackValue ) {
128+ vscode . commands . executeCommand (
129+ "workbench.action.openSettings" ,
130+ "lldb-dap.executable-path" ,
131+ ) ;
132+ }
114133}
115134
116135/**
117- * This class defines a factory used to find the lldb-dap binary to use
118- * depending on the session configuration.
136+ * Creates a new {@link vscode.DebugAdapterExecutable} based on the provided workspace folder and
137+ * debug configuration. Assumes that the given debug configuration is for a local launch of lldb-dap.
138+ *
139+ * @param folder The {@link vscode.WorkspaceFolder} that the debug session will be launched within
140+ * @param configuration The {@link vscode.DebugConfiguration}
141+ * @param userInteractive Whether or not this was called due to user interaction (determines if modals should be shown)
142+ * @returns
119143 */
120- export class LLDBDapDescriptorFactory
121- implements vscode . DebugAdapterDescriptorFactory , vscode . Disposable
122- {
123- private server ?: Promise < {
124- process : child_process . ChildProcess ;
125- host : string ;
126- port : number ;
127- } > ;
128-
129- dispose ( ) {
130- this . server ?. then ( ( { process } ) => {
131- process . kill ( ) ;
132- } ) ;
144+ export async function createDebugAdapterExecutable (
145+ folder : vscode . WorkspaceFolder | undefined ,
146+ configuration : vscode . DebugConfiguration ,
147+ userInteractive ?: boolean ,
148+ ) : Promise < vscode . DebugAdapterExecutable | undefined > {
149+ const config = vscode . workspace . getConfiguration ( "lldb-dap" , folder ) ;
150+ const log_path = config . get < string > ( "log-path" ) ;
151+ let env : { [ key : string ] : string } = { } ;
152+ if ( log_path ) {
153+ env [ "LLDBDAP_LOG" ] = log_path ;
133154 }
155+ const configEnvironment =
156+ config . get < { [ key : string ] : string } > ( "environment" ) || { } ;
157+ const dapPath = await getDAPExecutable ( folder , configuration ) ;
134158
135- async createDebugAdapterDescriptor (
136- session : vscode . DebugSession ,
137- _executable : vscode . DebugAdapterExecutable | undefined ,
138- ) : Promise < vscode . DebugAdapterDescriptor | undefined > {
139- const config = vscode . workspace . getConfiguration (
140- "lldb-dap" ,
141- session . workspaceFolder ,
142- ) ;
143-
144- const log_path = config . get < string > ( "log-path" ) ;
145- let env : { [ key : string ] : string } = { } ;
146- if ( log_path ) {
147- env [ "LLDBDAP_LOG" ] = log_path ;
159+ if ( ! dapPath ) {
160+ if ( userInteractive ) {
161+ showLLDBDapNotFoundMessage ( ) ;
148162 }
149- const configEnvironment =
150- config . get < { [ key : string ] : string } > ( "environment" ) || { } ;
151- const dapPath = await getDAPExecutable ( session ) ;
163+ return undefined ;
164+ }
152165
153- if ( ! dapPath ) {
154- LLDBDapDescriptorFactory . showLLDBDapNotFoundMessage ( ) ;
155- return undefined ;
166+ if ( ! ( await isExecutable ( dapPath ) ) ) {
167+ if ( userInteractive ) {
168+ showLLDBDapNotFoundMessage ( dapPath ) ;
156169 }
170+ return undefined ;
171+ }
157172
158- if ( ! ( await isExecutable ( dapPath ) ) ) {
159- LLDBDapDescriptorFactory . showLLDBDapNotFoundMessage ( dapPath ) ;
160- return ;
161- }
173+ const dbgOptions = {
174+ env : {
175+ ...configEnvironment ,
176+ ...env ,
177+ } ,
178+ } ;
179+ const dbgArgs = getDAPArguments ( folder , configuration ) ;
180+
181+ return new vscode . DebugAdapterExecutable ( dapPath , dbgArgs , dbgOptions ) ;
182+ }
162183
163- const dbgOptions = {
164- env : {
165- ... configEnvironment ,
166- ... env ,
167- } ,
168- } ;
169- const dbgArgs = getDAPArguments ( session ) ;
170-
171- const serverMode = config . get < boolean > ( "serverMode" , false ) ;
172- if ( serverMode && ( await isServerModeSupported ( dapPath ) ) ) {
173- const { host , port } = await this . startServer (
174- dapPath ,
175- dbgArgs ,
176- dbgOptions ,
184+ /**
185+ * This class defines a factory used to find the lldb-dap binary to use
186+ * depending on the session configuration.
187+ */
188+ export class LLDBDapDescriptorFactory
189+ implements vscode . DebugAdapterDescriptorFactory
190+ {
191+ async createDebugAdapterDescriptor (
192+ session : vscode . DebugSession ,
193+ executable : vscode . DebugAdapterExecutable | undefined ,
194+ ) : Promise < vscode . DebugAdapterDescriptor | undefined > {
195+ if ( executable ) {
196+ throw new Error (
197+ "Setting the debug adapter executable in the package.json is not supported." ,
177198 ) ;
178- return new vscode . DebugAdapterServer ( port , host ) ;
179199 }
180200
181- return new vscode . DebugAdapterExecutable ( dapPath , dbgArgs , dbgOptions ) ;
182- }
183-
184- startServer (
185- dapPath : string ,
186- args : string [ ] ,
187- options : child_process . CommonSpawnOptions ,
188- ) : Promise < { host : string ; port : number } > {
189- if ( this . server ) {
190- return this . server ;
201+ // Use a server connection if the debugAdapterPort is provided
202+ if ( session . configuration . debugAdapterPort ) {
203+ return new vscode . DebugAdapterServer (
204+ session . configuration . debugAdapterPort ,
205+ session . configuration . debugAdapterHost ,
206+ ) ;
191207 }
192208
193- this . server = new Promise ( ( resolve ) => {
194- args . push ( "--connection" , "connect://localhost:0" ) ;
195- const server = child_process . spawn ( dapPath , args , options ) ;
196- server . stdout ! . setEncoding ( "utf8" ) . once ( "data" , ( data : string ) => {
197- const connection = / c o n n e c t i o n : \/ \/ \[ ( [ ^ \] ] + ) \] : ( \d + ) / . exec ( data ) ;
198- if ( connection ) {
199- const host = connection [ 1 ] ;
200- const port = Number ( connection [ 2 ] ) ;
201- resolve ( { process : server , host, port } ) ;
202- }
203- } ) ;
204- server . on ( "exit" , ( ) => {
205- this . server = undefined ;
206- } ) ;
207- } ) ;
208- return this . server ;
209- }
210-
211- /**
212- * Shows a message box when the debug adapter's path is not found
213- */
214- static async showLLDBDapNotFoundMessage ( path ?: string | undefined ) {
215- const message =
216- path !== undefined
217- ? `Debug adapter path: ${ path } is not a valid file`
218- : "Unable to find the path to the LLDB debug adapter executable." ;
219- const openSettingsAction = "Open Settings" ;
220- const callbackValue = await vscode . window . showErrorMessage (
221- message ,
222- openSettingsAction ,
209+ return createDebugAdapterExecutable (
210+ session . workspaceFolder ,
211+ session . configuration ,
223212 ) ;
224-
225- if ( openSettingsAction === callbackValue ) {
226- vscode . commands . executeCommand (
227- "workbench.action.openSettings" ,
228- "lldb-dap.executable-path" ,
229- ) ;
230- }
231213 }
232214}
0 commit comments