@jupyterlab/lsp 4.6.0 → 4.7.0-alpha.0

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.
@@ -525,21 +525,40 @@ export abstract class WidgetLSPAdapter<
525
525
  virtualDocument: VirtualDocument,
526
526
  sendOpen = false
527
527
  ): Promise<void> {
528
- virtualDocument.foreignDocumentOpened.connect(
529
- this.onForeignDocumentOpened,
530
- this
531
- );
532
- const connectionContext = await this._connect(virtualDocument).catch(
533
- console.error
534
- );
528
+ if (this._isDisposed || virtualDocument.isDisposed) {
529
+ return;
530
+ }
535
531
 
536
- if (connectionContext && connectionContext.connection) {
537
- virtualDocument.changed.connect(this.documentChanged, this);
538
- if (sendOpen) {
539
- connectionContext.connection.sendOpenWhenReady(
540
- virtualDocument.documentInfo
541
- );
532
+ const pendingConnection =
533
+ this._pendingDocumentConnections.get(virtualDocument);
534
+ if (pendingConnection) {
535
+ return pendingConnection;
536
+ }
537
+
538
+ const connectionPromise = (async () => {
539
+ virtualDocument.foreignDocumentOpened.connect(
540
+ this.onForeignDocumentOpened,
541
+ this
542
+ );
543
+ const connectionContext = await this._connect(virtualDocument).catch(
544
+ console.error
545
+ );
546
+
547
+ if (connectionContext && connectionContext.connection) {
548
+ virtualDocument.changed.connect(this.documentChanged, this);
549
+ if (sendOpen) {
550
+ connectionContext.connection.sendOpenWhenReady(
551
+ virtualDocument.documentInfo
552
+ );
553
+ }
542
554
  }
555
+ })();
556
+ this._pendingDocumentConnections.set(virtualDocument, connectionPromise);
557
+
558
+ try {
559
+ await connectionPromise;
560
+ } finally {
561
+ this._pendingDocumentConnections.delete(virtualDocument);
543
562
  }
544
563
  }
545
564
 
@@ -549,7 +568,7 @@ export abstract class WidgetLSPAdapter<
549
568
  protected initVirtual(): void {
550
569
  this._virtualDocument?.dispose();
551
570
  this._virtualDocument = this.createVirtualDocument();
552
- this._onLspSessionOrFeatureChanged();
571
+ this._toggleVirtualDocumentUpdates();
553
572
  }
554
573
 
555
574
  /**
@@ -616,6 +635,11 @@ export abstract class WidgetLSPAdapter<
616
635
  private _updateFinished: Promise<void>;
617
636
  private _virtualDocument: VirtualDocument | null = null;
618
637
  private _editorToAdapter: WeakMap<Document.IEditor, EditorAdapter>;
638
+ private _pendingDocumentConnections = new WeakMap<
639
+ VirtualDocument,
640
+ Promise<void>
641
+ >();
642
+ private _queuedConnectionRetries = new WeakSet<VirtualDocument>();
619
643
 
620
644
  private _onEditorAdded(
621
645
  sender: WidgetLSPAdapter<T>,
@@ -697,6 +721,10 @@ export abstract class WidgetLSPAdapter<
697
721
 
698
722
  let connection = await this.connectionManager.connect(options);
699
723
 
724
+ if (this._isDisposed || virtualDocument.isDisposed) {
725
+ return undefined;
726
+ }
727
+
700
728
  if (connection) {
701
729
  await this.onConnected({ virtualDocument, connection });
702
730
 
@@ -755,6 +783,10 @@ export abstract class WidgetLSPAdapter<
755
783
  * the LSP server status changed or when a LSP feature is registered.
756
784
  */
757
785
  private _onLspSessionOrFeatureChanged(): void {
786
+ this._toggleVirtualDocumentUpdates(true);
787
+ }
788
+
789
+ private _toggleVirtualDocumentUpdates(retryConnection = false): void {
758
790
  if (!this._virtualDocument) {
759
791
  return;
760
792
  }
@@ -763,8 +795,49 @@ export abstract class WidgetLSPAdapter<
763
795
 
764
796
  if (this._shouldUpdateVirtualDocument()) {
765
797
  model.contentChanged.connect(this._onContentChanged, this);
798
+ if (retryConnection) {
799
+ this._connectVirtualDocumentIfNeeded(this._virtualDocument);
800
+ }
766
801
  } else {
767
802
  model.contentChanged.disconnect(this._onContentChanged, this);
768
803
  }
769
804
  }
805
+
806
+ private _connectVirtualDocumentIfNeeded(
807
+ virtualDocument: VirtualDocument
808
+ ): void {
809
+ if (
810
+ this._isDisposed ||
811
+ virtualDocument.isDisposed ||
812
+ this.connectionManager.connections.has(virtualDocument.uri)
813
+ ) {
814
+ return;
815
+ }
816
+
817
+ const pendingConnection =
818
+ this._pendingDocumentConnections.get(virtualDocument);
819
+ if (pendingConnection) {
820
+ if (this._queuedConnectionRetries.has(virtualDocument)) {
821
+ return;
822
+ }
823
+ this._queuedConnectionRetries.add(virtualDocument);
824
+ void pendingConnection
825
+ .finally(() => {
826
+ if (!this._queuedConnectionRetries.delete(virtualDocument)) {
827
+ return;
828
+ }
829
+ if (
830
+ this._virtualDocument === virtualDocument &&
831
+ this._shouldUpdateVirtualDocument() &&
832
+ !this.connectionManager.connections.has(virtualDocument.uri)
833
+ ) {
834
+ this._connectVirtualDocumentIfNeeded(virtualDocument);
835
+ }
836
+ })
837
+ .catch(console.warn);
838
+ return;
839
+ }
840
+
841
+ this.connectDocument(virtualDocument, false).catch(console.warn);
842
+ }
770
843
  }
@@ -1,6 +1,5 @@
1
1
  // Copyright (c) Jupyter Development Team.
2
2
  // Distributed under the terms of the Modified BSD License.
3
- /* eslint-disable @typescript-eslint/no-explicit-any */
4
3
 
5
4
  import type {
6
5
  IConfigurableExtension,
@@ -74,7 +73,7 @@ export class EditorAdapter implements IDisposable {
74
73
  });
75
74
  }
76
75
 
77
- private _widgetAdapter: WidgetLSPAdapter<any>;
76
+ private _widgetAdapter: WidgetLSPAdapter;
78
77
  private _extensions: EditorAdapter.ILSPEditorExtensionFactory[];
79
78
  }
80
79
 
@@ -103,7 +102,7 @@ export namespace EditorAdapter {
103
102
  }
104
103
 
105
104
  export interface ILSPEditorExtensionFactory extends Omit<
106
- IEditorExtensionFactory<any>,
105
+ IEditorExtensionFactory<unknown>,
107
106
  'factory'
108
107
  > {
109
108
  /**
@@ -114,7 +113,7 @@ export namespace EditorAdapter {
114
113
  */
115
114
  readonly factory: (
116
115
  options: IFactoryOptions
117
- ) => IConfigurableExtension<any> | null;
116
+ ) => IConfigurableExtension<unknown> | null;
118
117
  }
119
118
 
120
119
  export interface IFactoryOptions extends IEditorExtensionFactory.IOptions {
@@ -129,6 +128,6 @@ export namespace EditorAdapter {
129
128
  /**
130
129
  * The widget lsp adapter.
131
130
  */
132
- widgetAdapter: WidgetLSPAdapter<any>;
131
+ widgetAdapter: WidgetLSPAdapter;
133
132
  }
134
133
  }
package/src/connection.ts CHANGED
@@ -183,6 +183,42 @@ interface IMessageLog<T extends AnyMethod = AnyMethod> {
183
183
  message: any;
184
184
  }
185
185
 
186
+ interface ICancellationDisposable {
187
+ dispose(): void;
188
+ }
189
+
190
+ interface ISignalCancellationToken {
191
+ readonly isCancellationRequested: boolean;
192
+ onCancellationRequested(
193
+ listener: (event: unknown) => void,
194
+ thisArgs?: unknown,
195
+ disposables?: ICancellationDisposable[]
196
+ ): ICancellationDisposable;
197
+ }
198
+
199
+ function cancellationTokenFromSignal(
200
+ signal: AbortSignal
201
+ ): ISignalCancellationToken {
202
+ return {
203
+ get isCancellationRequested(): boolean {
204
+ return signal.aborted;
205
+ },
206
+ onCancellationRequested: (listener, thisArgs, disposables) => {
207
+ const onAbort = () => {
208
+ listener.call(thisArgs, undefined);
209
+ };
210
+ signal.addEventListener('abort', onAbort, { once: true });
211
+ const disposable = {
212
+ dispose: () => {
213
+ signal.removeEventListener('abort', onAbort);
214
+ }
215
+ };
216
+ disposables?.push(disposable);
217
+ return disposable;
218
+ }
219
+ };
220
+ }
221
+
186
222
  export class LSPConnection extends LspWsConnection implements ILSPConnection {
187
223
  constructor(options: ILSPOptions) {
188
224
  super(options);
@@ -324,6 +360,67 @@ export class LSPConnection extends LspWsConnection implements ILSPConnection {
324
360
  return !!(this.serverCapabilities && this.serverCapabilities[capability]);
325
361
  }
326
362
 
363
+ /**
364
+ * Send a request to the language server.
365
+ */
366
+ async request<M extends Method.ClientRequest>(
367
+ method: M,
368
+ params: IClientRequestParams[M],
369
+ options: ILSPConnection.IRequestOptions = {}
370
+ ): Promise<IClientResult[M]> {
371
+ if (this.isDisposed) {
372
+ throw new Error('Cannot send an LSP request on a disposed connection.');
373
+ }
374
+ if (!this.isReady) {
375
+ throw new Error(
376
+ 'Cannot send an LSP request before the connection is ready.'
377
+ );
378
+ }
379
+
380
+ const { signal } = options;
381
+ if (signal?.aborted) {
382
+ throw (
383
+ signal.reason ??
384
+ new DOMException('The request was aborted.', 'AbortError')
385
+ );
386
+ }
387
+
388
+ const cancellation = signal
389
+ ? cancellationTokenFromSignal(signal)
390
+ : undefined;
391
+ let rejectOnAbort: ((reason?: unknown) => void) | undefined;
392
+ const aborted = signal
393
+ ? new Promise<never>((_, reject) => {
394
+ rejectOnAbort = reject;
395
+ })
396
+ : undefined;
397
+ const cancel = () => {
398
+ rejectOnAbort?.(
399
+ signal?.reason ??
400
+ new DOMException('The request was aborted.', 'AbortError')
401
+ );
402
+ };
403
+ signal?.addEventListener('abort', cancel, { once: true });
404
+
405
+ this.log(MessageKind.clientRequested, { method, message: params });
406
+ try {
407
+ const response = cancellation
408
+ ? this.connection.sendRequest<IClientResult[M]>(
409
+ method,
410
+ params,
411
+ cancellation
412
+ )
413
+ : this.connection.sendRequest<IClientResult[M]>(method, params);
414
+ const result = aborted
415
+ ? await Promise.race([response, aborted])
416
+ : await response;
417
+ this.log(MessageKind.resultForClient, { method, message: result });
418
+ return result;
419
+ } finally {
420
+ signal?.removeEventListener('abort', cancel);
421
+ }
422
+ }
423
+
327
424
  /**
328
425
  * Close the connection to the server.
329
426
  */
@@ -370,7 +370,8 @@ export class DocumentConnectionManager implements ILSPDocumentConnectionManager
370
370
 
371
371
  /**
372
372
  * Create a new connection to the language server
373
- * @return A promise of the LSP connection
373
+ *
374
+ * Returns a promise of the LSP connection.
374
375
  */
375
376
  async connect(
376
377
  options: ISocketConnectionOptions,
@@ -487,7 +488,7 @@ export class DocumentConnectionManager implements ILSPDocumentConnectionManager
487
488
  /**
488
489
  * Create the LSP connection for requested virtual document.
489
490
  *
490
- * @return Return the promise of the LSP connection.
491
+ * Returns a promise of the LSP connection.
491
492
  */
492
493
 
493
494
  private async _connectSocket(
@@ -725,8 +726,17 @@ namespace Private {
725
726
  ): Promise<LSPConnection> {
726
727
  let connection = _connections.get(languageServerId);
727
728
  if (!connection) {
728
- const { settings } = Private.getLanguageServerManager();
729
- const socket = new settings.WebSocket(uris.socket);
729
+ const serverManager = Private.getLanguageServerManager();
730
+ const { settings } = serverManager;
731
+ const transportFactory =
732
+ serverManager.getTransportFactory(languageServerId);
733
+ const socket = transportFactory
734
+ ? transportFactory({
735
+ languageServerId,
736
+ socketUrl: uris.socket,
737
+ settings
738
+ })
739
+ : new settings.WebSocket(uris.socket);
730
740
  const connection = new LSPConnection({
731
741
  languageId: language,
732
742
  serverUri: uris.server,
package/src/manager.ts CHANGED
@@ -1,13 +1,16 @@
1
1
  // Copyright (c) Jupyter Development Team.
2
2
  // Distributed under the terms of the Modified BSD License.
3
- /* eslint-disable @typescript-eslint/no-explicit-any */
4
3
 
5
4
  import { URLExt } from '@jupyterlab/coreutils';
6
5
  import { ServerConnection } from '@jupyterlab/services';
6
+ import { PromiseDelegate } from '@lumino/coreutils';
7
+ import { DisposableDelegate } from '@lumino/disposable';
8
+ import type { IDisposable } from '@lumino/disposable';
7
9
  import type { ISignal } from '@lumino/signaling';
8
10
  import { Signal } from '@lumino/signaling';
9
11
 
10
12
  import type {
13
+ ILanguageServerProvider,
11
14
  TLanguageServerConfigurations,
12
15
  TLanguageServerId,
13
16
  TSessionMap,
@@ -15,7 +18,11 @@ import type {
15
18
  } from './tokens';
16
19
  import { ILanguageServerManager } from './tokens';
17
20
  import type { ServerSpecProperties } from './schema';
18
- import { PromiseDelegate } from '@lumino/coreutils';
21
+
22
+ interface IProviderRegistration {
23
+ provider: ILanguageServerProvider;
24
+ onSessionsChanged: () => void;
25
+ }
19
26
 
20
27
  export class LanguageServerManager implements ILanguageServerManager {
21
28
  constructor(options: ILanguageServerManager.IOptions) {
@@ -106,6 +113,10 @@ export class LanguageServerManager implements ILanguageServerManager {
106
113
  disable(): void {
107
114
  this._enabled = false;
108
115
  this._sessions = new Map();
116
+ this._specs = new Map();
117
+ this._serverSessions = new Map();
118
+ this._serverSpecs = new Map();
119
+ this._transports.clear();
109
120
  this._sessionsChanged.emit(void 0);
110
121
  }
111
122
 
@@ -118,6 +129,18 @@ export class LanguageServerManager implements ILanguageServerManager {
118
129
  }
119
130
  this._isDisposed = true;
120
131
 
132
+ for (const registration of this._providers.values()) {
133
+ if (registration.provider.sessionsChanged) {
134
+ registration.provider.sessionsChanged.disconnect(
135
+ registration.onSessionsChanged
136
+ );
137
+ }
138
+ }
139
+ this._providers.clear();
140
+ this._serverSessions.clear();
141
+ this._serverSpecs.clear();
142
+ this._transports.clear();
143
+
121
144
  Signal.clearData(this);
122
145
  }
123
146
 
@@ -128,6 +151,52 @@ export class LanguageServerManager implements ILanguageServerManager {
128
151
  this._configuration = configuration;
129
152
  }
130
153
 
154
+ /**
155
+ * Register a runtime language server provider.
156
+ */
157
+ registerProvider(provider: ILanguageServerProvider): IDisposable {
158
+ if (this._providers.has(provider.id)) {
159
+ console.warn(
160
+ `Language server provider with id ${provider.id} is already registered`
161
+ );
162
+ return new DisposableDelegate(() => undefined);
163
+ }
164
+
165
+ const registration = {
166
+ provider,
167
+ onSessionsChanged: () => {
168
+ void this.fetchSessions().catch(console.error);
169
+ }
170
+ };
171
+ this._providers.set(provider.id, registration);
172
+
173
+ if (provider.sessionsChanged) {
174
+ provider.sessionsChanged.connect(registration.onSessionsChanged);
175
+ }
176
+
177
+ void this.fetchSessions().catch(console.error);
178
+
179
+ return new DisposableDelegate(() => {
180
+ if (this._providers.get(provider.id) !== registration) {
181
+ return;
182
+ }
183
+ if (provider.sessionsChanged) {
184
+ provider.sessionsChanged.disconnect(registration.onSessionsChanged);
185
+ }
186
+ this._providers.delete(provider.id);
187
+ void this.fetchSessions().catch(console.error);
188
+ });
189
+ }
190
+
191
+ /**
192
+ * Get a runtime transport factory for a language server.
193
+ */
194
+ getTransportFactory(
195
+ languageServerId: TLanguageServerId
196
+ ): ILanguageServerProvider.TTransportFactory | null {
197
+ return this._transports.get(languageServerId) ?? null;
198
+ }
199
+
131
200
  /**
132
201
  * Get matching language server for input language option.
133
202
  */
@@ -176,58 +245,62 @@ export class LanguageServerManager implements ILanguageServerManager {
176
245
  if (!this._enabled) {
177
246
  return;
178
247
  }
179
- let response = await ServerConnection.makeRequest(
180
- this.statusUrl,
181
- { method: 'GET' },
182
- this._settings
183
- );
184
-
185
- this._statusCode = response.status;
186
- if (!response.ok) {
187
- if (this._retries > 0) {
188
- this._retries -= 1;
189
- setTimeout(this.fetchSessions.bind(this), this._retriesInterval);
190
- } else {
191
- this._ready.resolve(undefined);
192
- console.log('Missing jupyter_lsp server extension, skipping.');
193
- }
248
+ let statusCode = this._statusCode;
249
+ const sessions: TSessionMap = new Map();
250
+ const specs: TSpecsMap = new Map();
251
+ const transports = new Map<
252
+ TLanguageServerId,
253
+ ILanguageServerProvider.TTransportFactory
254
+ >();
255
+
256
+ const serverData = await this._fetchServerData();
257
+ if (serverData?.statusCode !== undefined) {
258
+ statusCode = serverData.statusCode;
259
+ this._statusCode = statusCode;
260
+ }
261
+ if (serverData?.retryScheduled && this._providers.size === 0) {
194
262
  return;
195
263
  }
264
+ if (serverData?.sessions !== undefined) {
265
+ this._syncSnapshot(this._serverSessions, serverData.sessions);
266
+ }
267
+ if (serverData?.specs !== undefined) {
268
+ this._syncSnapshot(this._serverSpecs, serverData.specs);
269
+ }
270
+ if (serverData) {
271
+ if (serverData.version !== undefined) {
272
+ this.version = serverData.version;
273
+ }
274
+ }
196
275
 
197
- let sessions: { [key: string]: any };
276
+ this._mergeSnapshot(specs, this._serverSpecs);
277
+ this._mergeSnapshot(sessions, this._serverSessions);
198
278
 
199
- try {
200
- const data = await response.json();
201
- sessions = data.sessions;
279
+ for (const registration of this._providers.values()) {
202
280
  try {
203
- this.version = data.version;
204
- this._specs = new Map(Object.entries(data.specs)) as TSpecsMap;
281
+ const data = await registration.provider.fetch();
282
+ if (!data) {
283
+ continue;
284
+ }
285
+ if (data.statusCode !== undefined) {
286
+ statusCode = data.statusCode;
287
+ }
288
+ this._mergeSnapshot(specs, data.specs);
289
+ this._mergeSnapshot(sessions, data.sessions);
290
+ if (data.transport) {
291
+ for (const [key, factory] of Object.entries(data.transport)) {
292
+ transports.set(key as TLanguageServerId, factory);
293
+ }
294
+ }
205
295
  } catch (err) {
206
296
  console.warn(err);
207
297
  }
208
- } catch (err) {
209
- console.warn(err);
210
- this._ready.resolve(undefined);
211
- return;
212
298
  }
213
299
 
214
- for (let key of Object.keys(sessions)) {
215
- let id: TLanguageServerId = key as TLanguageServerId;
216
- if (this._sessions.has(id)) {
217
- Object.assign(this._sessions.get(id) || {}, sessions[key]);
218
- } else {
219
- this._sessions.set(id, sessions[key]);
220
- }
221
- }
222
-
223
- const oldKeys = this._sessions.keys();
224
-
225
- for (const oldKey in oldKeys) {
226
- if (!sessions[oldKey]) {
227
- let oldId = oldKey as TLanguageServerId;
228
- this._sessions.delete(oldId);
229
- }
230
- }
300
+ this._statusCode = statusCode;
301
+ this._transports = transports;
302
+ this._syncSnapshot(this._specs, specs);
303
+ this._syncSnapshot(this._sessions, sessions);
231
304
  this._sessionsChanged.emit(void 0);
232
305
  this._ready.resolve(undefined);
233
306
  }
@@ -280,6 +353,95 @@ export class LanguageServerManager implements ILanguageServerManager {
280
353
  return bRank - aRank;
281
354
  }
282
355
 
356
+ /**
357
+ * Fetch language server data from the HTTP endpoint.
358
+ */
359
+ private async _fetchServerData(): Promise<
360
+ | (ILanguageServerProvider.IFetchResult & {
361
+ version?: number;
362
+ retryScheduled?: boolean;
363
+ })
364
+ | null
365
+ > {
366
+ let response: Response;
367
+
368
+ try {
369
+ response = await ServerConnection.makeRequest(
370
+ this.statusUrl,
371
+ { method: 'GET' },
372
+ this._settings
373
+ );
374
+ } catch (err) {
375
+ console.warn(err);
376
+ return null;
377
+ }
378
+
379
+ if (!response.ok) {
380
+ if (this._retries > 0) {
381
+ this._retries -= 1;
382
+ setTimeout(this.fetchSessions.bind(this), this._retriesInterval);
383
+ return { statusCode: response.status, retryScheduled: true };
384
+ } else {
385
+ console.log('Missing jupyter_lsp server extension, skipping.');
386
+ }
387
+ return { statusCode: response.status };
388
+ }
389
+
390
+ try {
391
+ const data = await response.json();
392
+ return {
393
+ statusCode: response.status,
394
+ version: data.version,
395
+ sessions: data.sessions,
396
+ specs: data.specs
397
+ };
398
+ } catch (err) {
399
+ console.warn(err);
400
+ return { statusCode: response.status };
401
+ }
402
+ }
403
+
404
+ /**
405
+ * Merge provider snapshot into target map.
406
+ */
407
+ private _mergeSnapshot<T>(
408
+ target: Map<TLanguageServerId, T>,
409
+ source?: Map<TLanguageServerId, T> | { [key: string]: T }
410
+ ): void {
411
+ if (!source) {
412
+ return;
413
+ }
414
+ const entries =
415
+ source instanceof Map ? source.entries() : Object.entries(source);
416
+
417
+ for (const [key, value] of entries) {
418
+ target.set(key as TLanguageServerId, value);
419
+ }
420
+ }
421
+
422
+ /**
423
+ * Synchronize a mutable map in place.
424
+ */
425
+ private _syncSnapshot<T>(
426
+ target: Map<TLanguageServerId, T>,
427
+ source: Map<TLanguageServerId, T> | { [key: string]: T }
428
+ ): void {
429
+ const entries =
430
+ source instanceof Map ? source.entries() : Object.entries(source);
431
+ const nextKeys = new Set<TLanguageServerId>();
432
+
433
+ for (const [key, value] of entries) {
434
+ const id = key as TLanguageServerId;
435
+ nextKeys.add(id);
436
+ target.set(id, value);
437
+ }
438
+ for (const key of Array.from(target.keys())) {
439
+ if (!nextKeys.has(key)) {
440
+ target.delete(key);
441
+ }
442
+ }
443
+ }
444
+
283
445
  /**
284
446
  * Get the base URL for language server requests.
285
447
  */
@@ -297,6 +459,16 @@ export class LanguageServerManager implements ILanguageServerManager {
297
459
  */
298
460
  private _specs: TSpecsMap = new Map();
299
461
 
462
+ /**
463
+ * Last known language server sessions from HTTP status endpoint.
464
+ */
465
+ private _serverSessions: TSessionMap = new Map();
466
+
467
+ /**
468
+ * Last known language server specs from HTTP status endpoint.
469
+ */
470
+ private _serverSpecs: TSpecsMap = new Map();
471
+
300
472
  /**
301
473
  * Server connection setting.
302
474
  */
@@ -344,6 +516,19 @@ export class LanguageServerManager implements ILanguageServerManager {
344
516
  this
345
517
  );
346
518
 
519
+ /**
520
+ * Runtime language server providers.
521
+ */
522
+ private _providers = new Map<string, IProviderRegistration>();
523
+
524
+ /**
525
+ * Runtime language server transport factories.
526
+ */
527
+ private _transports = new Map<
528
+ TLanguageServerId,
529
+ ILanguageServerProvider.TTransportFactory
530
+ >();
531
+
347
532
  private _isDisposed = false;
348
533
 
349
534
  /**
package/src/plugin.ts CHANGED
@@ -11,7 +11,7 @@
11
11
  /**
12
12
  * Enable or disable the language server services.
13
13
  */
14
- export type Activate = Off | On;
14
+ export type Activate = (Off | On) & string;
15
15
  export type Off = 'off';
16
16
  export type On = 'on';
17
17
  /**
@@ -21,7 +21,8 @@ export type RankOfTheServer = number;
21
21
  /**
22
22
  * Whether to ask server to send logs with execution trace (for debugging). Accepted values are: "off", "messages", "verbose". Servers are allowed to ignore this request.
23
23
  */
24
- export type AskServersToSendTraceNotifications = Off1 | Messages | Verbose;
24
+ export type AskServersToSendTraceNotifications = (Off1 | Messages | Verbose) &
25
+ string;
25
26
  export type Off1 = 'off';
26
27
  export type Messages = 'messages';
27
28
  export type Verbose = 'verbose';