-
Notifications
You must be signed in to change notification settings - Fork 544
Expand file tree
/
Copy pathstandardLanguageClientStart.ts
More file actions
66 lines (58 loc) · 2.27 KB
/
Copy pathstandardLanguageClientStart.ts
File metadata and controls
66 lines (58 loc) · 2.27 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
import { Executable, ServerOptions, TransportKind } from "vscode-languageclient/node";
export interface StartableLanguageClient {
start(): Promise<void>;
}
export interface StartWithStdioFallbackOptions<T extends StartableLanguageClient> {
languageClient: T;
serverOptions: ServerOptions;
createLanguageClient(serverOptions: Executable): T;
pipeStartTimeout: number;
onFallback?(error: any): void;
}
class PipeStartTimeoutError extends Error {
}
export async function startWithStdioFallback<T extends StartableLanguageClient>(options: StartWithStdioFallbackOptions<T>): Promise<{ client: T; serverOptions: ServerOptions }> {
if (!isPipeExecutable(options.serverOptions)) {
await options.languageClient.start();
return { client: options.languageClient, serverOptions: options.serverOptions };
}
try {
await startWithTimeout(options.languageClient, options.pipeStartTimeout);
return { client: options.languageClient, serverOptions: options.serverOptions };
} catch (error) {
if (!(error instanceof PipeStartTimeoutError)) {
throw error;
}
options.onFallback?.(error);
const stdioServerOptions = createStdioServerOptions(options.serverOptions);
const stdioClient = options.createLanguageClient(stdioServerOptions);
await stdioClient.start();
return { client: stdioClient, serverOptions: stdioServerOptions };
}
}
async function startWithTimeout(client: StartableLanguageClient, timeout: number): Promise<void> {
let timeoutHandle: NodeJS.Timeout | undefined;
try {
await Promise.race([
client.start(),
new Promise<void>((_resolve, reject) => {
timeoutHandle = setTimeout(() => reject(new PipeStartTimeoutError(`Starting pipe transport timed out after ${timeout}ms.`)), timeout);
})
]);
} finally {
if (timeoutHandle) {
clearTimeout(timeoutHandle);
}
}
}
function isPipeExecutable(serverOptions: ServerOptions): serverOptions is Executable {
return !!serverOptions && typeof (serverOptions as Executable).command === 'string' && (serverOptions as Executable).transport === TransportKind.pipe;
}
function createStdioServerOptions(serverOptions: Executable): Executable {
return {
...serverOptions,
args: serverOptions.args?.slice(),
options: serverOptions.options ? { ...serverOptions.options } : undefined,
transport: TransportKind.stdio,
};
}