@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,611 @@
|
|
|
1
|
+
// Copyright (c) Jupyter Development Team.
|
|
2
|
+
// Distributed under the terms of the Modified BSD License.
|
|
3
|
+
|
|
4
|
+
import type { NotebookView } from '@difizen/libro-core';
|
|
5
|
+
import { Emitter } from '@difizen/mana-app';
|
|
6
|
+
import type { Disposable, Event, View } from '@difizen/mana-app';
|
|
7
|
+
import type {} from '@difizen/mana-app';
|
|
8
|
+
import mergeWith from 'lodash.mergewith';
|
|
9
|
+
|
|
10
|
+
import type { ClientCapabilities, LanguageIdentifier } from '../lsp.js';
|
|
11
|
+
import type { IVirtualPosition } from '../positioning.js';
|
|
12
|
+
import type {
|
|
13
|
+
Document,
|
|
14
|
+
IDocumentConnectionData,
|
|
15
|
+
ILSPCodeExtractorsManager,
|
|
16
|
+
ILSPDocumentConnectionManager,
|
|
17
|
+
ILSPFeatureManager,
|
|
18
|
+
ISocketConnectionOptions,
|
|
19
|
+
} from '../tokens.js';
|
|
20
|
+
import type { VirtualDocument } from '../virtual/document.js';
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* The values should follow the https://microsoft.github.io/language-server-protocol/specification guidelines
|
|
24
|
+
*/
|
|
25
|
+
const MIME_TYPE_LANGUAGE_MAP: Record<string, string> = {
|
|
26
|
+
'text/x-rsrc': 'r',
|
|
27
|
+
'text/x-r-source': 'r',
|
|
28
|
+
// currently there are no LSP servers for IPython we are aware of
|
|
29
|
+
'text/x-ipython': 'python',
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
export interface IEditorChangedData {
|
|
33
|
+
/**
|
|
34
|
+
* The CM editor invoking the change event.
|
|
35
|
+
*/
|
|
36
|
+
editor: Document.IEditor;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
export interface IAdapterOptions {
|
|
40
|
+
/**
|
|
41
|
+
* The LSP document and connection manager instance.
|
|
42
|
+
*/
|
|
43
|
+
connectionManager: ILSPDocumentConnectionManager;
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* The LSP feature manager instance.
|
|
47
|
+
*/
|
|
48
|
+
featureManager: ILSPFeatureManager;
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* The LSP foreign code extractor manager.
|
|
52
|
+
*/
|
|
53
|
+
foreignCodeExtractorsManager: ILSPCodeExtractorsManager;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* Foreign code: low level adapter is not aware of the presence of foreign languages;
|
|
58
|
+
* it operates on the virtual document and must not attempt to infer the language dependencies
|
|
59
|
+
* as this would make the logic of inspections caching impossible to maintain, thus the WidgetAdapter
|
|
60
|
+
* has to handle that, keeping multiple connections and multiple virtual documents.
|
|
61
|
+
*/
|
|
62
|
+
export abstract class WidgetLSPAdapter<T extends NotebookView> implements Disposable {
|
|
63
|
+
// note: it could be using namespace/IOptions pattern,
|
|
64
|
+
// but I do not know how to make it work with the generic type T
|
|
65
|
+
// (other than using 'any' in the IOptions interface)
|
|
66
|
+
constructor(
|
|
67
|
+
public widget: T,
|
|
68
|
+
protected options: IAdapterOptions,
|
|
69
|
+
) {
|
|
70
|
+
this._connectionManager = options.connectionManager;
|
|
71
|
+
this._isConnected = false;
|
|
72
|
+
// set up signal connections
|
|
73
|
+
this.widget.onSave(this.onSaveState);
|
|
74
|
+
// this.widget.context.saveState.connect(this.onSaveState, this);
|
|
75
|
+
// this.connectionManager.closed.connect(this.onConnectionClosed, this);
|
|
76
|
+
// this.widget.disposed.connect(this.dispose, this);
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* Check if the adapter is disposed
|
|
81
|
+
*/
|
|
82
|
+
get disposed(): boolean {
|
|
83
|
+
return this._isDisposed;
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* Check if the document contains multiple editors
|
|
87
|
+
*/
|
|
88
|
+
get hasMultipleEditors(): boolean {
|
|
89
|
+
return this.editors.length > 1;
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* Get the ID of the internal widget.
|
|
93
|
+
*/
|
|
94
|
+
get widgetId(): string {
|
|
95
|
+
return this.widget.id;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
/**
|
|
99
|
+
* Get the language identifier of the document
|
|
100
|
+
*/
|
|
101
|
+
get language(): LanguageIdentifier {
|
|
102
|
+
// the values should follow https://microsoft.github.io/language-server-protocol/specification guidelines,
|
|
103
|
+
// see the table in https://microsoft.github.io/language-server-protocol/specification#textDocumentItem
|
|
104
|
+
if (Object.prototype.hasOwnProperty.call(MIME_TYPE_LANGUAGE_MAP, this.mimeType)) {
|
|
105
|
+
return MIME_TYPE_LANGUAGE_MAP[this.mimeType];
|
|
106
|
+
} else {
|
|
107
|
+
const withoutParameters = this.mimeType.split(';')[0];
|
|
108
|
+
const [type, subtype] = withoutParameters.split('/');
|
|
109
|
+
if (type === 'application' || type === 'text') {
|
|
110
|
+
if (subtype.startsWith('x-')) {
|
|
111
|
+
return subtype.substring(2);
|
|
112
|
+
} else {
|
|
113
|
+
return subtype;
|
|
114
|
+
}
|
|
115
|
+
} else {
|
|
116
|
+
return this.mimeType;
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
/**
|
|
122
|
+
* Signal emitted when the adapter is connected.
|
|
123
|
+
*/
|
|
124
|
+
get adapterConnected(): Event<IDocumentConnectionData> {
|
|
125
|
+
return this._adapterConnected.event;
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
/**
|
|
129
|
+
* Signal emitted when the active editor have changed.
|
|
130
|
+
*/
|
|
131
|
+
get activeEditorChanged(): Event<IEditorChangedData> {
|
|
132
|
+
return this._activeEditorChanged.event;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
/**
|
|
136
|
+
* Signal emitted when the adapter is disposed.
|
|
137
|
+
*/
|
|
138
|
+
get onDispose(): Event<void> {
|
|
139
|
+
return this._disposed.event;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
/**
|
|
143
|
+
* Signal emitted when the an editor is changed.
|
|
144
|
+
*/
|
|
145
|
+
get editorAdded(): Event<IEditorChangedData> {
|
|
146
|
+
return this._editorAdded.event;
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
/**
|
|
150
|
+
* Signal emitted when the an editor is removed.
|
|
151
|
+
*/
|
|
152
|
+
get editorRemoved(): Event<IEditorChangedData> {
|
|
153
|
+
return this._editorRemoved.event;
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
/**
|
|
157
|
+
* Get the inner HTMLElement of the document widget.
|
|
158
|
+
*/
|
|
159
|
+
abstract get wrapperElement(): HTMLElement;
|
|
160
|
+
|
|
161
|
+
/**
|
|
162
|
+
* Get current path of the document.
|
|
163
|
+
*/
|
|
164
|
+
abstract get documentPath(): string;
|
|
165
|
+
|
|
166
|
+
/**
|
|
167
|
+
* Get the mime type of the document.
|
|
168
|
+
*/
|
|
169
|
+
abstract get mimeType(): string;
|
|
170
|
+
|
|
171
|
+
/**
|
|
172
|
+
* Get the file extension of the document.
|
|
173
|
+
*/
|
|
174
|
+
abstract get languageFileExtension(): string | undefined;
|
|
175
|
+
|
|
176
|
+
/**
|
|
177
|
+
* Get the activated CM editor.
|
|
178
|
+
*/
|
|
179
|
+
abstract get activeEditor(): Document.IEditor | undefined;
|
|
180
|
+
|
|
181
|
+
/**
|
|
182
|
+
* Get the list of CM editors in the document, there is only one editor
|
|
183
|
+
* in the case of file editor.
|
|
184
|
+
*/
|
|
185
|
+
abstract get editors(): Document.ICodeBlockOptions[];
|
|
186
|
+
|
|
187
|
+
/**
|
|
188
|
+
* Promise that resolves once the adapter is initialized
|
|
189
|
+
*/
|
|
190
|
+
abstract get ready(): Promise<void>;
|
|
191
|
+
|
|
192
|
+
/**
|
|
193
|
+
* The virtual document is connected or not
|
|
194
|
+
*/
|
|
195
|
+
get isConnected(): boolean {
|
|
196
|
+
return this._isConnected;
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
/**
|
|
200
|
+
* The LSP document and connection manager instance.
|
|
201
|
+
*/
|
|
202
|
+
get connectionManager(): ILSPDocumentConnectionManager {
|
|
203
|
+
return this._connectionManager;
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
/**
|
|
207
|
+
* Promise that resolves once the document is updated
|
|
208
|
+
*/
|
|
209
|
+
get updateFinished(): Promise<void> {
|
|
210
|
+
return this._updateFinished;
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
/**
|
|
214
|
+
* Internal virtual document of the adapter.
|
|
215
|
+
*/
|
|
216
|
+
get virtualDocument(): VirtualDocument | null {
|
|
217
|
+
return this._virtualDocument;
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
/**
|
|
221
|
+
* Callback on connection closed event.
|
|
222
|
+
*/
|
|
223
|
+
onConnectionClosed(
|
|
224
|
+
_: ILSPDocumentConnectionManager,
|
|
225
|
+
{ virtualDocument }: IDocumentConnectionData,
|
|
226
|
+
): void {
|
|
227
|
+
if (virtualDocument === this.virtualDocument) {
|
|
228
|
+
this.dispose();
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
/**
|
|
233
|
+
* Dispose the adapter.
|
|
234
|
+
*/
|
|
235
|
+
dispose(): void {
|
|
236
|
+
if (this._isDisposed) {
|
|
237
|
+
return;
|
|
238
|
+
}
|
|
239
|
+
this._isDisposed = true;
|
|
240
|
+
this.disconnect();
|
|
241
|
+
this._virtualDocument = null;
|
|
242
|
+
this._disposed.fire();
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
/**
|
|
246
|
+
* Disconnect virtual document from the language server.
|
|
247
|
+
*/
|
|
248
|
+
disconnect(): void {
|
|
249
|
+
const uri = this.virtualDocument?.uri;
|
|
250
|
+
if (uri) {
|
|
251
|
+
this.connectionManager.unregisterDocument(uri);
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
// pretend that all editors were removed to trigger the disconnection of even handlers
|
|
255
|
+
// they will be connected again on new connection
|
|
256
|
+
for (const { ceEditor: editor } of this.editors) {
|
|
257
|
+
this._editorRemoved.fire({
|
|
258
|
+
editor: editor,
|
|
259
|
+
});
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
this.virtualDocument?.dispose();
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
/**
|
|
266
|
+
* Update the virtual document.
|
|
267
|
+
*/
|
|
268
|
+
updateDocuments(): Promise<void> {
|
|
269
|
+
if (this._isDisposed) {
|
|
270
|
+
console.warn('Cannot update documents: adapter disposed');
|
|
271
|
+
return Promise.reject('Cannot update documents: adapter disposed');
|
|
272
|
+
}
|
|
273
|
+
return this.virtualDocument!.updateManager.updateDocuments(this.editors);
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
/**
|
|
277
|
+
* Callback called on the document changed event.
|
|
278
|
+
*/
|
|
279
|
+
documentChanged(virtualDocument: VirtualDocument): void {
|
|
280
|
+
if (this._isDisposed) {
|
|
281
|
+
console.warn('Cannot swap document: adapter disposed');
|
|
282
|
+
return;
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
// TODO only send the difference, using connection.sendSelectiveChange()
|
|
286
|
+
const connection = this.connectionManager.connections.get(virtualDocument.uri);
|
|
287
|
+
|
|
288
|
+
if (!connection?.isReady) {
|
|
289
|
+
console.warn('Skipping document update signal: connection not ready');
|
|
290
|
+
return;
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
connection.sendFullTextChange(virtualDocument.value, virtualDocument.documentInfo);
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
/**
|
|
297
|
+
* (re)create virtual document using current path and language
|
|
298
|
+
*/
|
|
299
|
+
protected abstract createVirtualDocument(): VirtualDocument;
|
|
300
|
+
|
|
301
|
+
/**
|
|
302
|
+
* Get the index of editor from the cursor position in the virtual
|
|
303
|
+
* document. Since there is only one editor, this method always return
|
|
304
|
+
* 0
|
|
305
|
+
*
|
|
306
|
+
* @param position - the position of cursor in the virtual document.
|
|
307
|
+
* @return - index of the virtual editor
|
|
308
|
+
*/
|
|
309
|
+
abstract getEditorIndexAt(position: IVirtualPosition): number;
|
|
310
|
+
|
|
311
|
+
/**
|
|
312
|
+
* Get the index of input editor
|
|
313
|
+
*
|
|
314
|
+
* @param ceEditor - instance of the code editor
|
|
315
|
+
*/
|
|
316
|
+
abstract getEditorIndex(ceEditor: Document.IEditor): number;
|
|
317
|
+
|
|
318
|
+
/**
|
|
319
|
+
* Get the index of input editor
|
|
320
|
+
*
|
|
321
|
+
* @param ceEditor - instance of the code editor
|
|
322
|
+
*/
|
|
323
|
+
abstract getCellEditor(cell: View): Document.IEditor | undefined;
|
|
324
|
+
|
|
325
|
+
/**
|
|
326
|
+
* Get the wrapper of input editor.
|
|
327
|
+
*
|
|
328
|
+
* @param ceEditor
|
|
329
|
+
*/
|
|
330
|
+
abstract getEditorWrapper(ceEditor: Document.IEditor): HTMLElement | undefined;
|
|
331
|
+
|
|
332
|
+
// equivalent to triggering didClose and didOpen, as per syncing specification,
|
|
333
|
+
// but also reloads the connection; used during file rename (or when it was moved)
|
|
334
|
+
protected reloadConnection(): void {
|
|
335
|
+
// ignore premature calls (before the editor was initialized)
|
|
336
|
+
if (this.virtualDocument === null) {
|
|
337
|
+
return;
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
// disconnect all existing connections (and dispose adapters)
|
|
341
|
+
this.disconnect();
|
|
342
|
+
|
|
343
|
+
// recreate virtual document using current path and language
|
|
344
|
+
// as virtual editor assumes it gets the virtual document at init,
|
|
345
|
+
// just dispose virtual editor (which disposes virtual document too)
|
|
346
|
+
// and re-initialize both virtual editor and document
|
|
347
|
+
this.initVirtual();
|
|
348
|
+
|
|
349
|
+
// reconnect
|
|
350
|
+
this.connectDocument(this.virtualDocument, true).catch(console.warn);
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
/**
|
|
354
|
+
* Callback on document saved event.
|
|
355
|
+
*/
|
|
356
|
+
protected onSaveState = (): void => {
|
|
357
|
+
// ignore premature calls (before the editor was initialized)
|
|
358
|
+
if (this.virtualDocument === null) {
|
|
359
|
+
return;
|
|
360
|
+
}
|
|
361
|
+
|
|
362
|
+
const documentsToSave = [this.virtualDocument];
|
|
363
|
+
|
|
364
|
+
for (const virtualDocument of documentsToSave) {
|
|
365
|
+
const connection = this.connectionManager.connections.get(virtualDocument.uri);
|
|
366
|
+
if (!connection) {
|
|
367
|
+
continue;
|
|
368
|
+
}
|
|
369
|
+
connection.sendSaved(virtualDocument.documentInfo);
|
|
370
|
+
for (const foreign of virtualDocument.foreignDocuments.values()) {
|
|
371
|
+
documentsToSave.push(foreign);
|
|
372
|
+
}
|
|
373
|
+
}
|
|
374
|
+
};
|
|
375
|
+
|
|
376
|
+
/**
|
|
377
|
+
* Connect the virtual document with the language server.
|
|
378
|
+
*/
|
|
379
|
+
protected async onConnected(data: IDocumentConnectionData): Promise<void> {
|
|
380
|
+
const { virtualDocument } = data;
|
|
381
|
+
|
|
382
|
+
this._adapterConnected.fire(data);
|
|
383
|
+
this._isConnected = true;
|
|
384
|
+
|
|
385
|
+
try {
|
|
386
|
+
await this.updateDocuments();
|
|
387
|
+
} catch (reason) {
|
|
388
|
+
console.warn('Could not update documents', reason);
|
|
389
|
+
return;
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
// refresh the document on the LSP server
|
|
393
|
+
this.documentChanged(virtualDocument);
|
|
394
|
+
|
|
395
|
+
data.connection.serverNotifications['$/logTrace'].event((message) => {
|
|
396
|
+
console.warn(
|
|
397
|
+
data.connection.serverIdentifier,
|
|
398
|
+
'trace',
|
|
399
|
+
virtualDocument.uri,
|
|
400
|
+
message,
|
|
401
|
+
);
|
|
402
|
+
});
|
|
403
|
+
|
|
404
|
+
data.connection.serverNotifications['window/logMessage'].event((message) => {
|
|
405
|
+
console.warn(data.connection.serverIdentifier + ': ' + message.message);
|
|
406
|
+
});
|
|
407
|
+
|
|
408
|
+
data.connection.serverNotifications['window/showMessage'].event((message) => {
|
|
409
|
+
// void showDialog({
|
|
410
|
+
// title: this.trans.__('Message from ') + connection.serverIdentifier,
|
|
411
|
+
// body: message.message,
|
|
412
|
+
// });
|
|
413
|
+
alert(`Message from ${data.connection.serverIdentifier}: ${message.message}`);
|
|
414
|
+
});
|
|
415
|
+
|
|
416
|
+
data.connection.serverRequests['window/showMessageRequest'].setHandler(
|
|
417
|
+
async (params) => {
|
|
418
|
+
alert(`Message from ${data.connection.serverIdentifier}: ${params.message}`);
|
|
419
|
+
return null;
|
|
420
|
+
|
|
421
|
+
// const actionItems = params.actions;
|
|
422
|
+
// const buttons = actionItems
|
|
423
|
+
// ? actionItems.map(action => {
|
|
424
|
+
// return createButton({
|
|
425
|
+
// label: action.title,
|
|
426
|
+
// });
|
|
427
|
+
// })
|
|
428
|
+
// : [createButton({ label: this.trans.__('Dismiss') })];
|
|
429
|
+
// const result = await showDialog<IButton>({
|
|
430
|
+
// title: this.trans.__('Message from ') + data.connection.serverIdentifier,
|
|
431
|
+
// body: params.message,
|
|
432
|
+
// buttons: buttons,
|
|
433
|
+
// });
|
|
434
|
+
// const choice = buttons.indexOf(result.button);
|
|
435
|
+
// if (choice === -1) {
|
|
436
|
+
// return null;
|
|
437
|
+
// }
|
|
438
|
+
// if (actionItems) {
|
|
439
|
+
// return actionItems[choice];
|
|
440
|
+
// }
|
|
441
|
+
// return null;
|
|
442
|
+
},
|
|
443
|
+
);
|
|
444
|
+
}
|
|
445
|
+
|
|
446
|
+
/**
|
|
447
|
+
* Opens a connection for the document. The connection may or may
|
|
448
|
+
* not be initialized, yet, and depending on when this is called, the client
|
|
449
|
+
* may not be fully connected.
|
|
450
|
+
*
|
|
451
|
+
* @param virtualDocument a VirtualDocument
|
|
452
|
+
* @param sendOpen whether to open the document immediately
|
|
453
|
+
*/
|
|
454
|
+
protected async connectDocument(
|
|
455
|
+
virtualDocument: VirtualDocument,
|
|
456
|
+
sendOpen = false,
|
|
457
|
+
): Promise<void> {
|
|
458
|
+
virtualDocument.foreignDocumentOpened(this.onForeignDocumentOpened, this);
|
|
459
|
+
const connectionContext = await this._connect(virtualDocument).catch(console.error);
|
|
460
|
+
|
|
461
|
+
if (connectionContext && connectionContext.connection) {
|
|
462
|
+
virtualDocument.changed(this.documentChanged, this);
|
|
463
|
+
if (sendOpen) {
|
|
464
|
+
connectionContext.connection.sendOpenWhenReady(virtualDocument.documentInfo);
|
|
465
|
+
}
|
|
466
|
+
}
|
|
467
|
+
}
|
|
468
|
+
|
|
469
|
+
/**
|
|
470
|
+
* Create the virtual document using current path and language.
|
|
471
|
+
*/
|
|
472
|
+
protected initVirtual(): void {
|
|
473
|
+
const { model } = this.widget;
|
|
474
|
+
this._virtualDocument?.dispose();
|
|
475
|
+
this._virtualDocument = this.createVirtualDocument();
|
|
476
|
+
model.onSourceChanged?.(() => this._onContentChanged());
|
|
477
|
+
}
|
|
478
|
+
|
|
479
|
+
/**
|
|
480
|
+
* Handler for opening a document contained in a parent document. The assumption
|
|
481
|
+
* is that the editor already exists for this, and as such the document
|
|
482
|
+
* should be queued for immediate opening.
|
|
483
|
+
*
|
|
484
|
+
* @param host the VirtualDocument that contains the VirtualDocument in another language
|
|
485
|
+
* @param context information about the foreign VirtualDocument
|
|
486
|
+
*/
|
|
487
|
+
protected async onForeignDocumentOpened(
|
|
488
|
+
context: Document.IForeignContext,
|
|
489
|
+
): Promise<void> {
|
|
490
|
+
const { foreignDocument } = context;
|
|
491
|
+
|
|
492
|
+
await this.connectDocument(foreignDocument, true);
|
|
493
|
+
|
|
494
|
+
foreignDocument.foreignDocumentClosed(this._onForeignDocumentClosed, this);
|
|
495
|
+
}
|
|
496
|
+
|
|
497
|
+
/**
|
|
498
|
+
* Signal emitted when the adapter is connected.
|
|
499
|
+
*/
|
|
500
|
+
protected _adapterConnected = new Emitter<IDocumentConnectionData>();
|
|
501
|
+
|
|
502
|
+
/**
|
|
503
|
+
* Signal emitted when the active editor have changed.
|
|
504
|
+
*/
|
|
505
|
+
protected _activeEditorChanged = new Emitter<IEditorChangedData>();
|
|
506
|
+
|
|
507
|
+
/**
|
|
508
|
+
* Signal emitted when an editor is changed.
|
|
509
|
+
*/
|
|
510
|
+
protected _editorAdded = new Emitter<IEditorChangedData>();
|
|
511
|
+
|
|
512
|
+
/**
|
|
513
|
+
* Signal emitted when an editor is removed.
|
|
514
|
+
*/
|
|
515
|
+
protected _editorRemoved = new Emitter<IEditorChangedData>();
|
|
516
|
+
|
|
517
|
+
/**
|
|
518
|
+
* Signal emitted when the adapter is disposed.
|
|
519
|
+
*/
|
|
520
|
+
protected _disposed = new Emitter<void>();
|
|
521
|
+
|
|
522
|
+
protected _isDisposed = false;
|
|
523
|
+
|
|
524
|
+
protected readonly _connectionManager: ILSPDocumentConnectionManager;
|
|
525
|
+
|
|
526
|
+
protected _isConnected: boolean;
|
|
527
|
+
protected _updateFinished: Promise<void>;
|
|
528
|
+
protected _virtualDocument: VirtualDocument | null = null;
|
|
529
|
+
|
|
530
|
+
/**
|
|
531
|
+
* Callback called when a foreign document is closed,
|
|
532
|
+
* the associated signals with this virtual document
|
|
533
|
+
* are disconnected.
|
|
534
|
+
*/
|
|
535
|
+
protected _onForeignDocumentClosed(context: Document.IForeignContext): void {
|
|
536
|
+
// const { foreignDocument } = context;
|
|
537
|
+
}
|
|
538
|
+
|
|
539
|
+
/**
|
|
540
|
+
* Detect the capabilities for the document type then
|
|
541
|
+
* open the websocket connection with the language server.
|
|
542
|
+
*/
|
|
543
|
+
protected async _connect(virtualDocument: VirtualDocument) {
|
|
544
|
+
const language = virtualDocument.language;
|
|
545
|
+
|
|
546
|
+
let capabilities: ClientCapabilities = {
|
|
547
|
+
textDocument: {
|
|
548
|
+
synchronization: {
|
|
549
|
+
dynamicRegistration: true,
|
|
550
|
+
willSave: false,
|
|
551
|
+
didSave: true,
|
|
552
|
+
willSaveWaitUntil: false,
|
|
553
|
+
},
|
|
554
|
+
},
|
|
555
|
+
workspace: {
|
|
556
|
+
didChangeConfiguration: {
|
|
557
|
+
dynamicRegistration: true,
|
|
558
|
+
},
|
|
559
|
+
},
|
|
560
|
+
};
|
|
561
|
+
capabilities = mergeWith(
|
|
562
|
+
capabilities,
|
|
563
|
+
this.options.featureManager.clientCapabilities(),
|
|
564
|
+
);
|
|
565
|
+
|
|
566
|
+
const options: ISocketConnectionOptions = {
|
|
567
|
+
capabilities,
|
|
568
|
+
virtualDocument,
|
|
569
|
+
language,
|
|
570
|
+
hasLspSupportedFile: virtualDocument.hasLspSupportedFile,
|
|
571
|
+
};
|
|
572
|
+
|
|
573
|
+
const connection = await this.connectionManager.connect(options);
|
|
574
|
+
|
|
575
|
+
if (connection) {
|
|
576
|
+
await this.onConnected({ virtualDocument, connection });
|
|
577
|
+
|
|
578
|
+
return {
|
|
579
|
+
connection,
|
|
580
|
+
virtualDocument,
|
|
581
|
+
};
|
|
582
|
+
} else {
|
|
583
|
+
return undefined;
|
|
584
|
+
}
|
|
585
|
+
}
|
|
586
|
+
|
|
587
|
+
/**
|
|
588
|
+
* Handle content changes and update all virtual documents after a change.
|
|
589
|
+
*
|
|
590
|
+
* #### Notes
|
|
591
|
+
* Update to the state of a notebook may be done without a notice on the
|
|
592
|
+
* CodeMirror level, e.g. when a cell is deleted. Therefore a
|
|
593
|
+
* JupyterLab-specific signal is watched instead.
|
|
594
|
+
*
|
|
595
|
+
* While by not using the change event of CodeMirror editors we lose an easy
|
|
596
|
+
* way to send selective (range) updates this can be still implemented by
|
|
597
|
+
* comparison of before/after states of the virtual documents, which is
|
|
598
|
+
* more resilient and editor-independent.
|
|
599
|
+
*/
|
|
600
|
+
protected async _onContentChanged() {
|
|
601
|
+
// Update the virtual documents.
|
|
602
|
+
// Sending the updates to LSP is out of scope here.
|
|
603
|
+
const promise = this.updateDocuments();
|
|
604
|
+
if (!promise) {
|
|
605
|
+
console.warn('Could not update documents');
|
|
606
|
+
return;
|
|
607
|
+
}
|
|
608
|
+
this._updateFinished = promise.catch(console.warn);
|
|
609
|
+
await this.updateFinished;
|
|
610
|
+
}
|
|
611
|
+
}
|