@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.
Files changed (104) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +0 -0
  3. package/es/adapters/adapter.d.ts +255 -0
  4. package/es/adapters/adapter.d.ts.map +1 -0
  5. package/es/adapters/adapter.js +647 -0
  6. package/es/adapters/notebook-adapter.d.ts +150 -0
  7. package/es/adapters/notebook-adapter.d.ts.map +1 -0
  8. package/es/adapters/notebook-adapter.js +588 -0
  9. package/es/adapters/status-message.d.ts +48 -0
  10. package/es/adapters/status-message.d.ts.map +1 -0
  11. package/es/adapters/status-message.js +110 -0
  12. package/es/connection-manager.d.ts +199 -0
  13. package/es/connection-manager.d.ts.map +1 -0
  14. package/es/connection-manager.js +685 -0
  15. package/es/connection.d.ts +149 -0
  16. package/es/connection.d.ts.map +1 -0
  17. package/es/connection.js +591 -0
  18. package/es/extractors/index.d.ts +4 -0
  19. package/es/extractors/index.d.ts.map +1 -0
  20. package/es/extractors/index.js +6 -0
  21. package/es/extractors/manager.d.ts +31 -0
  22. package/es/extractors/manager.d.ts.map +1 -0
  23. package/es/extractors/manager.js +90 -0
  24. package/es/extractors/text-extractor.d.ts +56 -0
  25. package/es/extractors/text-extractor.d.ts.map +1 -0
  26. package/es/extractors/text-extractor.js +72 -0
  27. package/es/extractors/types.d.ts +68 -0
  28. package/es/extractors/types.d.ts.map +1 -0
  29. package/es/extractors/types.js +1 -0
  30. package/es/feature.d.ts +29 -0
  31. package/es/feature.d.ts.map +1 -0
  32. package/es/feature.js +85 -0
  33. package/es/index.d.ts +19 -0
  34. package/es/index.d.ts.map +1 -0
  35. package/es/index.js +21 -0
  36. package/es/lsp-app-contribution.d.ts +19 -0
  37. package/es/lsp-app-contribution.d.ts.map +1 -0
  38. package/es/lsp-app-contribution.js +155 -0
  39. package/es/lsp-protocol.d.ts +10 -0
  40. package/es/lsp-protocol.d.ts.map +1 -0
  41. package/es/lsp-protocol.js +1 -0
  42. package/es/lsp.d.ts +136 -0
  43. package/es/lsp.d.ts.map +1 -0
  44. package/es/lsp.js +141 -0
  45. package/es/manager.d.ts +142 -0
  46. package/es/manager.d.ts.map +1 -0
  47. package/es/manager.js +423 -0
  48. package/es/module.d.ts +3 -0
  49. package/es/module.d.ts.map +1 -0
  50. package/es/module.js +21 -0
  51. package/es/plugin.d.ts +56 -0
  52. package/es/plugin.d.ts.map +1 -0
  53. package/es/plugin.js +0 -0
  54. package/es/positioning.d.ts +66 -0
  55. package/es/positioning.d.ts.map +1 -0
  56. package/es/positioning.js +96 -0
  57. package/es/schema.d.ts +240 -0
  58. package/es/schema.d.ts.map +1 -0
  59. package/es/schema.js +0 -0
  60. package/es/tokens.d.ts +677 -0
  61. package/es/tokens.d.ts.map +1 -0
  62. package/es/tokens.js +183 -0
  63. package/es/utils.d.ts +33 -0
  64. package/es/utils.d.ts.map +1 -0
  65. package/es/utils.js +168 -0
  66. package/es/virtual/document.d.ts +546 -0
  67. package/es/virtual/document.d.ts.map +1 -0
  68. package/es/virtual/document.js +1263 -0
  69. package/es/ws-connection/server-capability-registration.d.ts +19 -0
  70. package/es/ws-connection/server-capability-registration.d.ts.map +1 -0
  71. package/es/ws-connection/server-capability-registration.js +51 -0
  72. package/es/ws-connection/types.d.ts +76 -0
  73. package/es/ws-connection/types.d.ts.map +1 -0
  74. package/es/ws-connection/types.js +1 -0
  75. package/es/ws-connection/ws-connection.d.ts +105 -0
  76. package/es/ws-connection/ws-connection.d.ts.map +1 -0
  77. package/es/ws-connection/ws-connection.js +301 -0
  78. package/package.json +67 -0
  79. package/src/adapters/adapter.ts +611 -0
  80. package/src/adapters/notebook-adapter.ts +463 -0
  81. package/src/adapters/status-message.ts +93 -0
  82. package/src/connection-manager.ts +626 -0
  83. package/src/connection.ts +570 -0
  84. package/src/extractors/index.ts +6 -0
  85. package/src/extractors/manager.ts +82 -0
  86. package/src/extractors/text-extractor.ts +94 -0
  87. package/src/extractors/types.ts +78 -0
  88. package/src/feature.ts +60 -0
  89. package/src/index.spec.ts +10 -0
  90. package/src/index.ts +21 -0
  91. package/src/lsp-app-contribution.ts +83 -0
  92. package/src/lsp-protocol.ts +10 -0
  93. package/src/lsp.ts +160 -0
  94. package/src/manager.ts +358 -0
  95. package/src/module.ts +32 -0
  96. package/src/plugin.ts +62 -0
  97. package/src/positioning.ts +121 -0
  98. package/src/schema.ts +249 -0
  99. package/src/tokens.ts +843 -0
  100. package/src/utils.ts +109 -0
  101. package/src/virtual/document.ts +1250 -0
  102. package/src/ws-connection/server-capability-registration.ts +77 -0
  103. package/src/ws-connection/types.ts +102 -0
  104. 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,6 @@
1
+ // Copyright (c) Jupyter Development Team.
2
+ // Distributed under the terms of the Modified BSD License.
3
+
4
+ export * from './manager.js';
5
+ export * from './text-extractor.js';
6
+ export * from './types.js';
@@ -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
+ }