@@ -28,6 +28,11 @@ type ToolConfig = Map<Tool, string>;
28
28
type ManageHLS = 'GHCup' | 'PATH' ;
29
29
let manageHLS = workspace . getConfiguration ( 'haskell' ) . get ( 'manageHLS' ) as ManageHLS ;
30
30
31
+ export type Context = {
32
+ manageHls : ManageHLS ;
33
+ serverResolved ?: HlsExecutable ;
34
+ } ;
35
+
31
36
// On Windows the executable needs to be stored somewhere with an .exe extension
32
37
const exeExt = process . platform === 'win32' ? '.exe' : '' ;
33
38
@@ -163,6 +168,27 @@ async function findHLSinPATH(_context: ExtensionContext, logger: Logger): Promis
163
168
throw new MissingToolError ( 'hls' ) ;
164
169
}
165
170
171
+ export type HlsExecutable = HlsOnPath | HlsViaVSCodeConfig | HlsViaGhcup ;
172
+
173
+ export type HlsOnPath = {
174
+ location : string ;
175
+ tag : 'path' ;
176
+ } ;
177
+
178
+ export type HlsViaVSCodeConfig = {
179
+ location : string ;
180
+ tag : 'config' ;
181
+ } ;
182
+
183
+ export type HlsViaGhcup = {
184
+ location : string ;
185
+ /**
186
+ * if we download HLS, add that bin dir to PATH
187
+ */
188
+ binaryDirectory : string ;
189
+ tag : 'ghcup' ;
190
+ } ;
191
+
166
192
/**
167
193
* Downloads the latest haskell-language-server binaries via GHCup.
168
194
* Makes sure that either `ghcup` is available locally, otherwise installs
@@ -181,12 +207,15 @@ export async function findHaskellLanguageServer(
181
207
logger : Logger ,
182
208
workingDir : string ,
183
209
folder ?: WorkspaceFolder ,
184
- ) : Promise < [ string , string | undefined ] > {
210
+ ) : Promise < HlsExecutable > {
185
211
logger . info ( 'Finding haskell-language-server' ) ;
186
212
187
213
if ( workspace . getConfiguration ( 'haskell' ) . get ( 'serverExecutablePath' ) as string ) {
188
214
const exe = await findServerExecutable ( logger , folder ) ;
189
- return [ exe , undefined ] ;
215
+ return {
216
+ location : exe ,
217
+ tag : 'config' ,
218
+ } ;
190
219
}
191
220
192
221
const storagePath : string = await getStoragePath ( context ) ;
@@ -196,47 +225,24 @@ export async function findHaskellLanguageServer(
196
225
}
197
226
198
227
// first plugin initialization
199
- if ( manageHLS !== 'GHCup' && ( ! context . globalState . get ( 'pluginInitialized' ) as boolean | null ) ) {
200
- const promptMessage = `How do you want the extension to manage/discover HLS and the relevant toolchain?
201
-
202
- Choose "Automatically" if you're in doubt.
203
- ` ;
204
-
205
- const popup = window . showInformationMessage (
206
- promptMessage ,
207
- { modal : true } ,
208
- 'Automatically via GHCup' ,
209
- 'Manually via PATH' ,
210
- ) ;
211
-
212
- const decision = ( await popup ) || null ;
213
- if ( decision === 'Automatically via GHCup' ) {
214
- manageHLS = 'GHCup' ;
215
- } else if ( decision === 'Manually via PATH' ) {
216
- manageHLS = 'PATH' ;
217
- } else {
218
- window . showWarningMessage (
219
- "Choosing default PATH method for HLS discovery. You can change this via 'haskell.manageHLS' in the settings." ,
220
- ) ;
221
- manageHLS = 'PATH' ;
222
- }
223
- workspace . getConfiguration ( 'haskell' ) . update ( 'manageHLS' , manageHLS , ConfigurationTarget . Global ) ;
224
- context . globalState . update ( 'pluginInitialized' , true ) ;
225
- }
228
+ manageHLS = await promptUserForManagingHls ( context , manageHLS ) ;
226
229
227
230
if ( manageHLS === 'PATH' ) {
228
231
const exe = await findHLSinPATH ( context , logger ) ;
229
- return [ exe , undefined ] ;
232
+ return {
233
+ location : exe ,
234
+ tag : 'path' ,
235
+ } ;
230
236
} else {
231
237
// we manage HLS, make sure ghcup is installed/available
232
238
await upgradeGHCup ( context , logger ) ;
233
239
234
240
// boring init
235
- let latestHLS : string | undefined | null ;
241
+ let latestHLS : string | undefined ;
236
242
let latestCabal : string | undefined | null ;
237
243
let latestStack : string | undefined | null ;
238
244
let recGHC : string | undefined | null = 'recommended' ;
239
- let projectHls : string | undefined | null ;
245
+ let projectHls : string | undefined ;
240
246
let projectGhc : string | undefined | null ;
241
247
242
248
// support explicit toolchain config
@@ -358,7 +364,7 @@ export async function findHaskellLanguageServer(
358
364
359
365
// more download popups
360
366
if ( promptBeforeDownloads ) {
361
- const hlsInstalled = projectHls ? await toolInstalled ( context , logger , 'hls' , projectHls ) : undefined ;
367
+ const hlsInstalled = await toolInstalled ( context , logger , 'hls' , projectHls ) ;
362
368
const ghcInstalled = projectGhc ? await toolInstalled ( context , logger , 'ghc' , projectGhc ) : undefined ;
363
369
const toInstall : InstalledTool [ ] = [ hlsInstalled , ghcInstalled ] . filter (
364
370
( tool ) => tool && ! tool . installed ,
@@ -398,7 +404,7 @@ export async function findHaskellLanguageServer(
398
404
logger ,
399
405
[
400
406
'run' ,
401
- ...( projectHls ? [ '--hls' , projectHls ] : [ ] ) ,
407
+ ...[ '--hls' , projectHls ] ,
402
408
...( latestCabal ? [ '--cabal' , latestCabal ] : [ ] ) ,
403
409
...( latestStack ? [ '--stack' , latestStack ] : [ ] ) ,
404
410
...( projectGhc ? [ '--ghc' , projectGhc ] : [ ] ) ,
@@ -416,12 +422,45 @@ export async function findHaskellLanguageServer(
416
422
true ,
417
423
) ;
418
424
419
- if ( projectHls ) {
420
- return [ path . join ( hlsBinDir , `haskell-language-server-wrapper${ exeExt } ` ) , hlsBinDir ] ;
425
+ return {
426
+ binaryDirectory : hlsBinDir ,
427
+ location : path . join ( hlsBinDir , `haskell-language-server-wrapper${ exeExt } ` ) ,
428
+ tag : 'ghcup' ,
429
+ } ;
430
+ }
431
+ }
432
+
433
+ async function promptUserForManagingHls ( context : ExtensionContext , manageHlsSetting : ManageHLS ) : Promise < ManageHLS > {
434
+ if ( manageHlsSetting !== 'GHCup' && ( ! context . globalState . get ( 'pluginInitialized' ) as boolean | null ) ) {
435
+ const promptMessage = `How do you want the extension to manage/discover HLS and the relevant toolchain?
436
+
437
+ Choose "Automatically" if you're in doubt.
438
+ ` ;
439
+
440
+ const popup = window . showInformationMessage (
441
+ promptMessage ,
442
+ { modal : true } ,
443
+ 'Automatically via GHCup' ,
444
+ 'Manually via PATH' ,
445
+ ) ;
446
+
447
+ const decision = ( await popup ) || null ;
448
+ let howToManage : ManageHLS ;
449
+ if ( decision === 'Automatically via GHCup' ) {
450
+ howToManage = 'GHCup' ;
451
+ } else if ( decision === 'Manually via PATH' ) {
452
+ howToManage = 'PATH' ;
421
453
} else {
422
- const exe = await findHLSinPATH ( context , logger ) ;
423
- return [ exe , hlsBinDir ] ;
454
+ window . showWarningMessage (
455
+ "Choosing default PATH method for HLS discovery. You can change this via 'haskell.manageHLS' in the settings." ,
456
+ ) ;
457
+ howToManage = 'PATH' ;
424
458
}
459
+ workspace . getConfiguration ( 'haskell' ) . update ( 'manageHLS' , howToManage , ConfigurationTarget . Global ) ;
460
+ context . globalState . update ( 'pluginInitialized' , true ) ;
461
+ return howToManage ;
462
+ } else {
463
+ return manageHlsSetting ;
425
464
}
426
465
}
427
466
0 commit comments