@@ -5,7 +5,6 @@ import { stat } from 'fs/promises';
5
5
import * as https from 'https' ;
6
6
import * as path from 'path' ;
7
7
import { match } from 'ts-pattern' ;
8
- import * as url from 'url' ;
9
8
import { promisify } from 'util' ;
10
9
import { ConfigurationTarget , ExtensionContext , ProgressLocation , window , workspace , WorkspaceFolder } from 'vscode' ;
11
10
import { Logger } from 'vscode-languageclient' ;
@@ -68,7 +67,7 @@ async function callAsync(
68
67
envAdd ?: IEnvVars ,
69
68
callback ?: ProcessCallback
70
69
) : Promise < string > {
71
- let newEnv : IEnvVars = await resolveServerEnvironmentPATH (
70
+ let newEnv : IEnvVars = resolveServerEnvironmentPATH (
72
71
workspace . getConfiguration ( 'haskell' ) . get ( 'serverEnvironment' ) || { }
73
72
) ;
74
73
newEnv = { ...( process . env as IEnvVars ) , ...newEnv , ...( envAdd || { } ) } ;
@@ -135,15 +134,14 @@ async function callAsync(
135
134
/** Gets serverExecutablePath and fails if it's not set.
136
135
*/
137
136
async function findServerExecutable (
138
- context : ExtensionContext ,
139
137
logger : Logger ,
140
138
folder ?: WorkspaceFolder
141
139
) : Promise < string > {
142
140
let exePath = workspace . getConfiguration ( 'haskell' ) . get ( 'serverExecutablePath' ) as string ;
143
141
logger . info ( `Trying to find the server executable in: ${ exePath } ` ) ;
144
142
exePath = resolvePathPlaceHolders ( exePath , folder ) ;
145
143
logger . log ( `Location after path variables substitution: ${ exePath } ` ) ;
146
- if ( await executableExists ( exePath ) ) {
144
+ if ( executableExists ( exePath ) ) {
147
145
return exePath ;
148
146
} else {
149
147
const msg = `Could not find a HLS binary at ${ exePath } ! Consider installing HLS via ghcup or change "haskell.manageHLS" in your settings.` ;
@@ -153,13 +151,13 @@ async function findServerExecutable(
153
151
154
152
/** Searches the PATH. Fails if nothing is found.
155
153
*/
156
- async function findHLSinPATH ( context : ExtensionContext , logger : Logger , folder ?: WorkspaceFolder ) : Promise < string > {
154
+ async function findHLSinPATH ( _context : ExtensionContext , logger : Logger ) : Promise < string > {
157
155
// try PATH
158
156
const exes : string [ ] = [ 'haskell-language-server-wrapper' , 'haskell-language-server' ] ;
159
157
logger . info ( `Searching for server executables ${ exes . join ( ',' ) } in $PATH` ) ;
160
158
logger . info ( `$PATH environment variable: ${ process . env . PATH } ` ) ;
161
159
for ( const exe of exes ) {
162
- if ( await executableExists ( exe ) ) {
160
+ if ( executableExists ( exe ) ) {
163
161
logger . info ( `Found server executable in $PATH: ${ exe } ` ) ;
164
162
return exe ;
165
163
}
@@ -189,7 +187,7 @@ export async function findHaskellLanguageServer(
189
187
logger . info ( 'Finding haskell-language-server' ) ;
190
188
191
189
if ( workspace . getConfiguration ( 'haskell' ) . get ( 'serverExecutablePath' ) as string ) {
192
- const exe = await findServerExecutable ( context , logger , folder ) ;
190
+ const exe = await findServerExecutable ( logger , folder ) ;
193
191
return [ exe , undefined ] ;
194
192
}
195
193
@@ -226,7 +224,7 @@ export async function findHaskellLanguageServer(
226
224
}
227
225
228
226
if ( manageHLS === 'PATH' ) {
229
- const exe = await findHLSinPATH ( context , logger , folder ) ;
227
+ const exe = await findHLSinPATH ( context , logger ) ;
230
228
return [ exe , undefined ] ;
231
229
} else {
232
230
// we manage HLS, make sure ghcup is installed/available
@@ -267,40 +265,42 @@ export async function findHaskellLanguageServer(
267
265
latestStack = await getLatestToolFromGHCup ( context , logger , 'stack' ) ;
268
266
}
269
267
if ( recGHC === undefined ) {
270
- recGHC = ! ( await executableExists ( 'ghc' ) )
268
+ recGHC = ! executableExists ( 'ghc' )
271
269
? await getLatestAvailableToolFromGHCup ( context , logger , 'ghc' , 'recommended' )
272
270
: null ;
273
271
}
274
272
275
273
// download popups
276
274
const promptBeforeDownloads = workspace . getConfiguration ( 'haskell' ) . get ( 'promptBeforeDownloads' ) as boolean ;
277
275
if ( promptBeforeDownloads ) {
278
- const hlsInstalled = latestHLS
279
- ? await toolInstalled ( context , logger , 'hls' , latestHLS )
280
- : undefined ;
281
- const cabalInstalled = latestCabal
282
- ? await toolInstalled ( context , logger , 'cabal' , latestCabal )
283
- : undefined ;
284
- const stackInstalled = latestStack
285
- ? await toolInstalled ( context , logger , 'stack' , latestStack )
286
- : undefined ;
276
+ const hlsInstalled = latestHLS ? await toolInstalled ( context , logger , 'hls' , latestHLS ) : undefined ;
277
+ const cabalInstalled = latestCabal ? await toolInstalled ( context , logger , 'cabal' , latestCabal ) : undefined ;
278
+ const stackInstalled = latestStack ? await toolInstalled ( context , logger , 'stack' , latestStack ) : undefined ;
287
279
const ghcInstalled = executableExists ( 'ghc' )
288
- ? new InstalledTool ( 'ghc' , await callAsync ( `ghc${ exeExt } ` , [ '--numeric-version' ] , logger , undefined , undefined , false ) )
289
- // if recGHC is null, that means user disabled automatic handling,
290
- : ( recGHC !== null ? await toolInstalled ( context , logger , 'ghc' , recGHC ) : undefined ) ;
291
- const toInstall : InstalledTool [ ] = [ hlsInstalled , cabalInstalled , stackInstalled , ghcInstalled ]
292
- . filter ( ( tool ) => tool && ! tool . installed ) as InstalledTool [ ] ;
280
+ ? new InstalledTool (
281
+ 'ghc' ,
282
+ await callAsync ( `ghc${ exeExt } ` , [ '--numeric-version' ] , logger , undefined , undefined , false )
283
+ )
284
+ : // if recGHC is null, that means user disabled automatic handling,
285
+ recGHC !== null
286
+ ? await toolInstalled ( context , logger , 'ghc' , recGHC )
287
+ : undefined ;
288
+ const toInstall : InstalledTool [ ] = [ hlsInstalled , cabalInstalled , stackInstalled , ghcInstalled ] . filter (
289
+ ( tool ) => tool && ! tool . installed
290
+ ) as InstalledTool [ ] ;
293
291
if ( toInstall . length > 0 ) {
294
292
const decision = await window . showInformationMessage (
295
- `Need to download ${ toInstall . map ( t => t . nameWithVersion ) . join ( ', ' ) } , continue?` ,
293
+ `Need to download ${ toInstall . map ( ( t ) => t . nameWithVersion ) . join ( ', ' ) } , continue?` ,
296
294
'Yes' ,
297
295
'No' ,
298
296
"Yes, don't ask again"
299
297
) ;
300
298
if ( decision === 'Yes' ) {
301
- logger . info ( `User accepted download for ${ toInstall . map ( t => t . nameWithVersion ) . join ( ', ' ) } .` ) ;
299
+ logger . info ( `User accepted download for ${ toInstall . map ( ( t ) => t . nameWithVersion ) . join ( ', ' ) } .` ) ;
302
300
} else if ( decision === "Yes, don't ask again" ) {
303
- logger . info ( `User accepted download for ${ toInstall . map ( t => t . nameWithVersion ) . join ( ', ' ) } and won't be asked again.` ) ;
301
+ logger . info (
302
+ `User accepted download for ${ toInstall . map ( ( t ) => t . nameWithVersion ) . join ( ', ' ) } and won't be asked again.`
303
+ ) ;
304
304
workspace . getConfiguration ( 'haskell' ) . update ( 'promptBeforeDownloads' , false ) ;
305
305
} else {
306
306
toInstall . forEach ( ( tool ) => {
@@ -353,26 +353,25 @@ export async function findHaskellLanguageServer(
353
353
354
354
// more download popups
355
355
if ( promptBeforeDownloads ) {
356
- const hlsInstalled = projectHls
357
- ? await toolInstalled ( context , logger , 'hls' , projectHls )
358
- : undefined ;
359
- const ghcInstalled = projectGhc
360
- ? await toolInstalled ( context , logger , 'ghc' , projectGhc )
361
- : undefined ;
362
- const toInstall : InstalledTool [ ] = [ hlsInstalled , ghcInstalled ]
363
- . filter ( ( tool ) => tool && ! tool . installed ) as InstalledTool [ ] ;
356
+ const hlsInstalled = projectHls ? await toolInstalled ( context , logger , 'hls' , projectHls ) : undefined ;
357
+ const ghcInstalled = projectGhc ? await toolInstalled ( context , logger , 'ghc' , projectGhc ) : undefined ;
358
+ const toInstall : InstalledTool [ ] = [ hlsInstalled , ghcInstalled ] . filter (
359
+ ( tool ) => tool && ! tool . installed
360
+ ) as InstalledTool [ ] ;
364
361
if ( toInstall . length > 0 ) {
365
362
const decision = await window . showInformationMessage (
366
- `Need to download ${ toInstall . map ( t => t . nameWithVersion ) . join ( ', ' ) } , continue?` ,
363
+ `Need to download ${ toInstall . map ( ( t ) => t . nameWithVersion ) . join ( ', ' ) } , continue?` ,
367
364
{ modal : true } ,
368
365
'Yes' ,
369
366
'No' ,
370
367
"Yes, don't ask again"
371
368
) ;
372
369
if ( decision === 'Yes' ) {
373
- logger . info ( `User accepted download for ${ toInstall . map ( t => t . nameWithVersion ) . join ( ', ' ) } .` ) ;
370
+ logger . info ( `User accepted download for ${ toInstall . map ( ( t ) => t . nameWithVersion ) . join ( ', ' ) } .` ) ;
374
371
} else if ( decision === "Yes, don't ask again" ) {
375
- logger . info ( `User accepted download for ${ toInstall . map ( t => t . nameWithVersion ) . join ( ', ' ) } and won't be asked again.` ) ;
372
+ logger . info (
373
+ `User accepted download for ${ toInstall . map ( ( t ) => t . nameWithVersion ) . join ( ', ' ) } and won't be asked again.`
374
+ ) ;
376
375
workspace . getConfiguration ( 'haskell' ) . update ( 'promptBeforeDownloads' , false ) ;
377
376
} else {
378
377
toInstall . forEach ( ( tool ) => {
@@ -400,14 +399,22 @@ export async function findHaskellLanguageServer(
400
399
...( projectGhc ? [ '--ghc' , projectGhc ] : [ ] ) ,
401
400
'--install' ,
402
401
] ,
403
- `Installing project specific toolchain: ${ [ [ 'hls' , projectHls ] , [ 'GHC' , projectGhc ] , [ 'cabal' , latestCabal ] , [ 'stack' , latestStack ] ] . filter ( t => t [ 1 ] ) . map ( t => `${ t [ 0 ] } -${ t [ 1 ] } ` ) . join ( ', ' ) } ` ,
402
+ `Installing project specific toolchain: ${ [
403
+ [ 'hls' , projectHls ] ,
404
+ [ 'GHC' , projectGhc ] ,
405
+ [ 'cabal' , latestCabal ] ,
406
+ [ 'stack' , latestStack ] ,
407
+ ]
408
+ . filter ( ( t ) => t [ 1 ] )
409
+ . map ( ( t ) => `${ t [ 0 ] } -${ t [ 1 ] } ` )
410
+ . join ( ', ' ) } `,
404
411
true
405
412
) ;
406
413
407
414
if ( projectHls ) {
408
415
return [ path . join ( hlsBinDir , `haskell-language-server-wrapper${ exeExt } ` ) , hlsBinDir ] ;
409
416
} else {
410
- const exe = await findHLSinPATH ( context , logger , folder ) ;
417
+ const exe = await findHLSinPATH ( context , logger ) ;
411
418
return [ exe , hlsBinDir ] ;
412
419
}
413
420
}
@@ -470,8 +477,8 @@ async function getLatestProjectHLS(
470
477
const merged = new Map < string , string [ ] > ( [ ...metadataMap , ...ghcupMap ] ) ; // right-biased
471
478
// now sort and get the latest suitable version
472
479
const latest = [ ...merged ]
473
- . filter ( ( [ k , v ] ) => v . some ( ( x ) => x === projectGhc ) )
474
- . sort ( ( [ k1 , v1 ] , [ k2 , v2 ] ) => comparePVP ( k1 , k2 ) )
480
+ . filter ( ( [ _k , v ] ) => v . some ( ( x ) => x === projectGhc ) )
481
+ . sort ( ( [ k1 , _v1 ] , [ k2 , _v2 ] ) => comparePVP ( k1 , k2 ) )
475
482
. pop ( ) ;
476
483
477
484
if ( ! latest ) {
@@ -484,7 +491,7 @@ async function getLatestProjectHLS(
484
491
/**
485
492
* Obtain the project ghc version from the HLS - Wrapper (which must be in PATH now).
486
493
* Also, serves as a sanity check.
487
- * @param wrapper Path to the Haskell-Language-Server wrapper
494
+ * @param toolchainBindir Path to the toolchainn bin directory (added to PATH)
488
495
* @param workingDir Directory to run the process, usually the root of the workspace.
489
496
* @param logger Logger for feedback.
490
497
* @returns The GHC version, or fail with an `Error`.
@@ -499,7 +506,7 @@ export async function getProjectGHCVersion(
499
506
500
507
const args = [ '--project-ghc-version' ] ;
501
508
502
- const newPath = await addPathToProcessPath ( toolchainBindir , logger ) ;
509
+ const newPath = await addPathToProcessPath ( toolchainBindir ) ;
503
510
const environmentNew : IEnvVars = {
504
511
PATH : newPath ,
505
512
} ;
@@ -550,14 +557,14 @@ export async function upgradeGHCup(context: ExtensionContext, logger: Logger): P
550
557
}
551
558
}
552
559
553
- export async function findGHCup ( context : ExtensionContext , logger : Logger , folder ?: WorkspaceFolder ) : Promise < string > {
560
+ export async function findGHCup ( _context : ExtensionContext , logger : Logger , folder ?: WorkspaceFolder ) : Promise < string > {
554
561
logger . info ( 'Checking for ghcup installation' ) ;
555
562
let exePath = workspace . getConfiguration ( 'haskell' ) . get ( 'ghcupExecutablePath' ) as string ;
556
563
if ( exePath ) {
557
564
logger . info ( `Trying to find the ghcup executable in: ${ exePath } ` ) ;
558
565
exePath = resolvePathPlaceHolders ( exePath , folder ) ;
559
566
logger . log ( `Location after path variables substitution: ${ exePath } ` ) ;
560
- if ( await executableExists ( exePath ) ) {
567
+ if ( executableExists ( exePath ) ) {
561
568
return exePath ;
562
569
} else {
563
570
throw new Error ( `Could not find a ghcup binary at ${ exePath } !` ) ;
@@ -684,8 +691,8 @@ async function toolInstalled(
684
691
version : string
685
692
) : Promise < InstalledTool > {
686
693
const b = await callGHCup ( context , logger , [ 'whereis' , tool , version ] , undefined , false )
687
- . then ( ( x ) => true )
688
- . catch ( ( x ) => false ) ;
694
+ . then ( ( _x ) => true )
695
+ . catch ( ( _x ) => false ) ;
689
696
return new InstalledTool ( tool , version , b ) ;
690
697
}
691
698
@@ -737,7 +744,7 @@ export type ReleaseMetadata = Map<string, Map<string, Map<string, string[]>>>;
737
744
*/
738
745
async function getHLSesfromMetadata ( context : ExtensionContext , logger : Logger ) : Promise < Map < string , string [ ] > | null > {
739
746
const storagePath : string = await getStoragePath ( context ) ;
740
- const metadata = await getReleaseMetadata ( context , storagePath , logger ) . catch ( ( e ) => null ) ;
747
+ const metadata = await getReleaseMetadata ( context , storagePath , logger ) . catch ( ( _e ) => null ) ;
741
748
if ( ! metadata ) {
742
749
window . showErrorMessage ( 'Could not get release metadata' ) ;
743
750
return null ;
@@ -803,23 +810,23 @@ export function findSupportedHlsPerGhc(
803
810
/**
804
811
* Download GHCUP metadata.
805
812
*
806
- * @param context Extension context.
813
+ * @param _context Extension context.
807
814
* @param storagePath Path to put in binary files and caches.
808
815
* @param logger Logger for feedback.
809
816
* @returns Metadata of releases, or null if the cache can not be found.
810
817
*/
811
818
async function getReleaseMetadata (
812
- context : ExtensionContext ,
819
+ _context : ExtensionContext ,
813
820
storagePath : string ,
814
821
logger : Logger
815
822
) : Promise < ReleaseMetadata | null > {
816
823
const releasesUrl = workspace . getConfiguration ( 'haskell' ) . releasesURL
817
- ? url . parse ( workspace . getConfiguration ( 'haskell' ) . releasesURL )
824
+ ? new URL ( workspace . getConfiguration ( 'haskell' ) . releasesURL )
818
825
: undefined ;
819
826
const opts : https . RequestOptions = releasesUrl
820
827
? {
821
828
host : releasesUrl . host ,
822
- path : releasesUrl . path ,
829
+ path : releasesUrl . pathname ,
823
830
}
824
831
: {
825
832
host : 'raw.githubusercontent.com' ,
0 commit comments