@difizen/libro-lsp 0.1.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +0 -0
- package/es/adapters/adapter.d.ts +255 -0
- package/es/adapters/adapter.d.ts.map +1 -0
- package/es/adapters/adapter.js +647 -0
- package/es/adapters/notebook-adapter.d.ts +150 -0
- package/es/adapters/notebook-adapter.d.ts.map +1 -0
- package/es/adapters/notebook-adapter.js +588 -0
- package/es/adapters/status-message.d.ts +48 -0
- package/es/adapters/status-message.d.ts.map +1 -0
- package/es/adapters/status-message.js +110 -0
- package/es/connection-manager.d.ts +199 -0
- package/es/connection-manager.d.ts.map +1 -0
- package/es/connection-manager.js +685 -0
- package/es/connection.d.ts +149 -0
- package/es/connection.d.ts.map +1 -0
- package/es/connection.js +591 -0
- package/es/extractors/index.d.ts +4 -0
- package/es/extractors/index.d.ts.map +1 -0
- package/es/extractors/index.js +6 -0
- package/es/extractors/manager.d.ts +31 -0
- package/es/extractors/manager.d.ts.map +1 -0
- package/es/extractors/manager.js +90 -0
- package/es/extractors/text-extractor.d.ts +56 -0
- package/es/extractors/text-extractor.d.ts.map +1 -0
- package/es/extractors/text-extractor.js +72 -0
- package/es/extractors/types.d.ts +68 -0
- package/es/extractors/types.d.ts.map +1 -0
- package/es/extractors/types.js +1 -0
- package/es/feature.d.ts +29 -0
- package/es/feature.d.ts.map +1 -0
- package/es/feature.js +85 -0
- package/es/index.d.ts +19 -0
- package/es/index.d.ts.map +1 -0
- package/es/index.js +21 -0
- package/es/lsp-app-contribution.d.ts +19 -0
- package/es/lsp-app-contribution.d.ts.map +1 -0
- package/es/lsp-app-contribution.js +155 -0
- package/es/lsp-protocol.d.ts +10 -0
- package/es/lsp-protocol.d.ts.map +1 -0
- package/es/lsp-protocol.js +1 -0
- package/es/lsp.d.ts +136 -0
- package/es/lsp.d.ts.map +1 -0
- package/es/lsp.js +141 -0
- package/es/manager.d.ts +142 -0
- package/es/manager.d.ts.map +1 -0
- package/es/manager.js +423 -0
- package/es/module.d.ts +3 -0
- package/es/module.d.ts.map +1 -0
- package/es/module.js +21 -0
- package/es/plugin.d.ts +56 -0
- package/es/plugin.d.ts.map +1 -0
- package/es/plugin.js +0 -0
- package/es/positioning.d.ts +66 -0
- package/es/positioning.d.ts.map +1 -0
- package/es/positioning.js +96 -0
- package/es/schema.d.ts +240 -0
- package/es/schema.d.ts.map +1 -0
- package/es/schema.js +0 -0
- package/es/tokens.d.ts +677 -0
- package/es/tokens.d.ts.map +1 -0
- package/es/tokens.js +183 -0
- package/es/utils.d.ts +33 -0
- package/es/utils.d.ts.map +1 -0
- package/es/utils.js +168 -0
- package/es/virtual/document.d.ts +546 -0
- package/es/virtual/document.d.ts.map +1 -0
- package/es/virtual/document.js +1263 -0
- package/es/ws-connection/server-capability-registration.d.ts +19 -0
- package/es/ws-connection/server-capability-registration.d.ts.map +1 -0
- package/es/ws-connection/server-capability-registration.js +51 -0
- package/es/ws-connection/types.d.ts +76 -0
- package/es/ws-connection/types.d.ts.map +1 -0
- package/es/ws-connection/types.js +1 -0
- package/es/ws-connection/ws-connection.d.ts +105 -0
- package/es/ws-connection/ws-connection.d.ts.map +1 -0
- package/es/ws-connection/ws-connection.js +301 -0
- package/package.json +67 -0
- package/src/adapters/adapter.ts +611 -0
- package/src/adapters/notebook-adapter.ts +463 -0
- package/src/adapters/status-message.ts +93 -0
- package/src/connection-manager.ts +626 -0
- package/src/connection.ts +570 -0
- package/src/extractors/index.ts +6 -0
- package/src/extractors/manager.ts +82 -0
- package/src/extractors/text-extractor.ts +94 -0
- package/src/extractors/types.ts +78 -0
- package/src/feature.ts +60 -0
- package/src/index.spec.ts +10 -0
- package/src/index.ts +21 -0
- package/src/lsp-app-contribution.ts +83 -0
- package/src/lsp-protocol.ts +10 -0
- package/src/lsp.ts +160 -0
- package/src/manager.ts +358 -0
- package/src/module.ts +32 -0
- package/src/plugin.ts +62 -0
- package/src/positioning.ts +121 -0
- package/src/schema.ts +249 -0
- package/src/tokens.ts +843 -0
- package/src/utils.ts +109 -0
- package/src/virtual/document.ts +1250 -0
- package/src/ws-connection/server-capability-registration.ts +77 -0
- package/src/ws-connection/types.ts +102 -0
- package/src/ws-connection/ws-connection.ts +320 -0
|
@@ -0,0 +1,570 @@
|
|
|
1
|
+
/* eslint-disable @typescript-eslint/no-parameter-properties */
|
|
2
|
+
/* eslint-disable @typescript-eslint/parameter-properties */
|
|
3
|
+
/* eslint-disable @typescript-eslint/no-unused-vars */
|
|
4
|
+
/* eslint-disable @typescript-eslint/no-shadow */
|
|
5
|
+
/* eslint-disable @typescript-eslint/no-use-before-define */
|
|
6
|
+
// Copyright (c) Jupyter Development Team.
|
|
7
|
+
// Distributed under the terms of the Modified BSD License.
|
|
8
|
+
|
|
9
|
+
import type { Event } from '@difizen/mana-app';
|
|
10
|
+
import { Emitter } from '@difizen/mana-app';
|
|
11
|
+
import type * as lsp from 'vscode-languageserver-protocol';
|
|
12
|
+
import type { MessageConnection } from 'vscode-ws-jsonrpc';
|
|
13
|
+
|
|
14
|
+
import { Method } from './tokens.js';
|
|
15
|
+
import type {
|
|
16
|
+
ClientNotifications,
|
|
17
|
+
ClientRequests,
|
|
18
|
+
IClientRequestHandler,
|
|
19
|
+
IClientRequestParams,
|
|
20
|
+
IClientResult,
|
|
21
|
+
IDocumentInfo,
|
|
22
|
+
ILSPConnection,
|
|
23
|
+
ILSPOptions,
|
|
24
|
+
IServerRequestHandler,
|
|
25
|
+
IServerRequestParams,
|
|
26
|
+
IServerResult,
|
|
27
|
+
ServerNotifications,
|
|
28
|
+
ServerRequests,
|
|
29
|
+
} from './tokens.js';
|
|
30
|
+
import { untilReady } from './utils.js';
|
|
31
|
+
import {
|
|
32
|
+
registerServerCapability,
|
|
33
|
+
unregisterServerCapability,
|
|
34
|
+
} from './ws-connection/server-capability-registration.js';
|
|
35
|
+
import { LspWsConnection } from './ws-connection/ws-connection.js';
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Helper class to handle client request
|
|
39
|
+
*/
|
|
40
|
+
class ClientRequestHandler<
|
|
41
|
+
T extends keyof IClientRequestParams = keyof IClientRequestParams,
|
|
42
|
+
> implements IClientRequestHandler
|
|
43
|
+
{
|
|
44
|
+
constructor(
|
|
45
|
+
protected connection: MessageConnection,
|
|
46
|
+
protected method: T,
|
|
47
|
+
protected emitter: LSPConnection,
|
|
48
|
+
) {}
|
|
49
|
+
request(params: IClientRequestParams[T]): Promise<IClientResult[T]> {
|
|
50
|
+
// TODO check if is ready?
|
|
51
|
+
this.emitter.log(MessageKind.clientRequested, {
|
|
52
|
+
method: this.method,
|
|
53
|
+
message: params,
|
|
54
|
+
});
|
|
55
|
+
return this.connection
|
|
56
|
+
.sendRequest<any>(this.method, params)
|
|
57
|
+
.then((result: IClientResult[T]) => {
|
|
58
|
+
this.emitter.log(MessageKind.resultForClient, {
|
|
59
|
+
method: this.method,
|
|
60
|
+
message: params,
|
|
61
|
+
});
|
|
62
|
+
return result;
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* Helper class to handle server responses
|
|
69
|
+
*/
|
|
70
|
+
class ServerRequestHandler<
|
|
71
|
+
T extends keyof IServerRequestParams = keyof IServerRequestParams,
|
|
72
|
+
> implements IServerRequestHandler
|
|
73
|
+
{
|
|
74
|
+
constructor(
|
|
75
|
+
protected connection: MessageConnection,
|
|
76
|
+
protected method: T,
|
|
77
|
+
protected emitter: LSPConnection,
|
|
78
|
+
) {
|
|
79
|
+
// on request accepts "thenable"
|
|
80
|
+
this.connection.onRequest(method, this._handle.bind(this));
|
|
81
|
+
this._handler = null;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
setHandler(
|
|
85
|
+
handler: (
|
|
86
|
+
params: IServerRequestParams[T],
|
|
87
|
+
connection?: LSPConnection,
|
|
88
|
+
) => Promise<IServerResult[T]>,
|
|
89
|
+
) {
|
|
90
|
+
this._handler = handler;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
clearHandler() {
|
|
94
|
+
this._handler = null;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
protected _handler:
|
|
98
|
+
| ((
|
|
99
|
+
params: IServerRequestParams[T],
|
|
100
|
+
connection?: LSPConnection,
|
|
101
|
+
) => Promise<IServerResult[T]>)
|
|
102
|
+
| null;
|
|
103
|
+
|
|
104
|
+
protected _handle(
|
|
105
|
+
request: IServerRequestParams[T],
|
|
106
|
+
): Promise<IServerResult[T] | undefined> {
|
|
107
|
+
this.emitter.log(MessageKind.serverRequested, {
|
|
108
|
+
method: this.method,
|
|
109
|
+
message: request,
|
|
110
|
+
});
|
|
111
|
+
if (!this._handler) {
|
|
112
|
+
return new Promise(() => undefined);
|
|
113
|
+
}
|
|
114
|
+
return this._handler(request, this.emitter).then((result) => {
|
|
115
|
+
this.emitter.log(MessageKind.responseForServer, {
|
|
116
|
+
method: this.method,
|
|
117
|
+
message: result,
|
|
118
|
+
});
|
|
119
|
+
return result;
|
|
120
|
+
});
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
export const Provider: Record<string, keyof lsp.ServerCapabilities> = {
|
|
125
|
+
TEXT_DOCUMENT_SYNC: 'textDocumentSync',
|
|
126
|
+
COMPLETION: 'completionProvider',
|
|
127
|
+
HOVER: 'hoverProvider',
|
|
128
|
+
SIGNATURE_HELP: 'signatureHelpProvider',
|
|
129
|
+
DECLARATION: 'declarationProvider',
|
|
130
|
+
DEFINITION: 'definitionProvider',
|
|
131
|
+
TYPE_DEFINITION: 'typeDefinitionProvider',
|
|
132
|
+
IMPLEMENTATION: 'implementationProvider',
|
|
133
|
+
REFERENCES: 'referencesProvider',
|
|
134
|
+
DOCUMENT_HIGHLIGHT: 'documentHighlightProvider',
|
|
135
|
+
DOCUMENT_SYMBOL: 'documentSymbolProvider',
|
|
136
|
+
CODE_ACTION: 'codeActionProvider',
|
|
137
|
+
CODE_LENS: 'codeLensProvider',
|
|
138
|
+
DOCUMENT_LINK: 'documentLinkProvider',
|
|
139
|
+
COLOR: 'colorProvider',
|
|
140
|
+
DOCUMENT_FORMATTING: 'documentFormattingProvider',
|
|
141
|
+
DOCUMENT_RANGE_FORMATTING: 'documentRangeFormattingProvider',
|
|
142
|
+
DOCUMENT_ON_TYPE_FORMATTING: 'documentOnTypeFormattingProvider',
|
|
143
|
+
RENAME: 'renameProvider',
|
|
144
|
+
FOLDING_RANGE: 'foldingRangeProvider',
|
|
145
|
+
EXECUTE_COMMAND: 'executeCommandProvider',
|
|
146
|
+
SELECTION_RANGE: 'selectionRangeProvider',
|
|
147
|
+
WORKSPACE_SYMBOL: 'workspaceSymbolProvider',
|
|
148
|
+
WORKSPACE: 'workspace',
|
|
149
|
+
};
|
|
150
|
+
|
|
151
|
+
type AnyMethodType =
|
|
152
|
+
| typeof Method.ServerNotification
|
|
153
|
+
| typeof Method.ClientNotification
|
|
154
|
+
| typeof Method.ClientRequest
|
|
155
|
+
| typeof Method.ServerRequest;
|
|
156
|
+
type AnyMethod =
|
|
157
|
+
| Method.ServerNotification
|
|
158
|
+
| Method.ClientNotification
|
|
159
|
+
| Method.ClientRequest
|
|
160
|
+
| Method.ServerRequest;
|
|
161
|
+
|
|
162
|
+
/**
|
|
163
|
+
* Create a map between the request method and its handler
|
|
164
|
+
*/
|
|
165
|
+
function createMethodMap<T, H, U extends keyof T = keyof T>(
|
|
166
|
+
methods: AnyMethodType,
|
|
167
|
+
handlerFactory: (method: U) => H,
|
|
168
|
+
): T {
|
|
169
|
+
const result: { [key in U]?: H } = {};
|
|
170
|
+
for (const method of Object.values(methods)) {
|
|
171
|
+
result[method as U] = handlerFactory(method as U);
|
|
172
|
+
}
|
|
173
|
+
return result as T;
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
enum MessageKind {
|
|
177
|
+
clientNotifiedServer,
|
|
178
|
+
serverNotifiedClient,
|
|
179
|
+
serverRequested,
|
|
180
|
+
clientRequested,
|
|
181
|
+
resultForClient,
|
|
182
|
+
responseForServer,
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
interface IMessageLog<T extends AnyMethod = AnyMethod> {
|
|
186
|
+
method: T;
|
|
187
|
+
message: any;
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
export class LSPConnection extends LspWsConnection implements ILSPConnection {
|
|
191
|
+
constructor(options: ILSPOptions) {
|
|
192
|
+
super(options);
|
|
193
|
+
this._options = options;
|
|
194
|
+
this.logAllCommunication = false;
|
|
195
|
+
this.serverIdentifier = options.serverIdentifier;
|
|
196
|
+
this.serverLanguage = options.languageId;
|
|
197
|
+
this.documentsToOpen = [];
|
|
198
|
+
this.clientNotifications = this.constructNotificationHandlers<ClientNotifications>(
|
|
199
|
+
Method.ClientNotification,
|
|
200
|
+
);
|
|
201
|
+
this.serverNotifications = this.constructNotificationHandlers<ServerNotifications>(
|
|
202
|
+
Method.ServerNotification,
|
|
203
|
+
);
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
/**
|
|
207
|
+
* Identifier of the language server
|
|
208
|
+
*/
|
|
209
|
+
readonly serverIdentifier?: string;
|
|
210
|
+
|
|
211
|
+
/**
|
|
212
|
+
* Language of the language server
|
|
213
|
+
*/
|
|
214
|
+
readonly serverLanguage?: string;
|
|
215
|
+
|
|
216
|
+
/**
|
|
217
|
+
* Notifications comes from the client.
|
|
218
|
+
*/
|
|
219
|
+
readonly clientNotifications: ClientNotifications;
|
|
220
|
+
|
|
221
|
+
/**
|
|
222
|
+
* Notifications comes from the server.
|
|
223
|
+
*/
|
|
224
|
+
readonly serverNotifications: ServerNotifications;
|
|
225
|
+
|
|
226
|
+
/**
|
|
227
|
+
* Requests comes from the client.
|
|
228
|
+
*/
|
|
229
|
+
clientRequests: ClientRequests;
|
|
230
|
+
|
|
231
|
+
/**
|
|
232
|
+
* Responses comes from the server.
|
|
233
|
+
*/
|
|
234
|
+
serverRequests: ServerRequests;
|
|
235
|
+
|
|
236
|
+
/**
|
|
237
|
+
* Should log all communication?
|
|
238
|
+
*/
|
|
239
|
+
logAllCommunication: boolean;
|
|
240
|
+
|
|
241
|
+
get capabilities() {
|
|
242
|
+
return this.serverCapabilities;
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
/**
|
|
246
|
+
* Signal emitted when the connection is closed.
|
|
247
|
+
*/
|
|
248
|
+
get closeSignal(): Event<boolean> {
|
|
249
|
+
return this._closeSignal.event;
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
/**
|
|
253
|
+
* Signal emitted when the connection receives an error
|
|
254
|
+
* message..
|
|
255
|
+
*/
|
|
256
|
+
get errorSignal(): Event<any> {
|
|
257
|
+
return this._errorSignal.event;
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
/**
|
|
261
|
+
* Signal emitted when the connection is initialized.
|
|
262
|
+
*/
|
|
263
|
+
get serverInitialized(): Event<lsp.ServerCapabilities<any>> {
|
|
264
|
+
return this._serverInitialized.event;
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
/**
|
|
268
|
+
* Dispose the connection.
|
|
269
|
+
*/
|
|
270
|
+
override dispose(): void {
|
|
271
|
+
if (this.isDisposed) {
|
|
272
|
+
return;
|
|
273
|
+
}
|
|
274
|
+
Object.values(this.serverRequests).forEach((request) => request.clearHandler());
|
|
275
|
+
this.close();
|
|
276
|
+
super.dispose();
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
/**
|
|
280
|
+
* Helper to print the logs to logger, for now we are using
|
|
281
|
+
* directly the browser's console.
|
|
282
|
+
*/
|
|
283
|
+
log(kind: MessageKind, message: IMessageLog): void {
|
|
284
|
+
if (this.logAllCommunication) {
|
|
285
|
+
// eslint-disable-next-line no-console
|
|
286
|
+
console.log(kind, message);
|
|
287
|
+
}
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
/**
|
|
291
|
+
* Send the open request to the backend when the server is
|
|
292
|
+
* ready.
|
|
293
|
+
*/
|
|
294
|
+
sendOpenWhenReady(documentInfo: IDocumentInfo): void {
|
|
295
|
+
if (this.isReady) {
|
|
296
|
+
this.sendOpen(documentInfo);
|
|
297
|
+
} else {
|
|
298
|
+
this.documentsToOpen.push(documentInfo);
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
/**
|
|
303
|
+
* Send the document changes to the server.
|
|
304
|
+
*/
|
|
305
|
+
sendSelectiveChange(
|
|
306
|
+
changeEvent: lsp.TextDocumentContentChangeEvent,
|
|
307
|
+
documentInfo: IDocumentInfo,
|
|
308
|
+
): void {
|
|
309
|
+
this._sendChange([changeEvent], documentInfo);
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
/**
|
|
313
|
+
* Send all changes to the server.
|
|
314
|
+
*/
|
|
315
|
+
sendFullTextChange(text: string, documentInfo: IDocumentInfo): void {
|
|
316
|
+
this._sendChange([{ text }], documentInfo);
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
/**
|
|
320
|
+
* Check if a provider is available in the registered capabilities.
|
|
321
|
+
*/
|
|
322
|
+
provides(provider: keyof lsp.ServerCapabilities): boolean {
|
|
323
|
+
return !!(this.serverCapabilities && this.serverCapabilities[provider]);
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
/**
|
|
327
|
+
* Close the connection to the server.
|
|
328
|
+
*/
|
|
329
|
+
override close(): void {
|
|
330
|
+
try {
|
|
331
|
+
this._closingManually = true;
|
|
332
|
+
super.close();
|
|
333
|
+
} catch (e) {
|
|
334
|
+
this._closingManually = false;
|
|
335
|
+
}
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
/**
|
|
339
|
+
* initialize a connection over a web socket that speaks the LSP
|
|
340
|
+
*/
|
|
341
|
+
override connect(socket: WebSocket): void {
|
|
342
|
+
super.connect(socket);
|
|
343
|
+
untilReady(() => {
|
|
344
|
+
return this.isConnected;
|
|
345
|
+
}, -1)
|
|
346
|
+
.then(() => {
|
|
347
|
+
const disposable = this.connection.onClose(() => {
|
|
348
|
+
this._isConnected = false;
|
|
349
|
+
this._closeSignal.fire(this._closingManually);
|
|
350
|
+
});
|
|
351
|
+
this._disposables.push(disposable);
|
|
352
|
+
return;
|
|
353
|
+
})
|
|
354
|
+
.catch(() => {
|
|
355
|
+
console.error('Could not connect onClose signal');
|
|
356
|
+
});
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
/**
|
|
360
|
+
* Get send request to the server to get completion results
|
|
361
|
+
* from a completion item
|
|
362
|
+
*/
|
|
363
|
+
async getCompletionResolve(
|
|
364
|
+
completionItem: lsp.CompletionItem,
|
|
365
|
+
): Promise<lsp.CompletionItem | undefined> {
|
|
366
|
+
if (!this.isReady) {
|
|
367
|
+
return;
|
|
368
|
+
}
|
|
369
|
+
return this.connection.sendRequest<lsp.CompletionItem>(
|
|
370
|
+
'completionItem/resolve',
|
|
371
|
+
completionItem,
|
|
372
|
+
);
|
|
373
|
+
}
|
|
374
|
+
|
|
375
|
+
/**
|
|
376
|
+
* List of documents waiting to be opened once the connection
|
|
377
|
+
* is ready.
|
|
378
|
+
*/
|
|
379
|
+
protected documentsToOpen: IDocumentInfo[];
|
|
380
|
+
|
|
381
|
+
/**
|
|
382
|
+
* Generate the notification handlers
|
|
383
|
+
*/
|
|
384
|
+
protected constructNotificationHandlers<
|
|
385
|
+
T extends ServerNotifications | ClientNotifications,
|
|
386
|
+
>(methods: typeof Method.ServerNotification | typeof Method.ClientNotification): T {
|
|
387
|
+
const factory = () => new Emitter<any>();
|
|
388
|
+
return createMethodMap<T, Emitter<any>>(methods, factory);
|
|
389
|
+
}
|
|
390
|
+
|
|
391
|
+
/**
|
|
392
|
+
* Generate the client request handler
|
|
393
|
+
*/
|
|
394
|
+
protected constructClientRequestHandler<
|
|
395
|
+
T extends ClientRequests,
|
|
396
|
+
U extends keyof T = keyof T,
|
|
397
|
+
>(methods: typeof Method.ClientRequest): T {
|
|
398
|
+
return createMethodMap<T, IClientRequestHandler>(
|
|
399
|
+
methods,
|
|
400
|
+
(method) => new ClientRequestHandler(this.connection, method as U as any, this),
|
|
401
|
+
);
|
|
402
|
+
}
|
|
403
|
+
|
|
404
|
+
/**
|
|
405
|
+
* Generate the server response handler
|
|
406
|
+
*/
|
|
407
|
+
protected constructServerRequestHandler<
|
|
408
|
+
T extends ServerRequests,
|
|
409
|
+
U extends keyof T = keyof T,
|
|
410
|
+
>(methods: typeof Method.ServerRequest): T {
|
|
411
|
+
return createMethodMap<T, IServerRequestHandler>(
|
|
412
|
+
methods,
|
|
413
|
+
(method) => new ServerRequestHandler(this.connection, method as U as any, this),
|
|
414
|
+
);
|
|
415
|
+
}
|
|
416
|
+
|
|
417
|
+
/**
|
|
418
|
+
* Initialization parameters to be sent to the language server.
|
|
419
|
+
* Subclasses can overload this when adding more features.
|
|
420
|
+
*/
|
|
421
|
+
protected override initializeParams(): lsp.InitializeParams {
|
|
422
|
+
return {
|
|
423
|
+
...super.initializeParams(),
|
|
424
|
+
capabilities: this._options.capabilities,
|
|
425
|
+
initializationOptions: null,
|
|
426
|
+
processId: null,
|
|
427
|
+
workspaceFolders: null,
|
|
428
|
+
};
|
|
429
|
+
}
|
|
430
|
+
|
|
431
|
+
/**
|
|
432
|
+
* Callback called when the server is initialized.
|
|
433
|
+
*/
|
|
434
|
+
protected override onServerInitialized(params: lsp.InitializeResult): void {
|
|
435
|
+
this.afterInitialized();
|
|
436
|
+
super.onServerInitialized(params);
|
|
437
|
+
while (this.documentsToOpen.length) {
|
|
438
|
+
this.sendOpen(this.documentsToOpen.pop()!);
|
|
439
|
+
}
|
|
440
|
+
this._serverInitialized.fire(this.serverCapabilities);
|
|
441
|
+
}
|
|
442
|
+
|
|
443
|
+
/**
|
|
444
|
+
* Once the server is initialized, this method generates the
|
|
445
|
+
* client and server handlers
|
|
446
|
+
*/
|
|
447
|
+
protected afterInitialized(): void {
|
|
448
|
+
const disposable = this.connection.onError((e) => this._errorSignal.fire(e));
|
|
449
|
+
this._disposables.push(disposable);
|
|
450
|
+
for (const method of Object.values(
|
|
451
|
+
Method.ServerNotification,
|
|
452
|
+
) as (keyof ServerNotifications)[]) {
|
|
453
|
+
const signal = this.serverNotifications[method] as Emitter<any>;
|
|
454
|
+
const disposable = this.connection.onNotification(method, (params) => {
|
|
455
|
+
this.log(MessageKind.serverNotifiedClient, {
|
|
456
|
+
method,
|
|
457
|
+
message: params,
|
|
458
|
+
});
|
|
459
|
+
signal.fire(params);
|
|
460
|
+
});
|
|
461
|
+
this._disposables.push(disposable);
|
|
462
|
+
}
|
|
463
|
+
|
|
464
|
+
for (const method of Object.values(
|
|
465
|
+
Method.ClientNotification,
|
|
466
|
+
) as (keyof ClientNotifications)[]) {
|
|
467
|
+
const signal = this.clientNotifications[method] as Emitter<any>;
|
|
468
|
+
signal.event((params) => {
|
|
469
|
+
this.log(MessageKind.clientNotifiedServer, {
|
|
470
|
+
method,
|
|
471
|
+
message: params,
|
|
472
|
+
});
|
|
473
|
+
this.connection.sendNotification(method, params).catch(console.error);
|
|
474
|
+
});
|
|
475
|
+
}
|
|
476
|
+
|
|
477
|
+
this.clientRequests = this.constructClientRequestHandler<ClientRequests>(
|
|
478
|
+
Method.ClientRequest,
|
|
479
|
+
);
|
|
480
|
+
this.serverRequests = this.constructServerRequestHandler<ServerRequests>(
|
|
481
|
+
Method.ServerRequest,
|
|
482
|
+
);
|
|
483
|
+
|
|
484
|
+
this.serverRequests['client/registerCapability'].setHandler(
|
|
485
|
+
async (params: lsp.RegistrationParams) => {
|
|
486
|
+
params.registrations.forEach((capabilityRegistration: lsp.Registration) => {
|
|
487
|
+
try {
|
|
488
|
+
const updatedCapabilities = registerServerCapability(
|
|
489
|
+
this.serverCapabilities,
|
|
490
|
+
capabilityRegistration,
|
|
491
|
+
);
|
|
492
|
+
if (updatedCapabilities === null) {
|
|
493
|
+
console.error(
|
|
494
|
+
`Failed to register server capability: ${capabilityRegistration}`,
|
|
495
|
+
);
|
|
496
|
+
return;
|
|
497
|
+
}
|
|
498
|
+
this.serverCapabilities = updatedCapabilities;
|
|
499
|
+
} catch (err) {
|
|
500
|
+
console.error(err);
|
|
501
|
+
}
|
|
502
|
+
});
|
|
503
|
+
},
|
|
504
|
+
);
|
|
505
|
+
|
|
506
|
+
this.serverRequests['client/unregisterCapability'].setHandler(
|
|
507
|
+
async (params: lsp.UnregistrationParams) => {
|
|
508
|
+
params.unregisterations.forEach(
|
|
509
|
+
(capabilityUnregistration: lsp.Unregistration) => {
|
|
510
|
+
this.serverCapabilities = unregisterServerCapability(
|
|
511
|
+
this.serverCapabilities,
|
|
512
|
+
capabilityUnregistration,
|
|
513
|
+
);
|
|
514
|
+
},
|
|
515
|
+
);
|
|
516
|
+
},
|
|
517
|
+
);
|
|
518
|
+
|
|
519
|
+
this.serverRequests['workspace/configuration'].setHandler(async (params) => {
|
|
520
|
+
return params.items.map((item) => {
|
|
521
|
+
// LSP: "If the client can’t provide a configuration setting for a given scope
|
|
522
|
+
// then `null` needs to be present in the returned array."
|
|
523
|
+
|
|
524
|
+
// for now we do not support configuration, but yaml server does not respect
|
|
525
|
+
// client capability so we have a handler just for that
|
|
526
|
+
return null;
|
|
527
|
+
});
|
|
528
|
+
});
|
|
529
|
+
}
|
|
530
|
+
|
|
531
|
+
/**
|
|
532
|
+
* Is the connection is closed manually?
|
|
533
|
+
*/
|
|
534
|
+
protected _closingManually = false;
|
|
535
|
+
|
|
536
|
+
protected _options: ILSPOptions;
|
|
537
|
+
|
|
538
|
+
protected _closeSignal = new Emitter<boolean>();
|
|
539
|
+
protected _errorSignal = new Emitter<any>();
|
|
540
|
+
protected _serverInitialized = new Emitter<lsp.ServerCapabilities<any>>();
|
|
541
|
+
|
|
542
|
+
/**
|
|
543
|
+
* Send the document changed data to the server.
|
|
544
|
+
*/
|
|
545
|
+
protected _sendChange(
|
|
546
|
+
changeEvents: lsp.TextDocumentContentChangeEvent[],
|
|
547
|
+
documentInfo: IDocumentInfo,
|
|
548
|
+
) {
|
|
549
|
+
if (!this.isReady) {
|
|
550
|
+
return;
|
|
551
|
+
}
|
|
552
|
+
if (documentInfo.uri.length === 0) {
|
|
553
|
+
return;
|
|
554
|
+
}
|
|
555
|
+
if (!this.openedUris.get(documentInfo.uri)) {
|
|
556
|
+
this.sendOpen(documentInfo);
|
|
557
|
+
}
|
|
558
|
+
const textDocumentChange: lsp.DidChangeTextDocumentParams = {
|
|
559
|
+
textDocument: {
|
|
560
|
+
uri: documentInfo.uri,
|
|
561
|
+
version: documentInfo.version,
|
|
562
|
+
} as lsp.VersionedTextDocumentIdentifier,
|
|
563
|
+
contentChanges: changeEvents,
|
|
564
|
+
};
|
|
565
|
+
this.connection
|
|
566
|
+
.sendNotification('textDocument/didChange', textDocumentChange)
|
|
567
|
+
.catch(console.error);
|
|
568
|
+
documentInfo.version++;
|
|
569
|
+
}
|
|
570
|
+
}
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
// Copyright (c) Jupyter Development Team.
|
|
2
|
+
// Distributed under the terms of the Modified BSD License.
|
|
3
|
+
|
|
4
|
+
import { singleton } from '@difizen/mana-app';
|
|
5
|
+
|
|
6
|
+
import { ILSPCodeExtractorsManager } from '../tokens.js';
|
|
7
|
+
|
|
8
|
+
import type { IForeignCodeExtractor } from './types.js';
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Manager for the code extractors
|
|
12
|
+
*/
|
|
13
|
+
@singleton({ token: ILSPCodeExtractorsManager })
|
|
14
|
+
export class CodeExtractorsManager implements ILSPCodeExtractorsManager {
|
|
15
|
+
constructor() {
|
|
16
|
+
this._extractorMap = new Map<string, Map<string, IForeignCodeExtractor[]>>();
|
|
17
|
+
|
|
18
|
+
this._extractorMapAnyLanguage = new Map<string, IForeignCodeExtractor[]>();
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Get the extractors for the input cell type and the main language of
|
|
23
|
+
* the document
|
|
24
|
+
*
|
|
25
|
+
* @param cellType - type of cell
|
|
26
|
+
* @param hostLanguage - main language of the document
|
|
27
|
+
*/
|
|
28
|
+
getExtractors(
|
|
29
|
+
cellType: string,
|
|
30
|
+
hostLanguage: string | null,
|
|
31
|
+
): IForeignCodeExtractor[] {
|
|
32
|
+
if (hostLanguage) {
|
|
33
|
+
const currentMap = this._extractorMap.get(cellType);
|
|
34
|
+
if (!currentMap) {
|
|
35
|
+
return [];
|
|
36
|
+
}
|
|
37
|
+
return currentMap.get(hostLanguage) ?? [];
|
|
38
|
+
} else {
|
|
39
|
+
return this._extractorMapAnyLanguage.get(cellType) ?? [];
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Register an extractor to extract foreign code from host documents of specified language.
|
|
45
|
+
*/
|
|
46
|
+
register(extractor: IForeignCodeExtractor, hostLanguage: string | null): void {
|
|
47
|
+
const cellType = extractor.cellType;
|
|
48
|
+
if (hostLanguage) {
|
|
49
|
+
cellType.forEach((type) => {
|
|
50
|
+
if (!this._extractorMap.has(type)) {
|
|
51
|
+
this._extractorMap.set(type, new Map());
|
|
52
|
+
}
|
|
53
|
+
const currentMap = this._extractorMap.get(type)!;
|
|
54
|
+
const extractorList = currentMap.get(hostLanguage);
|
|
55
|
+
if (!extractorList) {
|
|
56
|
+
currentMap.set(hostLanguage, [extractor]);
|
|
57
|
+
} else {
|
|
58
|
+
extractorList.push(extractor);
|
|
59
|
+
}
|
|
60
|
+
});
|
|
61
|
+
} else {
|
|
62
|
+
cellType.forEach((type) => {
|
|
63
|
+
if (!this._extractorMapAnyLanguage.has(type)) {
|
|
64
|
+
this._extractorMapAnyLanguage.set(type, []);
|
|
65
|
+
}
|
|
66
|
+
this._extractorMapAnyLanguage.get(type)!.push(extractor);
|
|
67
|
+
});
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* The map with key is the type of cell, value is another map between
|
|
73
|
+
* the language of cell and its code extractor.
|
|
74
|
+
*/
|
|
75
|
+
protected _extractorMap: Map<string, Map<string, IForeignCodeExtractor[]>>;
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* The map with key is the cell type, value is the code extractor associated
|
|
79
|
+
* with this cell type, this is used for the non-code cell types.
|
|
80
|
+
*/
|
|
81
|
+
protected _extractorMapAnyLanguage: Map<string, IForeignCodeExtractor[]>;
|
|
82
|
+
}
|