Skip to content

Commit 3a844c7

Browse files
committed
feat: add restart language server command
1 parent 18abce0 commit 3a844c7

File tree

6 files changed

+63
-5
lines changed

6 files changed

+63
-5
lines changed

README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,8 @@
1111
1212
## Features
1313

14-
- Syntax highlighting for `.hsml` files
15-
- Diagnostics and hover via the [hsml](https://github.com/hsml-lab/hsml) language server
14+
- Syntax highlighting for `.hsml` files and `<template lang="hsml">` in Vue SFCs
15+
- Diagnostics, hover, and formatting via the [hsml](https://github.com/hsml-lab/hsml) language server
1616
- Auto-download of the `hsml` binary from GitHub releases
1717
- Comment toggling (`//` line comments)
1818
- Bracket matching and auto-closing pairs

client/src/extension.ts

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
11
import type { ExtensionContext } from 'vscode';
2-
import { workspace } from 'vscode';
2+
import { commands, workspace } from 'vscode';
33
import type { Executable, LanguageClientOptions, ServerOptions } from 'vscode-languageclient/node';
44
import { LanguageClient } from 'vscode-languageclient/node';
55
import { resolveServerPath } from './binary.js';
66

77
let client: LanguageClient | undefined;
88

9-
export async function activate(context: ExtensionContext) {
9+
async function startClient(context: ExtensionContext): Promise<void> {
1010
const serverPath = await resolveServerPath(context);
1111
if (!serverPath) {
1212
return;
@@ -36,7 +36,21 @@ export async function activate(context: ExtensionContext) {
3636
clientOptions,
3737
);
3838

39-
client.start();
39+
await client.start();
40+
}
41+
42+
export async function activate(context: ExtensionContext) {
43+
context.subscriptions.push(
44+
commands.registerCommand('hsml.restartLanguageServer', async () => {
45+
if (client) {
46+
await client.restart();
47+
} else {
48+
await startClient(context);
49+
}
50+
}),
51+
);
52+
53+
await startClient(context);
4054
}
4155

4256
export function deactivate(): Promise<void> | undefined {

package.json

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,12 @@
5555
"vscode-tmgrammar-test": "0.1.3"
5656
},
5757
"contributes": {
58+
"commands": [
59+
{
60+
"command": "hsml.restartLanguageServer",
61+
"title": "HSML: Restart Language Server"
62+
}
63+
],
5864
"configuration": {
5965
"type": "object",
6066
"title": "HSML configuration",

tests/__mocks__/vscode-languageclient-node.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,10 @@ import { vi } from 'vitest';
22

33
export const mockStart = vi.fn();
44
export const mockStop = vi.fn(() => Promise.resolve());
5+
export const mockRestart = vi.fn(() => Promise.resolve());
56

67
export class LanguageClient {
78
start = mockStart;
89
stop = mockStop;
10+
restart = mockRestart;
911
}

tests/__mocks__/vscode.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,4 +28,7 @@ export const Uri = {
2828

2929
export const commands = {
3030
executeCommand: vi.fn(),
31+
registerCommand: vi.fn((_command: string, _callback: (...args: unknown[]) => unknown) => ({
32+
dispose: vi.fn(),
33+
})),
3134
};

tests/extension.test.ts

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import { resolveServerPath } from './__mocks__/binary.js';
44

55
const mockContext = {
66
globalStorageUri: { fsPath: '/tmp/test-storage' },
7+
subscriptions: [],
78
} as unknown as ExtensionContext;
89

910
beforeEach(() => {
@@ -40,6 +41,38 @@ describe('activate', () => {
4041
});
4142
});
4243

44+
describe('activate', () => {
45+
it('should register restart command', async () => {
46+
const { commands } = await import('vscode');
47+
const { activate } = await import('../client/src/extension.js');
48+
await activate(mockContext);
49+
50+
expect(commands.registerCommand).toHaveBeenCalledWith(
51+
'hsml.restartLanguageServer',
52+
expect.any(Function),
53+
);
54+
});
55+
});
56+
57+
describe('restart command', () => {
58+
it('should call restart on existing client', async () => {
59+
const { commands } = await import('vscode');
60+
const { mockRestart } = await import('./__mocks__/vscode-languageclient-node.js');
61+
const { activate } = await import('../client/src/extension.js');
62+
await activate(mockContext);
63+
64+
// Get the registered callback
65+
const registerCall = (commands.registerCommand as ReturnType<typeof vi.fn>).mock.calls.find(
66+
(call) => call[0] === 'hsml.restartLanguageServer',
67+
);
68+
const restartCallback = registerCall?.[1] as () => Promise<void>;
69+
await restartCallback();
70+
71+
expect(mockRestart).toHaveBeenCalled();
72+
});
73+
74+
});
75+
4376
describe('deactivate', () => {
4477
it('should stop the client when active', async () => {
4578
const { mockStop } = await import('./__mocks__/vscode-languageclient-node.js');

0 commit comments

Comments
 (0)