1+ import * as path from "path" ;
2+ import * as util from "util" ;
13import * as vscode from "vscode" ;
2- import { LLDBDapOptions } from "./types" ;
4+ import * as child_process from "child_process" ;
5+ import * as fs from "node:fs/promises" ;
36
4- /**
5- * This class defines a factory used to find the lldb-dap binary to use
6- * depending on the session configuration.
7- */
8- export class LLDBDapDescriptorFactory
9- implements vscode . DebugAdapterDescriptorFactory
10- {
11- private lldbDapOptions : LLDBDapOptions ;
12-
13- constructor ( lldbDapOptions : LLDBDapOptions ) {
14- this . lldbDapOptions = lldbDapOptions ;
7+ export async function isExecutable ( path : string ) : Promise < Boolean > {
8+ try {
9+ await fs . access ( path , fs . constants . X_OK ) ;
10+ } catch {
11+ return false ;
1512 }
13+ return true ;
14+ }
1615
17- static async isValidDebugAdapterPath (
18- pathUri : vscode . Uri ,
19- ) : Promise < Boolean > {
16+ async function findWithXcrun ( executable : string ) : Promise < string | undefined > {
17+ if ( process . platform === "darwin" ) {
2018 try {
21- const fileStats = await vscode . workspace . fs . stat ( pathUri ) ;
22- if ( ! ( fileStats . type & vscode . FileType . File ) ) {
23- return false ;
19+ const exec = util . promisify ( child_process . execFile ) ;
20+ let { stdout, stderr } = await exec ( "/usr/bin/xcrun" , [
21+ "-find" ,
22+ executable ,
23+ ] ) ;
24+ if ( stdout ) {
25+ return stdout . toString ( ) . trimEnd ( ) ;
2426 }
25- } catch ( err ) {
26- return false ;
27+ } catch ( error ) { }
28+ }
29+ return undefined ;
30+ }
31+
32+ async function findInPath ( executable : string ) : Promise < string | undefined > {
33+ const env_path =
34+ process . platform === "win32" ? process . env [ "Path" ] : process . env [ "PATH" ] ;
35+ if ( ! env_path ) {
36+ return undefined ;
37+ }
38+
39+ const paths = env_path . split ( path . delimiter ) ;
40+ for ( const p of paths ) {
41+ const exe_path = path . join ( p , executable ) ;
42+ if ( await isExecutable ( exe_path ) ) {
43+ return exe_path ;
2744 }
28- return true ;
45+ }
46+ return undefined ;
47+ }
48+
49+ async function findDAPExecutable ( ) : Promise < string | undefined > {
50+ const executable = process . platform === "win32" ? "lldb-dap.exe" : "lldb-dap" ;
51+
52+ // Prefer lldb-dap from Xcode on Darwin.
53+ const xcrun_dap = findWithXcrun ( executable ) ;
54+ if ( xcrun_dap ) {
55+ return xcrun_dap ;
56+ }
57+
58+ // Find lldb-dap in the user's path.
59+ const path_dap = findInPath ( executable ) ;
60+ if ( path_dap ) {
61+ return path_dap ;
2962 }
3063
64+ return undefined ;
65+ }
66+
67+ async function getDAPExecutable (
68+ session : vscode . DebugSession ,
69+ ) : Promise < string | undefined > {
70+ const config = vscode . workspace . getConfiguration (
71+ "lldb-dap" ,
72+ session . workspaceFolder ,
73+ ) ;
74+
75+ // Prefer the explicitly specified path in the extension's configuration.
76+ const configPath = config . get < string > ( "executable-path" ) ;
77+ if ( configPath && configPath . length !== 0 ) {
78+ return configPath ;
79+ }
80+
81+ // Try finding the lldb-dap binary.
82+ const foundPath = await findDAPExecutable ( ) ;
83+ if ( foundPath ) {
84+ return foundPath ;
85+ }
86+
87+ return undefined ;
88+ }
89+
90+ /**
91+ * This class defines a factory used to find the lldb-dap binary to use
92+ * depending on the session configuration.
93+ */
94+ export class LLDBDapDescriptorFactory
95+ implements vscode . DebugAdapterDescriptorFactory
96+ {
3197 async createDebugAdapterDescriptor (
3298 session : vscode . DebugSession ,
3399 executable : vscode . DebugAdapterExecutable | undefined ,
@@ -36,14 +102,40 @@ export class LLDBDapDescriptorFactory
36102 "lldb-dap" ,
37103 session . workspaceFolder ,
38104 ) ;
39- const customPath = config . get < string > ( "executable-path" ) ;
40- const path : string = customPath || executable ! ! . command ;
41105
42- const fileUri = vscode . Uri . file ( path ) ;
43- if ( ! ( await LLDBDapDescriptorFactory . isValidDebugAdapterPath ( fileUri ) ) ) {
44- LLDBDapDescriptorFactory . showLLDBDapNotFoundMessage ( fileUri . path ) ;
106+ const log_path = config . get < string > ( "log-path" ) ;
107+ let env : { [ key : string ] : string } = { } ;
108+ if ( log_path ) {
109+ env [ "LLDBDAP_LOG" ] = log_path ;
110+ }
111+ const configEnvironment =
112+ config . get < { [ key : string ] : string } > ( "environment" ) || { } ;
113+ const dapPath = await getDAPExecutable ( session ) ;
114+ const dbgOptions = {
115+ env : {
116+ ...executable ?. options ?. env ,
117+ ...configEnvironment ,
118+ ...env ,
119+ } ,
120+ } ;
121+ if ( dapPath ) {
122+ if ( ! ( await isExecutable ( dapPath ) ) ) {
123+ LLDBDapDescriptorFactory . showLLDBDapNotFoundMessage ( dapPath ) ;
124+ return undefined ;
125+ }
126+ return new vscode . DebugAdapterExecutable ( dapPath , [ ] , dbgOptions ) ;
127+ } else if ( executable ) {
128+ if ( ! ( await isExecutable ( executable . command ) ) ) {
129+ LLDBDapDescriptorFactory . showLLDBDapNotFoundMessage ( executable . command ) ;
130+ return undefined ;
131+ }
132+ return new vscode . DebugAdapterExecutable (
133+ executable . command ,
134+ executable . args ,
135+ dbgOptions ,
136+ ) ;
45137 }
46- return this . lldbDapOptions . createDapExecutableCommand ( session , executable ) ;
138+ return undefined ;
47139 }
48140
49141 /**
0 commit comments