Skip to content

Commit 1a2b356

Browse files
authored
Merge pull request #605 from hasufell/cleanups
Cleanups
2 parents 902204c + 4398241 commit 1a2b356

File tree

5 files changed

+67
-61
lines changed

5 files changed

+67
-61
lines changed

.github/workflows/test.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ jobs:
1212
fail-fast: false
1313
matrix:
1414
os: [macos-11, ubuntu-latest, windows-latest]
15-
ghc: [9.0.1, 8.10.4]
15+
ghc: [9.0.2, 8.10.4]
1616
runs-on: ${{ matrix.os }}
1717
steps:
1818
- name: Checkout

src/errors.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,6 @@ export class NoMatchingHls extends Error {
5454
super(`HLS does not support GHC ${ghcProjVersion} yet.`);
5555
}
5656
public docLink(): Uri {
57-
return Uri.parse('https://haskell-language-server.readthedocs.io/en/latest/supported-versions.html');
57+
return Uri.parse('https://haskell-language-server.readthedocs.io/en/latest/supported-versions.html');
5858
}
5959
}

src/extension.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -223,7 +223,7 @@ async function activateServerForFolder(context: ExtensionContext, uri: Uri, fold
223223

224224
let serverEnvironment: IEnvVars = await workspace.getConfiguration('haskell', uri).serverEnvironment;
225225
if (addInternalServerPath !== undefined) {
226-
const newPath = await addPathToProcessPath(addInternalServerPath, logger);
226+
const newPath = await addPathToProcessPath(addInternalServerPath);
227227
serverEnvironment = {
228228
...serverEnvironment,
229229
...{ PATH: newPath },

src/hlsBinaries.ts

Lines changed: 59 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@ import { stat } from 'fs/promises';
55
import * as https from 'https';
66
import * as path from 'path';
77
import { match } from 'ts-pattern';
8-
import * as url from 'url';
98
import { promisify } from 'util';
109
import { ConfigurationTarget, ExtensionContext, ProgressLocation, window, workspace, WorkspaceFolder } from 'vscode';
1110
import { Logger } from 'vscode-languageclient';
@@ -68,7 +67,7 @@ async function callAsync(
6867
envAdd?: IEnvVars,
6968
callback?: ProcessCallback
7069
): Promise<string> {
71-
let newEnv: IEnvVars = await resolveServerEnvironmentPATH(
70+
let newEnv: IEnvVars = resolveServerEnvironmentPATH(
7271
workspace.getConfiguration('haskell').get('serverEnvironment') || {}
7372
);
7473
newEnv = { ...(process.env as IEnvVars), ...newEnv, ...(envAdd || {}) };
@@ -135,15 +134,14 @@ async function callAsync(
135134
/** Gets serverExecutablePath and fails if it's not set.
136135
*/
137136
async function findServerExecutable(
138-
context: ExtensionContext,
139137
logger: Logger,
140138
folder?: WorkspaceFolder
141139
): Promise<string> {
142140
let exePath = workspace.getConfiguration('haskell').get('serverExecutablePath') as string;
143141
logger.info(`Trying to find the server executable in: ${exePath}`);
144142
exePath = resolvePathPlaceHolders(exePath, folder);
145143
logger.log(`Location after path variables substitution: ${exePath}`);
146-
if (await executableExists(exePath)) {
144+
if (executableExists(exePath)) {
147145
return exePath;
148146
} else {
149147
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(
153151

154152
/** Searches the PATH. Fails if nothing is found.
155153
*/
156-
async function findHLSinPATH(context: ExtensionContext, logger: Logger, folder?: WorkspaceFolder): Promise<string> {
154+
async function findHLSinPATH(_context: ExtensionContext, logger: Logger): Promise<string> {
157155
// try PATH
158156
const exes: string[] = ['haskell-language-server-wrapper', 'haskell-language-server'];
159157
logger.info(`Searching for server executables ${exes.join(',')} in $PATH`);
160158
logger.info(`$PATH environment variable: ${process.env.PATH}`);
161159
for (const exe of exes) {
162-
if (await executableExists(exe)) {
160+
if (executableExists(exe)) {
163161
logger.info(`Found server executable in $PATH: ${exe}`);
164162
return exe;
165163
}
@@ -189,7 +187,7 @@ export async function findHaskellLanguageServer(
189187
logger.info('Finding haskell-language-server');
190188

191189
if (workspace.getConfiguration('haskell').get('serverExecutablePath') as string) {
192-
const exe = await findServerExecutable(context, logger, folder);
190+
const exe = await findServerExecutable(logger, folder);
193191
return [exe, undefined];
194192
}
195193

@@ -226,7 +224,7 @@ export async function findHaskellLanguageServer(
226224
}
227225

228226
if (manageHLS === 'PATH') {
229-
const exe = await findHLSinPATH(context, logger, folder);
227+
const exe = await findHLSinPATH(context, logger);
230228
return [exe, undefined];
231229
} else {
232230
// we manage HLS, make sure ghcup is installed/available
@@ -267,40 +265,42 @@ export async function findHaskellLanguageServer(
267265
latestStack = await getLatestToolFromGHCup(context, logger, 'stack');
268266
}
269267
if (recGHC === undefined) {
270-
recGHC = !(await executableExists('ghc'))
268+
recGHC = !executableExists('ghc')
271269
? await getLatestAvailableToolFromGHCup(context, logger, 'ghc', 'recommended')
272270
: null;
273271
}
274272

275273
// download popups
276274
const promptBeforeDownloads = workspace.getConfiguration('haskell').get('promptBeforeDownloads') as boolean;
277275
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;
287279
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[];
293291
if (toInstall.length > 0) {
294292
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?`,
296294
'Yes',
297295
'No',
298296
"Yes, don't ask again"
299297
);
300298
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(', ')}.`);
302300
} 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+
);
304304
workspace.getConfiguration('haskell').update('promptBeforeDownloads', false);
305305
} else {
306306
toInstall.forEach((tool) => {
@@ -353,26 +353,25 @@ export async function findHaskellLanguageServer(
353353

354354
// more download popups
355355
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[];
364361
if (toInstall.length > 0) {
365362
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?`,
367364
{ modal: true },
368365
'Yes',
369366
'No',
370367
"Yes, don't ask again"
371368
);
372369
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(', ')}.`);
374371
} 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+
);
376375
workspace.getConfiguration('haskell').update('promptBeforeDownloads', false);
377376
} else {
378377
toInstall.forEach((tool) => {
@@ -400,14 +399,22 @@ export async function findHaskellLanguageServer(
400399
...(projectGhc ? ['--ghc', projectGhc] : []),
401400
'--install',
402401
],
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(', ')}`,
404411
true
405412
);
406413

407414
if (projectHls) {
408415
return [path.join(hlsBinDir, `haskell-language-server-wrapper${exeExt}`), hlsBinDir];
409416
} else {
410-
const exe = await findHLSinPATH(context, logger, folder);
417+
const exe = await findHLSinPATH(context, logger);
411418
return [exe, hlsBinDir];
412419
}
413420
}
@@ -470,8 +477,8 @@ async function getLatestProjectHLS(
470477
const merged = new Map<string, string[]>([...metadataMap, ...ghcupMap]); // right-biased
471478
// now sort and get the latest suitable version
472479
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))
475482
.pop();
476483

477484
if (!latest) {
@@ -484,7 +491,7 @@ async function getLatestProjectHLS(
484491
/**
485492
* Obtain the project ghc version from the HLS - Wrapper (which must be in PATH now).
486493
* 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)
488495
* @param workingDir Directory to run the process, usually the root of the workspace.
489496
* @param logger Logger for feedback.
490497
* @returns The GHC version, or fail with an `Error`.
@@ -499,7 +506,7 @@ export async function getProjectGHCVersion(
499506

500507
const args = ['--project-ghc-version'];
501508

502-
const newPath = await addPathToProcessPath(toolchainBindir, logger);
509+
const newPath = await addPathToProcessPath(toolchainBindir);
503510
const environmentNew: IEnvVars = {
504511
PATH: newPath,
505512
};
@@ -550,14 +557,14 @@ export async function upgradeGHCup(context: ExtensionContext, logger: Logger): P
550557
}
551558
}
552559

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> {
554561
logger.info('Checking for ghcup installation');
555562
let exePath = workspace.getConfiguration('haskell').get('ghcupExecutablePath') as string;
556563
if (exePath) {
557564
logger.info(`Trying to find the ghcup executable in: ${exePath}`);
558565
exePath = resolvePathPlaceHolders(exePath, folder);
559566
logger.log(`Location after path variables substitution: ${exePath}`);
560-
if (await executableExists(exePath)) {
567+
if (executableExists(exePath)) {
561568
return exePath;
562569
} else {
563570
throw new Error(`Could not find a ghcup binary at ${exePath}!`);
@@ -684,8 +691,8 @@ async function toolInstalled(
684691
version: string
685692
): Promise<InstalledTool> {
686693
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);
689696
return new InstalledTool(tool, version, b);
690697
}
691698

@@ -737,7 +744,7 @@ export type ReleaseMetadata = Map<string, Map<string, Map<string, string[]>>>;
737744
*/
738745
async function getHLSesfromMetadata(context: ExtensionContext, logger: Logger): Promise<Map<string, string[]> | null> {
739746
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);
741748
if (!metadata) {
742749
window.showErrorMessage('Could not get release metadata');
743750
return null;
@@ -803,23 +810,23 @@ export function findSupportedHlsPerGhc(
803810
/**
804811
* Download GHCUP metadata.
805812
*
806-
* @param context Extension context.
813+
* @param _context Extension context.
807814
* @param storagePath Path to put in binary files and caches.
808815
* @param logger Logger for feedback.
809816
* @returns Metadata of releases, or null if the cache can not be found.
810817
*/
811818
async function getReleaseMetadata(
812-
context: ExtensionContext,
819+
_context: ExtensionContext,
813820
storagePath: string,
814821
logger: Logger
815822
): Promise<ReleaseMetadata | null> {
816823
const releasesUrl = workspace.getConfiguration('haskell').releasesURL
817-
? url.parse(workspace.getConfiguration('haskell').releasesURL)
824+
? new URL(workspace.getConfiguration('haskell').releasesURL)
818825
: undefined;
819826
const opts: https.RequestOptions = releasesUrl
820827
? {
821828
host: releasesUrl.host,
822-
path: releasesUrl.path,
829+
path: releasesUrl.pathname,
823830
}
824831
: {
825832
host: 'raw.githubusercontent.com',

src/utils.ts

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@ import * as http from 'http';
66
import * as https from 'https';
77
import * as os from 'os';
88
import { extname } from 'path';
9-
import * as url from 'url';
109
import { promisify } from 'util';
1110
import { OutputChannel, ProgressLocation, window, workspace, WorkspaceFolder } from 'vscode';
1211
import { Logger } from 'vscode-languageclient';
@@ -215,10 +214,10 @@ export async function downloadFile(titleMsg: string, src: string, dest: string):
215214
},
216215
async (progress) => {
217216
const p = new Promise<void>((resolve, reject) => {
218-
const srcUrl = url.parse(src);
217+
const srcUrl = new URL(src);
219218
const opts: https.RequestOptions = {
220219
host: srcUrl.host,
221-
path: srcUrl.path,
220+
path: srcUrl.pathname,
222221
protocol: srcUrl.protocol,
223222
port: srcUrl.port,
224223
headers: userAgentHeader,
@@ -230,9 +229,9 @@ export async function downloadFile(titleMsg: string, src: string, dest: string):
230229

231230
// Decompress it if it's a gzip or zip
232231
const needsGunzip =
233-
res.headers['content-type'] === 'application/gzip' || extname(srcUrl.path ?? '') === '.gz';
232+
res.headers['content-type'] === 'application/gzip' || extname(srcUrl.pathname ?? '') === '.gz';
234233
const needsUnzip =
235-
res.headers['content-type'] === 'application/zip' || extname(srcUrl.path ?? '') === '.zip';
234+
res.headers['content-type'] === 'application/zip' || extname(srcUrl.pathname ?? '') === '.zip';
236235
if (needsGunzip) {
237236
const gunzip = createGunzip();
238237
gunzip.on('error', reject);
@@ -360,7 +359,7 @@ export function resolvePATHPlaceHolders(path: string) {
360359
}
361360

362361
// also honours serverEnvironment.PATH
363-
export async function addPathToProcessPath(extraPath: string, logger: Logger): Promise<string> {
362+
export async function addPathToProcessPath(extraPath: string): Promise<string> {
364363
const pathSep = process.platform === 'win32' ? ';' : ':';
365364
const serverEnvironment: IEnvVars = (await workspace.getConfiguration('haskell').get('serverEnvironment')) || {};
366365
const path: string[] = serverEnvironment.PATH

0 commit comments

Comments
 (0)