Skip to content

Commit c78b71b

Browse files
aviateskclaude
andauthored
jetls-client: improve error handling for missing JETLS executable (#335)
When the JETLS executable is not found (ENOENT error), the extension now provides a user-friendly error notification that includes: - The command that was attempted - The current PATH environment variable - A hint to restart VS Code if JETLS is already installed - Buttons to install JETLS or view the installation guide Also refactored URL and command constants to reduce duplication. Co-authored-by: Claude <noreply@anthropic.com>
1 parent 24c5f6a commit c78b71b

File tree

2 files changed

+96
-56
lines changed

2 files changed

+96
-56
lines changed

jetls-client/CHANGELOG.md

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,16 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
1010
- Commit: [`HEAD`](https://github.com/aviatesk/JETLS.jl/commit/HEAD)
1111
- Diff: [`250188fc...HEAD`](https://github.com/aviatesk/JETLS.jl/compare/250188fc...HEAD)
1212

13+
### Improved
14+
15+
- Improved error handling when the JETLS executable is not found (ENOENT error).
16+
The extension now displays a user-friendly error notification with:
17+
- The command that was attempted
18+
- The current PATH environment variable
19+
- A hint to restart VS Code if JETLS is already installed
20+
- Buttons to install JETLS or view the installation guide
21+
(aviatesk/JETLS.jl#332)
22+
1323
## v0.2.2
1424

1525
- Commit: [`250188fc`](https://github.com/aviatesk/JETLS.jl/commit/9008d1b)

jetls-client/jetls-client.ts

Lines changed: 86 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,14 @@ interface ServerConfig {
2828

2929
let currentServerConfig: ServerConfig | null = null;
3030

31+
const JETLS_INSTALL_COMMAND =
32+
'julia -e \'using Pkg; Pkg.Apps.add(; url="https://github.com/aviatesk/JETLS.jl", rev="release")\'';
33+
const JETLS_INSTALL_GUIDE_URL =
34+
"https://github.com/aviatesk/JETLS.jl/blob/master/jetls-client/README.md#getting-started";
35+
const JETLS_CHANGELOG_URL =
36+
"https://github.com/aviatesk/JETLS.jl/blob/master/jetls-client/CHANGELOG.md";
37+
const JETLS_MIGRATION_GUIDE_URL = `${JETLS_CHANGELOG_URL}#v020`;
38+
3139
interface ProcessManager {
3240
process: cp.ChildProcess;
3341
timeoutHandle: NodeJS.Timeout | null;
@@ -86,6 +94,45 @@ function setupProcessMonitoring(
8694
return manager;
8795
}
8896

97+
// Helper to handle spawn errors with user-friendly messages
98+
function handleSpawnError(err: Error, command: string): void {
99+
const errno = err as NodeJS.ErrnoException;
100+
if (errno.code === "ENOENT") {
101+
outputChannel.appendLine(
102+
`[jetls-client] Failed to start JETLS: Command not found: ${command}`,
103+
);
104+
outputChannel.appendLine(`[jetls-client] PATH: ${process.env.PATH}`);
105+
outputChannel.appendLine(
106+
`[jetls-client] Please install JETLS using: ${JETLS_INSTALL_COMMAND}`,
107+
);
108+
outputChannel.appendLine(
109+
`[jetls-client] If JETLS is already installed, try restarting VS Code to refresh the PATH.`,
110+
);
111+
112+
const installButton = "Install JETLS";
113+
const docsButton = "View installation guide";
114+
vscode.window
115+
.showErrorMessage(
116+
`JETLS executable not found: "${command}". Please install JETLS or configure the executable path. If you have already installed JETLS, try restarting VS Code to refresh the PATH.`,
117+
installButton,
118+
docsButton,
119+
)
120+
.then((selection) => {
121+
if (selection === installButton) {
122+
const terminal = vscode.window.createTerminal("Install JETLS");
123+
terminal.show();
124+
terminal.sendText(JETLS_INSTALL_COMMAND, true);
125+
} else if (selection === docsButton) {
126+
vscode.env.openExternal(vscode.Uri.parse(JETLS_INSTALL_GUIDE_URL));
127+
}
128+
});
129+
} else {
130+
outputChannel.appendLine(
131+
`[jetls-client] Failed to start JETLS: ${err.message}`,
132+
);
133+
}
134+
}
135+
89136
// Helper to create timeout handler with cleanup
90137
function createTimeoutHandler(
91138
juliaProcess: cp.ChildProcess,
@@ -281,9 +328,7 @@ async function startLanguageServer() {
281328
});
282329

283330
jetlsProcess.on("error", (err) => {
284-
outputChannel.appendLine(
285-
`[jetls-client] Failed to start JETLS: ${err.message}`,
286-
);
331+
handleSpawnError(err, baseCommand);
287332
if (manager.timeoutHandle) {
288333
clearTimeout(manager.timeoutHandle);
289334
}
@@ -361,9 +406,7 @@ async function startLanguageServer() {
361406
});
362407

363408
jetlsProcess.on("error", (err) => {
364-
outputChannel.appendLine(
365-
`[jetls-client] Failed to start JETLS: ${err.message}`,
366-
);
409+
handleSpawnError(err, baseCommand);
367410
if (manager.timeoutHandle) {
368411
clearTimeout(manager.timeoutHandle);
369412
}
@@ -427,26 +470,34 @@ async function startLanguageServer() {
427470
"Loading JETLS and attempting to establish communication between client and server.";
428471
statusBarItem.show();
429472

430-
languageClient.start().then(() => {
431-
statusBarItem.hide();
432-
outputChannel.appendLine("[jetls-client] JETLS is ready!");
433-
434-
// Register handler for workspace/configuration requests after client starts
435-
languageClient.onRequest(
436-
"workspace/configuration",
437-
(params: { items: { scopeUri?: string; section?: string | null }[] }) => {
438-
const items = params.items || [];
439-
const results = items.map((item) => {
440-
const section = "jetls-client.settings";
441-
const scope = item.scopeUri
442-
? vscode.Uri.parse(item.scopeUri)
443-
: undefined;
444-
return vscode.workspace.getConfiguration(section, scope);
445-
});
446-
return results;
447-
},
448-
);
449-
});
473+
languageClient
474+
.start()
475+
.then(() => {
476+
statusBarItem.hide();
477+
outputChannel.appendLine("[jetls-client] JETLS is ready!");
478+
479+
// Register handler for workspace/configuration requests after client starts
480+
languageClient.onRequest(
481+
"workspace/configuration",
482+
(params: {
483+
items: { scopeUri?: string; section?: string | null }[];
484+
}) => {
485+
const items = params.items || [];
486+
const results = items.map((item) => {
487+
const section = "jetls-client.settings";
488+
const scope = item.scopeUri
489+
? vscode.Uri.parse(item.scopeUri)
490+
: undefined;
491+
return vscode.workspace.getConfiguration(section, scope);
492+
});
493+
return results;
494+
},
495+
);
496+
})
497+
.catch((err) => {
498+
statusBarItem.hide();
499+
handleSpawnError(err, baseCommand);
500+
});
450501
}
451502

452503
async function restartLanguageServer() {
@@ -474,7 +525,7 @@ async function checkForUpdates(context: ExtensionContext): Promise<void> {
474525
"Welcome to JETLS Client! To use this extension, you need to install the JETLS executable. " +
475526
"Click 'Install JETLS' to get started.";
476527
const installButton = "Install JETLS";
477-
const docsButton = "View Installation Guide";
528+
const docsButton = "View installation guide";
478529

479530
const selection = await vscode.window.showInformationMessage(
480531
message,
@@ -485,16 +536,9 @@ async function checkForUpdates(context: ExtensionContext): Promise<void> {
485536
if (selection === installButton) {
486537
const terminal = vscode.window.createTerminal("Install JETLS");
487538
terminal.show();
488-
terminal.sendText(
489-
'julia -e \'using Pkg; Pkg.Apps.add(; url="https://github.com/aviatesk/JETLS.jl", rev="release")\'',
490-
true,
491-
);
539+
terminal.sendText(JETLS_INSTALL_COMMAND, true);
492540
} else if (selection === docsButton) {
493-
vscode.env.openExternal(
494-
vscode.Uri.parse(
495-
"https://github.com/aviatesk/JETLS.jl/blob/master/jetls-client/README.md#getting-started",
496-
),
497-
);
541+
vscode.env.openExternal(vscode.Uri.parse(JETLS_INSTALL_GUIDE_URL));
498542
}
499543
} else if (
500544
currentVersion &&
@@ -511,7 +555,7 @@ async function checkForUpdates(context: ExtensionContext): Promise<void> {
511555
"JETLS Client v0.2.0 requires reinstalling JETLS with the new installation method. " +
512556
"Click 'Reinstall JETLS' to run the installation command.";
513557
const reinstallButton = "Reinstall JETLS";
514-
const migrationGuideButton = "View Migration Guide";
558+
const migrationGuideButton = "View migration guide";
515559

516560
const selection = await vscode.window.showWarningMessage(
517561
message,
@@ -522,23 +566,16 @@ async function checkForUpdates(context: ExtensionContext): Promise<void> {
522566
if (selection === reinstallButton) {
523567
const terminal = vscode.window.createTerminal("Reinstall JETLS");
524568
terminal.show();
525-
terminal.sendText(
526-
'julia -e \'using Pkg; Pkg.Apps.add(; url="https://github.com/aviatesk/JETLS.jl", rev="release")\'',
527-
true,
528-
);
569+
terminal.sendText(JETLS_INSTALL_COMMAND, true);
529570
} else if (selection === migrationGuideButton) {
530-
vscode.env.openExternal(
531-
vscode.Uri.parse(
532-
"https://github.com/aviatesk/JETLS.jl/blob/master/jetls-client/CHANGELOG.md#v020",
533-
),
534-
);
571+
vscode.env.openExternal(vscode.Uri.parse(JETLS_MIGRATION_GUIDE_URL));
535572
}
536573
} else {
537574
// Normal update
538575
const message =
539576
"JETLS Client has been updated! Please make sure to update the JETLS server as well.";
540577
const updateButton = "Update JETLS";
541-
const changelogButton = "View Changelog";
578+
const changelogButton = "View CHANGELOG.md";
542579

543580
const selection = await vscode.window.showInformationMessage(
544581
message,
@@ -549,16 +586,9 @@ async function checkForUpdates(context: ExtensionContext): Promise<void> {
549586
if (selection === updateButton) {
550587
const terminal = vscode.window.createTerminal("Update JETLS");
551588
terminal.show();
552-
terminal.sendText(
553-
'julia -e \'using Pkg; Pkg.Apps.add(; url="https://github.com/aviatesk/JETLS.jl", rev="release")\'',
554-
true,
555-
);
589+
terminal.sendText(JETLS_INSTALL_COMMAND, true);
556590
} else if (selection === changelogButton) {
557-
vscode.env.openExternal(
558-
vscode.Uri.parse(
559-
"https://github.com/aviatesk/JETLS.jl/blob/master/jetls-client/CHANGELOG.md",
560-
),
561-
);
591+
vscode.env.openExternal(vscode.Uri.parse(JETLS_CHANGELOG_URL));
562592
}
563593
}
564594
}

0 commit comments

Comments
 (0)