Skip to content
This repository was archived by the owner on Dec 25, 2023. It is now read-only.

Commit 4a7ae27

Browse files
authored
Handle language server crashes (#106)
* Handle language server crashes Relates to #91 * test language server crash behavior * lint * Update nova editor types * Update CHANGELOG.md
1 parent 8ea0249 commit 4a7ae27

File tree

6 files changed

+82
-12
lines changed

6 files changed

+82
-12
lines changed

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@
3030
"@rollup/plugin-commonjs": "^15.1.0",
3131
"@rollup/plugin-node-resolve": "^9.0.0",
3232
"@types/jest": "^26.0.15",
33-
"@types/nova-editor-node": "^1.2.2",
33+
"@types/nova-editor-node": "^2.0.0",
3434
"@typescript-eslint/eslint-plugin": "^4.0.0",
3535
"@typescript-eslint/parser": "^3.10.1",
3636
"concurrently": "^5.3.0",

src/main.test.ts

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ jest.useFakeTimers();
1414
(global as any).nova = Object.assign(nova, {
1515
commands: {
1616
register: jest.fn(),
17+
invoke: jest.fn(),
1718
},
1819
workspace: {
1920
path: "/workspace",
@@ -71,6 +72,7 @@ describe("test suite", () => {
7172
LanguageClientMock.mockReset().mockImplementation(() => ({
7273
onRequest: jest.fn(),
7374
onNotification: jest.fn(),
75+
onDidStop: jest.fn(),
7476
start: jest.fn(),
7577
stop: jest.fn(),
7678
}));
@@ -230,6 +232,50 @@ describe("test suite", () => {
230232
);
231233
});
232234

235+
it("handles unexpected crashes", async () => {
236+
resetMocks();
237+
nova.workspace.showActionPanel = jest.fn();
238+
239+
await activate();
240+
241+
const languageClient: LanguageClient =
242+
LanguageClientMock.mock.results[0].value;
243+
const stopCallback = (languageClient.onDidStop as jest.Mock).mock
244+
.calls[0][0];
245+
246+
stopCallback(new Error("Mock language server crash"));
247+
248+
expect(nova.workspace.showActionPanel).toBeCalledTimes(1);
249+
const actionPanelCall = (nova.workspace.showActionPanel as jest.Mock).mock
250+
.calls[0];
251+
expect(actionPanelCall[0]).toMatchInlineSnapshot(`
252+
"TypeScript Language Server stopped unexpectedly:
253+
254+
Error: Mock language server crash
255+
256+
Please report this, along with any output in the Extension Console."
257+
`);
258+
expect(actionPanelCall[1].buttons).toHaveLength(2);
259+
260+
const informationView = (informationViewModule.InformationView as jest.Mock<
261+
informationViewModule.InformationView
262+
>).mock.instances[0];
263+
expect(informationView.status).toBe("Stopped");
264+
265+
const actionCallback = actionPanelCall[2];
266+
267+
// reload
268+
expect(nova.commands.invoke).not.toBeCalled();
269+
actionCallback(0);
270+
expect(nova.commands.invoke).toBeCalledTimes(1);
271+
expect(nova.commands.invoke).toBeCalledWith(
272+
"apexskier.typescript.reload"
273+
);
274+
275+
// ignore
276+
actionCallback(1);
277+
});
278+
233279
test("reload", async () => {
234280
resetMocks();
235281

src/main.ts

Lines changed: 24 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -158,14 +158,31 @@ async function asyncActivate() {
158158
compositeDisposable.add(registerSignatureHelp(client));
159159
}
160160

161-
// Not working, I'm guessing Nova intercepts this notification.
162-
client.onNotification("initialized", () => {
163-
console.log("initialized");
164-
});
161+
compositeDisposable.add(
162+
client.onDidStop((err) => {
163+
informationView.status = "Stopped";
165164

166-
client.onNotification("window/showMessage", (params) => {
167-
console.log("window/showMessage", JSON.stringify(params));
168-
});
165+
let message = "TypeScript Language Server stopped unexpectedly";
166+
if (err) {
167+
message += `:\n\n${err.toString()}`;
168+
} else {
169+
message += ".";
170+
}
171+
message +=
172+
"\n\nPlease report this, along with any output in the Extension Console.";
173+
nova.workspace.showActionPanel(
174+
message,
175+
{
176+
buttons: ["Restart", "Ignore"],
177+
},
178+
(index) => {
179+
if (index == 0) {
180+
nova.commands.invoke("apexskier.typescript.reload");
181+
}
182+
}
183+
);
184+
})
185+
);
169186

170187
client.start();
171188

typescript.novaextension/CHANGELOG.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,11 @@
11
# Changelog
22

3+
## future
4+
5+
## Fixed
6+
7+
- Handle language server crashes more gracefully
8+
39
## v2.0.0
410

511
### Fixed

typescript.novaextension/extension.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
"bugs": "https://github.com/apexskier/nova-typescript/issues",
1111

1212
"main": "main.dist.js",
13+
"min_runtime": "2.0",
1314

1415
"activationEvents": [
1516
"onLanguage:typescript",

yarn.lock

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -678,10 +678,10 @@
678678
resolved "https://registry.yarnpkg.com/@types/normalize-package-data/-/normalize-package-data-2.4.0.tgz#e486d0d97396d79beedd0a6e33f4534ff6b4973e"
679679
integrity sha512-f5j5b/Gf71L+dbqxIpQ4Z2WlmI/mPJ0fOkGGmFgtb6sAu97EPczzbS3/tJKxmcYDj55OX6ssqwDAWOHIYDRDGA==
680680

681-
"@types/nova-editor-node@^1.2.2":
682-
version "1.2.2"
683-
resolved "https://registry.yarnpkg.com/@types/nova-editor-node/-/nova-editor-node-1.2.2.tgz#4da949f86621a46c2e7fc2dfcbb01db06a0e6fb8"
684-
integrity sha512-4FgSEzeeGWHIhU3v48+Eap+zjeoddMmXl2fv8zpFbVWIx3bXrIR7ATn+9Z41bHg0+AGdWU8BOenpo0oDpTz0+A==
681+
"@types/nova-editor-node@^2.0.0":
682+
version "2.0.0"
683+
resolved "https://registry.yarnpkg.com/@types/nova-editor-node/-/nova-editor-node-2.0.0.tgz#1e948c0ce355590ca4b69ff25fef5e166fc5f7bd"
684+
integrity sha512-vbE4WkHKaR/NJBz/ge+ygdacVlTU1mOtZr75AgZrGK07XrHZUiAoBWp1nMIb6/JEuOM0jgu02N0AJr3iS3JmNw==
685685

686686
"@types/prettier@^2.0.0":
687687
version "2.0.2"

0 commit comments

Comments
 (0)