Skip to content

Commit 383fb8f

Browse files
committed
Introduce 'haskell.toolchain' setting
1 parent 104a1c7 commit 383fb8f

File tree

2 files changed

+51
-30
lines changed

2 files changed

+51
-30
lines changed

package.json

Lines changed: 4 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -177,23 +177,11 @@
177177
"Discovers HLS and other executables in system PATH"
178178
]
179179
},
180-
"haskell.installStack": {
180+
"haskell.toolchain": {
181181
"scope": "resource",
182-
"type": "boolean",
183-
"default": true,
184-
"description": "Whether to also install/manage stack when 'manageHLS' is set to 'GHCup'."
185-
},
186-
"haskell.installCabal": {
187-
"scope": "resource",
188-
"type": "boolean",
189-
"default": true,
190-
"description": "Whether to also install/manage cabal when 'manageHLS' is set to 'GHCup'."
191-
},
192-
"haskell.installGHC": {
193-
"scope": "resource",
194-
"type": "boolean",
195-
"default": true,
196-
"description": "Whether to also install/manage GHC when 'manageHLS' is set to 'GHCup'."
182+
"type": "object",
183+
"default": {},
184+
"description": "When manageHLS is set to GHCup, this can overwrite the automatic toolchain configuration with a more specific one. When a tool is omitted, the extension will manage the version (for 'ghc' we try to figure out the version the project requires). The format is '{\"tool\": \"version\", ...}'. 'version' accepts all identifiers that 'ghcup' accepts."
197185
},
198186
"haskell.upgradeGHCup": {
199187
"scope": "resource",

src/hlsBinaries.ts

Lines changed: 47 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,10 @@ import {
2727
} from './utils';
2828
export { IEnvVars };
2929

30+
type Tool = "hls" | "ghc" | "cabal" | "stack"
31+
32+
type ToolConfig = Map<Tool, string>
33+
3034
export type ReleaseMetadata = Map<string, Map<string, Map<string, string[]>>>;
3135

3236
type ManageHLS = 'GHCup' | 'PATH';
@@ -266,21 +270,42 @@ export async function findHaskellLanguageServer(
266270
} else {
267271
// we manage HLS, make sure ghcup is installed/available
268272
await upgradeGHCup(context, logger);
273+
274+
const toolchainConfig: ToolConfig = new Map(Object.entries(workspace.getConfiguration('haskell').get('toolchain') as any)) as ToolConfig;
275+
let latestHLS: string | undefined | null = undefined;
276+
let latestCabal: string | undefined | null = undefined;
277+
let latestStack: string | undefined | null = undefined;
278+
let recGHC: string | undefined | null = "recommended";
279+
let projectHls: string | undefined | null = undefined;
280+
let projectGhc: string | undefined | null = undefined;
281+
282+
if (toolchainConfig) {
283+
latestHLS = toolchainConfig.get('hls');
284+
latestCabal = toolchainConfig.get('cabal');
285+
latestStack = toolchainConfig.get('stack');
286+
recGHC = toolchainConfig.get('ghc');
287+
288+
projectHls = latestHLS;
289+
projectGhc = recGHC;
290+
}
269291

270292
// get a preliminary toolchain for finding the correct project GHC version
271293
// (we need HLS and cabal/stack and ghc as fallback),
272294
// later we may install a different toolchain that's more project-specific
273-
const latestHLS = await getLatestToolFromGHCup(context, logger, 'hls');
274-
const latestCabal = (workspace.getConfiguration('haskell').get('installCabal') as boolean)
275-
? await getLatestToolFromGHCup(context, logger, 'cabal')
276-
: null;
277-
const latestStack = (workspace.getConfiguration('haskell').get('installStack') as boolean)
278-
? await getLatestToolFromGHCup(context, logger, 'stack')
279-
: null;
280-
const recGHC =
281-
!(await executableExists('ghc')) && (workspace.getConfiguration('haskell').get('installGHC') as boolean)
282-
? await getLatestAvailableToolFromGHCup(context, logger, 'ghc', 'recommended')
283-
: null;
295+
if (latestHLS === undefined) {
296+
latestHLS = await getLatestToolFromGHCup(context, logger, 'hls');
297+
}
298+
if (latestCabal === undefined) {
299+
latestCabal = await getLatestToolFromGHCup(context, logger, 'cabal');
300+
}
301+
if (latestStack === undefined) {
302+
latestStack = await getLatestToolFromGHCup(context, logger, 'stack');
303+
}
304+
if (recGHC === undefined) {
305+
recGHC = !(await executableExists('ghc'))
306+
? await getLatestAvailableToolFromGHCup(context, logger, 'ghc', 'recommended')
307+
: null;
308+
}
284309

285310
const latestToolchainBindir = await callGHCup(
286311
context,
@@ -291,7 +316,7 @@ export async function findHaskellLanguageServer(
291316
latestHLS,
292317
...(latestCabal ? ['--cabal', latestCabal] : []),
293318
...(latestStack ? ['--stack', latestStack] : []),
294-
...(recGHC ? ['--ghc', 'recommended'] : []),
319+
...(recGHC ? ['--ghc', recGHC] : []),
295320
'--install',
296321
],
297322
'Installing latest toolchain for bootstrap',
@@ -303,7 +328,15 @@ export async function findHaskellLanguageServer(
303328

304329
// now figure out the project GHC version and the latest supported HLS version
305330
// we need for it (e.g. this might in fact be a downgrade for old GHCs)
306-
const [projectHls, projectGhc] = await getLatestProjectHLS(context, logger, workingDir, latestToolchainBindir);
331+
if (projectHls === undefined || projectGhc === undefined) {
332+
const res = await getLatestProjectHLS(context, logger, workingDir, latestToolchainBindir);
333+
if (projectHls === undefined) {
334+
projectHls = res[0];
335+
}
336+
if (projectGhc === undefined) {
337+
projectGhc = res[1];
338+
}
339+
}
307340

308341
// now install said version in an isolated symlink directory
309342
const hlsBinDir = await callGHCup(
@@ -315,7 +348,7 @@ export async function findHaskellLanguageServer(
315348
projectHls,
316349
...(latestCabal ? ['--cabal', latestCabal] : []),
317350
...(latestStack ? ['--stack', latestStack] : []),
318-
...((workspace.getConfiguration('haskell').get('installGHC') as boolean) ? ['--ghc', projectGhc] : []),
351+
...(projectGhc ? ['--ghc', projectGhc] : []),
319352
'--install',
320353
],
321354
`Installing project specific toolchain: HLS-${projectHls}, GHC-${projectGhc}, cabal-${latestCabal}, stack-${latestStack}`,

0 commit comments

Comments
 (0)